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    /// Whether to return the per-asset balance detail for each wallet. When `false` or omitted, the response is
1137    /// unchanged from current behavior.
1138    ///
1139    /// This field is **optional.
1140    #[builder(setter(into), default)]
1141    #[serde(rename = "needBalanceDetail", default)]
1142    pub need_balance_detail: Option<bool>,
1143    ///
1144    /// The `recv_window` parameter.
1145    ///
1146    /// This field is **optional.
1147    #[builder(setter(into), default)]
1148    #[serde(rename = "recvWindow", default)]
1149    pub recv_window: Option<i64>,
1150}
1151
1152impl QueryUserWalletBalanceParams {
1153    /// Create a builder for [`query_user_wallet_balance`].
1154    ///
1155    #[must_use]
1156    pub fn builder() -> QueryUserWalletBalanceParamsBuilder {
1157        QueryUserWalletBalanceParamsBuilder::default()
1158    }
1159}
1160/// Request parameters for the [`toggle_bnb_burn_on_spot_trade_and_margin_interest`] operation.
1161///
1162/// This struct holds all of the inputs you can pass when calling
1163/// [`toggle_bnb_burn_on_spot_trade_and_margin_interest`](#method.toggle_bnb_burn_on_spot_trade_and_margin_interest).
1164#[derive(Clone, Debug, Builder, Deserialize, Default)]
1165#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1166pub struct ToggleBnbBurnOnSpotTradeAndMarginInterestParams {
1167    /// Determines whether to use BNB to pay for trading fees on SPOT
1168    ///
1169    /// This field is **optional.
1170    #[builder(setter(into), default)]
1171    #[serde(rename = "spotBNBBurn", default)]
1172    pub spot_bnb_burn: Option<String>,
1173    /// Determines whether to use BNB to pay for margin loan's interest
1174    ///
1175    /// This field is **optional.
1176    #[builder(setter(into), default)]
1177    #[serde(rename = "interestBNBBurn", default)]
1178    pub interest_bnb_burn: Option<String>,
1179    ///
1180    /// The `recv_window` parameter.
1181    ///
1182    /// This field is **optional.
1183    #[builder(setter(into), default)]
1184    #[serde(rename = "recvWindow", default)]
1185    pub recv_window: Option<i64>,
1186}
1187
1188impl ToggleBnbBurnOnSpotTradeAndMarginInterestParams {
1189    /// Create a builder for [`toggle_bnb_burn_on_spot_trade_and_margin_interest`].
1190    ///
1191    #[must_use]
1192    pub fn builder() -> ToggleBnbBurnOnSpotTradeAndMarginInterestParamsBuilder {
1193        ToggleBnbBurnOnSpotTradeAndMarginInterestParamsBuilder::default()
1194    }
1195}
1196/// Request parameters for the [`trade_fee`] operation.
1197///
1198/// This struct holds all of the inputs you can pass when calling
1199/// [`trade_fee`](#method.trade_fee).
1200#[derive(Clone, Debug, Builder, Deserialize, Default)]
1201#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1202pub struct TradeFeeParams {
1203    ///
1204    /// The `symbol` parameter.
1205    ///
1206    /// This field is **optional.
1207    #[builder(setter(into), default)]
1208    #[serde(rename = "symbol", default)]
1209    pub symbol: Option<String>,
1210    ///
1211    /// The `recv_window` parameter.
1212    ///
1213    /// This field is **optional.
1214    #[builder(setter(into), default)]
1215    #[serde(rename = "recvWindow", default)]
1216    pub recv_window: Option<i64>,
1217}
1218
1219impl TradeFeeParams {
1220    /// Create a builder for [`trade_fee`].
1221    ///
1222    #[must_use]
1223    pub fn builder() -> TradeFeeParamsBuilder {
1224        TradeFeeParamsBuilder::default()
1225    }
1226}
1227/// Request parameters for the [`user_asset`] operation.
1228///
1229/// This struct holds all of the inputs you can pass when calling
1230/// [`user_asset`](#method.user_asset).
1231#[derive(Clone, Debug, Builder, Deserialize, Default)]
1232#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1233pub struct UserAssetParams {
1234    /// If asset is blank, then query all positive assets user have.
1235    ///
1236    /// This field is **optional.
1237    #[builder(setter(into), default)]
1238    #[serde(rename = "asset", default)]
1239    pub asset: Option<String>,
1240    /// Whether need btc valuation or not.
1241    ///
1242    /// This field is **optional.
1243    #[builder(setter(into), default)]
1244    #[serde(rename = "needBtcValuation", default)]
1245    pub need_btc_valuation: Option<bool>,
1246    ///
1247    /// The `recv_window` parameter.
1248    ///
1249    /// This field is **optional.
1250    #[builder(setter(into), default)]
1251    #[serde(rename = "recvWindow", default)]
1252    pub recv_window: Option<i64>,
1253}
1254
1255impl UserAssetParams {
1256    /// Create a builder for [`user_asset`].
1257    ///
1258    #[must_use]
1259    pub fn builder() -> UserAssetParamsBuilder {
1260        UserAssetParamsBuilder::default()
1261    }
1262}
1263/// Request parameters for the [`user_universal_transfer`] operation.
1264///
1265/// This struct holds all of the inputs you can pass when calling
1266/// [`user_universal_transfer`](#method.user_universal_transfer).
1267#[derive(Clone, Debug, Builder, Deserialize)]
1268#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1269pub struct UserUniversalTransferParams {
1270    ///
1271    /// The `r#type` parameter.
1272    ///
1273    /// This field is **required.
1274    #[builder(setter(into))]
1275    #[serde(rename = "type")]
1276    pub r#type: UserUniversalTransferTypeEnum,
1277    ///
1278    /// The `asset` parameter.
1279    ///
1280    /// This field is **required.
1281    #[builder(setter(into))]
1282    #[serde(rename = "asset")]
1283    pub asset: String,
1284    ///
1285    /// The `amount` parameter.
1286    ///
1287    /// This field is **required.
1288    #[builder(setter(into))]
1289    #[serde(rename = "amount")]
1290    pub amount: rust_decimal::Decimal,
1291    ///
1292    /// The `from_symbol` parameter.
1293    ///
1294    /// This field is **optional.
1295    #[builder(setter(into), default)]
1296    #[serde(rename = "fromSymbol", default)]
1297    pub from_symbol: Option<UserUniversalTransferFromSymbolEnum>,
1298    ///
1299    /// The `to_symbol` parameter.
1300    ///
1301    /// This field is **optional.
1302    #[builder(setter(into), default)]
1303    #[serde(rename = "toSymbol", default)]
1304    pub to_symbol: Option<UserUniversalTransferToSymbolEnum>,
1305    ///
1306    /// The `recv_window` parameter.
1307    ///
1308    /// This field is **optional.
1309    #[builder(setter(into), default)]
1310    #[serde(rename = "recvWindow", default)]
1311    pub recv_window: Option<i64>,
1312}
1313
1314impl UserUniversalTransferParams {
1315    /// Create a builder for [`user_universal_transfer`].
1316    ///
1317    /// Required parameters:
1318    ///
1319    /// * `r#type` — String
1320    /// * `asset` — String
1321    /// * `amount` — `rust_decimal::Decimal`
1322    ///
1323    #[must_use]
1324    pub fn builder(
1325        r#type: UserUniversalTransferTypeEnum,
1326        asset: String,
1327        amount: rust_decimal::Decimal,
1328    ) -> UserUniversalTransferParamsBuilder {
1329        UserUniversalTransferParamsBuilder::default()
1330            .r#type(r#type)
1331            .asset(asset)
1332            .amount(amount)
1333    }
1334}
1335
1336#[async_trait]
1337impl AssetApi for AssetApiClient {
1338    async fn asset_detail(
1339        &self,
1340        params: AssetDetailParams,
1341    ) -> anyhow::Result<RestApiResponse<models::AssetDetailResponse>> {
1342        let AssetDetailParams { asset, recv_window } = params;
1343
1344        let mut query_params = BTreeMap::new();
1345        let body_params = BTreeMap::new();
1346
1347        if let Some(rw) = asset {
1348            query_params.insert("asset".to_string(), json!(rw));
1349        }
1350
1351        if let Some(rw) = recv_window {
1352            query_params.insert("recvWindow".to_string(), json!(rw));
1353        }
1354
1355        send_request::<models::AssetDetailResponse>(
1356            &self.configuration,
1357            "/sapi/v1/asset/assetDetail",
1358            reqwest::Method::GET,
1359            query_params,
1360            body_params,
1361            if HAS_TIME_UNIT {
1362                self.configuration.time_unit
1363            } else {
1364                None
1365            },
1366            true,
1367        )
1368        .await
1369    }
1370
1371    async fn asset_dividend_record(
1372        &self,
1373        params: AssetDividendRecordParams,
1374    ) -> anyhow::Result<RestApiResponse<models::AssetDividendRecordResponse>> {
1375        let AssetDividendRecordParams {
1376            asset,
1377            start_time,
1378            end_time,
1379            limit,
1380            recv_window,
1381        } = params;
1382
1383        let mut query_params = BTreeMap::new();
1384        let body_params = BTreeMap::new();
1385
1386        if let Some(rw) = asset {
1387            query_params.insert("asset".to_string(), json!(rw));
1388        }
1389
1390        if let Some(rw) = start_time {
1391            query_params.insert("startTime".to_string(), json!(rw));
1392        }
1393
1394        if let Some(rw) = end_time {
1395            query_params.insert("endTime".to_string(), json!(rw));
1396        }
1397
1398        if let Some(rw) = limit {
1399            query_params.insert("limit".to_string(), json!(rw));
1400        }
1401
1402        if let Some(rw) = recv_window {
1403            query_params.insert("recvWindow".to_string(), json!(rw));
1404        }
1405
1406        send_request::<models::AssetDividendRecordResponse>(
1407            &self.configuration,
1408            "/sapi/v1/asset/assetDividend",
1409            reqwest::Method::GET,
1410            query_params,
1411            body_params,
1412            if HAS_TIME_UNIT {
1413                self.configuration.time_unit
1414            } else {
1415                None
1416            },
1417            true,
1418        )
1419        .await
1420    }
1421
1422    async fn dust_convert(
1423        &self,
1424        params: DustConvertParams,
1425    ) -> anyhow::Result<RestApiResponse<models::DustConvertResponse>> {
1426        let DustConvertParams {
1427            asset,
1428            account_type,
1429            client_id,
1430            target_asset,
1431            third_party_client_id,
1432            dust_quota_asset_to_target_asset_price,
1433        } = params;
1434
1435        let mut query_params = BTreeMap::new();
1436        let body_params = BTreeMap::new();
1437
1438        query_params.insert("asset".to_string(), json!(asset));
1439
1440        if let Some(rw) = account_type {
1441            query_params.insert("accountType".to_string(), json!(rw));
1442        }
1443
1444        if let Some(rw) = client_id {
1445            query_params.insert("clientId".to_string(), json!(rw));
1446        }
1447
1448        if let Some(rw) = target_asset {
1449            query_params.insert("targetAsset".to_string(), json!(rw));
1450        }
1451
1452        if let Some(rw) = third_party_client_id {
1453            query_params.insert("thirdPartyClientId".to_string(), json!(rw));
1454        }
1455
1456        if let Some(rw) = dust_quota_asset_to_target_asset_price {
1457            query_params.insert("dustQuotaAssetToTargetAssetPrice".to_string(), json!(rw));
1458        }
1459
1460        send_request::<models::DustConvertResponse>(
1461            &self.configuration,
1462            "/sapi/v1/asset/dust-convert/convert",
1463            reqwest::Method::POST,
1464            query_params,
1465            body_params,
1466            if HAS_TIME_UNIT {
1467                self.configuration.time_unit
1468            } else {
1469                None
1470            },
1471            true,
1472        )
1473        .await
1474    }
1475
1476    async fn dust_convertible_assets(
1477        &self,
1478        params: DustConvertibleAssetsParams,
1479    ) -> anyhow::Result<RestApiResponse<models::DustConvertibleAssetsResponse>> {
1480        let DustConvertibleAssetsParams {
1481            target_asset,
1482            account_type,
1483            dust_quota_asset_to_target_asset_price,
1484        } = params;
1485
1486        let mut query_params = BTreeMap::new();
1487        let body_params = BTreeMap::new();
1488
1489        if let Some(rw) = account_type {
1490            query_params.insert("accountType".to_string(), json!(rw));
1491        }
1492
1493        query_params.insert("targetAsset".to_string(), json!(target_asset));
1494
1495        if let Some(rw) = dust_quota_asset_to_target_asset_price {
1496            query_params.insert("dustQuotaAssetToTargetAssetPrice".to_string(), json!(rw));
1497        }
1498
1499        send_request::<models::DustConvertibleAssetsResponse>(
1500            &self.configuration,
1501            "/sapi/v1/asset/dust-convert/query-convertible-assets",
1502            reqwest::Method::POST,
1503            query_params,
1504            body_params,
1505            if HAS_TIME_UNIT {
1506                self.configuration.time_unit
1507            } else {
1508                None
1509            },
1510            true,
1511        )
1512        .await
1513    }
1514
1515    async fn dust_transfer(
1516        &self,
1517        params: DustTransferParams,
1518    ) -> anyhow::Result<RestApiResponse<models::DustTransferResponse>> {
1519        let DustTransferParams {
1520            asset,
1521            account_type,
1522            recv_window,
1523        } = params;
1524
1525        let mut query_params = BTreeMap::new();
1526        let body_params = BTreeMap::new();
1527
1528        query_params.insert("asset".to_string(), json!(asset));
1529
1530        if let Some(rw) = account_type {
1531            query_params.insert("accountType".to_string(), json!(rw));
1532        }
1533
1534        if let Some(rw) = recv_window {
1535            query_params.insert("recvWindow".to_string(), json!(rw));
1536        }
1537
1538        send_request::<models::DustTransferResponse>(
1539            &self.configuration,
1540            "/sapi/v1/asset/dust",
1541            reqwest::Method::POST,
1542            query_params,
1543            body_params,
1544            if HAS_TIME_UNIT {
1545                self.configuration.time_unit
1546            } else {
1547                None
1548            },
1549            true,
1550        )
1551        .await
1552    }
1553
1554    async fn dustlog(
1555        &self,
1556        params: DustlogParams,
1557    ) -> anyhow::Result<RestApiResponse<models::DustlogResponse>> {
1558        let DustlogParams {
1559            account_type,
1560            start_time,
1561            end_time,
1562            recv_window,
1563        } = params;
1564
1565        let mut query_params = BTreeMap::new();
1566        let body_params = BTreeMap::new();
1567
1568        if let Some(rw) = account_type {
1569            query_params.insert("accountType".to_string(), json!(rw));
1570        }
1571
1572        if let Some(rw) = start_time {
1573            query_params.insert("startTime".to_string(), json!(rw));
1574        }
1575
1576        if let Some(rw) = end_time {
1577            query_params.insert("endTime".to_string(), json!(rw));
1578        }
1579
1580        if let Some(rw) = recv_window {
1581            query_params.insert("recvWindow".to_string(), json!(rw));
1582        }
1583
1584        send_request::<models::DustlogResponse>(
1585            &self.configuration,
1586            "/sapi/v1/asset/dribblet",
1587            reqwest::Method::GET,
1588            query_params,
1589            body_params,
1590            if HAS_TIME_UNIT {
1591                self.configuration.time_unit
1592            } else {
1593                None
1594            },
1595            true,
1596        )
1597        .await
1598    }
1599
1600    async fn funding_wallet(
1601        &self,
1602        params: FundingWalletParams,
1603    ) -> anyhow::Result<RestApiResponse<Vec<models::FundingWalletResponseInner>>> {
1604        let FundingWalletParams {
1605            asset,
1606            need_btc_valuation,
1607            recv_window,
1608        } = params;
1609
1610        let mut query_params = BTreeMap::new();
1611        let body_params = BTreeMap::new();
1612
1613        if let Some(rw) = asset {
1614            query_params.insert("asset".to_string(), json!(rw));
1615        }
1616
1617        if let Some(rw) = need_btc_valuation {
1618            query_params.insert("needBtcValuation".to_string(), json!(rw));
1619        }
1620
1621        if let Some(rw) = recv_window {
1622            query_params.insert("recvWindow".to_string(), json!(rw));
1623        }
1624
1625        send_request::<Vec<models::FundingWalletResponseInner>>(
1626            &self.configuration,
1627            "/sapi/v1/asset/get-funding-asset",
1628            reqwest::Method::POST,
1629            query_params,
1630            body_params,
1631            if HAS_TIME_UNIT {
1632                self.configuration.time_unit
1633            } else {
1634                None
1635            },
1636            true,
1637        )
1638        .await
1639    }
1640
1641    async fn get_assets_that_can_be_converted_into_bnb(
1642        &self,
1643        params: GetAssetsThatCanBeConvertedIntoBnbParams,
1644    ) -> anyhow::Result<RestApiResponse<models::GetAssetsThatCanBeConvertedIntoBnbResponse>> {
1645        let GetAssetsThatCanBeConvertedIntoBnbParams {
1646            account_type,
1647            recv_window,
1648        } = params;
1649
1650        let mut query_params = BTreeMap::new();
1651        let body_params = BTreeMap::new();
1652
1653        if let Some(rw) = account_type {
1654            query_params.insert("accountType".to_string(), json!(rw));
1655        }
1656
1657        if let Some(rw) = recv_window {
1658            query_params.insert("recvWindow".to_string(), json!(rw));
1659        }
1660
1661        send_request::<models::GetAssetsThatCanBeConvertedIntoBnbResponse>(
1662            &self.configuration,
1663            "/sapi/v1/asset/dust-btc",
1664            reqwest::Method::POST,
1665            query_params,
1666            body_params,
1667            if HAS_TIME_UNIT {
1668                self.configuration.time_unit
1669            } else {
1670                None
1671            },
1672            true,
1673        )
1674        .await
1675    }
1676
1677    async fn get_cloud_mining_payment_and_refund_history(
1678        &self,
1679        params: GetCloudMiningPaymentAndRefundHistoryParams,
1680    ) -> anyhow::Result<RestApiResponse<models::GetCloudMiningPaymentAndRefundHistoryResponse>>
1681    {
1682        let GetCloudMiningPaymentAndRefundHistoryParams {
1683            start_time,
1684            end_time,
1685            tran_id,
1686            client_tran_id,
1687            asset,
1688            current,
1689            size,
1690        } = params;
1691
1692        let mut query_params = BTreeMap::new();
1693        let body_params = BTreeMap::new();
1694
1695        if let Some(rw) = tran_id {
1696            query_params.insert("tranId".to_string(), json!(rw));
1697        }
1698
1699        if let Some(rw) = client_tran_id {
1700            query_params.insert("clientTranId".to_string(), json!(rw));
1701        }
1702
1703        if let Some(rw) = asset {
1704            query_params.insert("asset".to_string(), json!(rw));
1705        }
1706
1707        query_params.insert("startTime".to_string(), json!(start_time));
1708
1709        query_params.insert("endTime".to_string(), json!(end_time));
1710
1711        if let Some(rw) = current {
1712            query_params.insert("current".to_string(), json!(rw));
1713        }
1714
1715        if let Some(rw) = size {
1716            query_params.insert("size".to_string(), json!(rw));
1717        }
1718
1719        send_request::<models::GetCloudMiningPaymentAndRefundHistoryResponse>(
1720            &self.configuration,
1721            "/sapi/v1/asset/ledger-transfer/cloud-mining/queryByPage",
1722            reqwest::Method::GET,
1723            query_params,
1724            body_params,
1725            if HAS_TIME_UNIT {
1726                self.configuration.time_unit
1727            } else {
1728                None
1729            },
1730            true,
1731        )
1732        .await
1733    }
1734
1735    async fn get_open_symbol_list(
1736        &self,
1737    ) -> anyhow::Result<RestApiResponse<Vec<models::GetOpenSymbolListResponseInner>>> {
1738        let query_params = BTreeMap::new();
1739        let body_params = BTreeMap::new();
1740
1741        send_request::<Vec<models::GetOpenSymbolListResponseInner>>(
1742            &self.configuration,
1743            "/sapi/v1/spot/open-symbol-list",
1744            reqwest::Method::GET,
1745            query_params,
1746            body_params,
1747            if HAS_TIME_UNIT {
1748                self.configuration.time_unit
1749            } else {
1750                None
1751            },
1752            false,
1753        )
1754        .await
1755    }
1756
1757    async fn get_spot_asset_tags(
1758        &self,
1759        params: GetSpotAssetTagsParams,
1760    ) -> anyhow::Result<RestApiResponse<Vec<models::GetSpotAssetTagsResponseInner>>> {
1761        let GetSpotAssetTagsParams { tag } = params;
1762
1763        let mut query_params = BTreeMap::new();
1764        let body_params = BTreeMap::new();
1765
1766        if let Some(rw) = tag {
1767            query_params.insert("tag".to_string(), json!(rw));
1768        }
1769
1770        send_request::<Vec<models::GetSpotAssetTagsResponseInner>>(
1771            &self.configuration,
1772            "/sapi/v1/spot/asset/tags",
1773            reqwest::Method::GET,
1774            query_params,
1775            body_params,
1776            if HAS_TIME_UNIT {
1777                self.configuration.time_unit
1778            } else {
1779                None
1780            },
1781            false,
1782        )
1783        .await
1784    }
1785
1786    async fn query_user_delegation_history(
1787        &self,
1788        params: QueryUserDelegationHistoryParams,
1789    ) -> anyhow::Result<RestApiResponse<models::QueryUserDelegationHistoryResponse>> {
1790        let QueryUserDelegationHistoryParams {
1791            email,
1792            start_time,
1793            end_time,
1794            r#type,
1795            asset,
1796            current,
1797            size,
1798            recv_window,
1799        } = params;
1800
1801        let mut query_params = BTreeMap::new();
1802        let body_params = BTreeMap::new();
1803
1804        query_params.insert("email".to_string(), json!(email));
1805
1806        query_params.insert("startTime".to_string(), json!(start_time));
1807
1808        query_params.insert("endTime".to_string(), json!(end_time));
1809
1810        if let Some(rw) = r#type {
1811            query_params.insert("type".to_string(), json!(rw));
1812        }
1813
1814        if let Some(rw) = asset {
1815            query_params.insert("asset".to_string(), json!(rw));
1816        }
1817
1818        if let Some(rw) = current {
1819            query_params.insert("current".to_string(), json!(rw));
1820        }
1821
1822        if let Some(rw) = size {
1823            query_params.insert("size".to_string(), json!(rw));
1824        }
1825
1826        if let Some(rw) = recv_window {
1827            query_params.insert("recvWindow".to_string(), json!(rw));
1828        }
1829
1830        send_request::<models::QueryUserDelegationHistoryResponse>(
1831            &self.configuration,
1832            "/sapi/v1/asset/custody/transfer-history",
1833            reqwest::Method::GET,
1834            query_params,
1835            body_params,
1836            if HAS_TIME_UNIT {
1837                self.configuration.time_unit
1838            } else {
1839                None
1840            },
1841            true,
1842        )
1843        .await
1844    }
1845
1846    async fn query_user_universal_transfer_history(
1847        &self,
1848        params: QueryUserUniversalTransferHistoryParams,
1849    ) -> anyhow::Result<RestApiResponse<models::QueryUserUniversalTransferHistoryResponse>> {
1850        let QueryUserUniversalTransferHistoryParams {
1851            r#type,
1852            start_time,
1853            end_time,
1854            current,
1855            size,
1856            from_symbol,
1857            to_symbol,
1858            recv_window,
1859        } = params;
1860
1861        let mut query_params = BTreeMap::new();
1862        let body_params = BTreeMap::new();
1863
1864        query_params.insert("type".to_string(), json!(r#type));
1865
1866        if let Some(rw) = start_time {
1867            query_params.insert("startTime".to_string(), json!(rw));
1868        }
1869
1870        if let Some(rw) = end_time {
1871            query_params.insert("endTime".to_string(), json!(rw));
1872        }
1873
1874        if let Some(rw) = current {
1875            query_params.insert("current".to_string(), json!(rw));
1876        }
1877
1878        if let Some(rw) = size {
1879            query_params.insert("size".to_string(), json!(rw));
1880        }
1881
1882        if let Some(rw) = from_symbol {
1883            query_params.insert("fromSymbol".to_string(), json!(rw));
1884        }
1885
1886        if let Some(rw) = to_symbol {
1887            query_params.insert("toSymbol".to_string(), json!(rw));
1888        }
1889
1890        if let Some(rw) = recv_window {
1891            query_params.insert("recvWindow".to_string(), json!(rw));
1892        }
1893
1894        send_request::<models::QueryUserUniversalTransferHistoryResponse>(
1895            &self.configuration,
1896            "/sapi/v1/asset/transfer",
1897            reqwest::Method::GET,
1898            query_params,
1899            body_params,
1900            if HAS_TIME_UNIT {
1901                self.configuration.time_unit
1902            } else {
1903                None
1904            },
1905            true,
1906        )
1907        .await
1908    }
1909
1910    async fn query_user_wallet_balance(
1911        &self,
1912        params: QueryUserWalletBalanceParams,
1913    ) -> anyhow::Result<RestApiResponse<Vec<models::QueryUserWalletBalanceResponseInner>>> {
1914        let QueryUserWalletBalanceParams {
1915            quote_asset,
1916            need_balance_detail,
1917            recv_window,
1918        } = params;
1919
1920        let mut query_params = BTreeMap::new();
1921        let body_params = BTreeMap::new();
1922
1923        if let Some(rw) = quote_asset {
1924            query_params.insert("quoteAsset".to_string(), json!(rw));
1925        }
1926
1927        if let Some(rw) = need_balance_detail {
1928            query_params.insert("needBalanceDetail".to_string(), json!(rw));
1929        }
1930
1931        if let Some(rw) = recv_window {
1932            query_params.insert("recvWindow".to_string(), json!(rw));
1933        }
1934
1935        send_request::<Vec<models::QueryUserWalletBalanceResponseInner>>(
1936            &self.configuration,
1937            "/sapi/v1/asset/wallet/balance",
1938            reqwest::Method::GET,
1939            query_params,
1940            body_params,
1941            if HAS_TIME_UNIT {
1942                self.configuration.time_unit
1943            } else {
1944                None
1945            },
1946            true,
1947        )
1948        .await
1949    }
1950
1951    async fn toggle_bnb_burn_on_spot_trade_and_margin_interest(
1952        &self,
1953        params: ToggleBnbBurnOnSpotTradeAndMarginInterestParams,
1954    ) -> anyhow::Result<RestApiResponse<models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse>>
1955    {
1956        let ToggleBnbBurnOnSpotTradeAndMarginInterestParams {
1957            spot_bnb_burn,
1958            interest_bnb_burn,
1959            recv_window,
1960        } = params;
1961
1962        let mut query_params = BTreeMap::new();
1963        let body_params = BTreeMap::new();
1964
1965        if let Some(rw) = spot_bnb_burn {
1966            query_params.insert("spotBNBBurn".to_string(), json!(rw));
1967        }
1968
1969        if let Some(rw) = interest_bnb_burn {
1970            query_params.insert("interestBNBBurn".to_string(), json!(rw));
1971        }
1972
1973        if let Some(rw) = recv_window {
1974            query_params.insert("recvWindow".to_string(), json!(rw));
1975        }
1976
1977        send_request::<models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse>(
1978            &self.configuration,
1979            "/sapi/v1/bnbBurn",
1980            reqwest::Method::POST,
1981            query_params,
1982            body_params,
1983            if HAS_TIME_UNIT {
1984                self.configuration.time_unit
1985            } else {
1986                None
1987            },
1988            true,
1989        )
1990        .await
1991    }
1992
1993    async fn trade_fee(
1994        &self,
1995        params: TradeFeeParams,
1996    ) -> anyhow::Result<RestApiResponse<Vec<models::TradeFeeResponseInner>>> {
1997        let TradeFeeParams {
1998            symbol,
1999            recv_window,
2000        } = params;
2001
2002        let mut query_params = BTreeMap::new();
2003        let body_params = BTreeMap::new();
2004
2005        if let Some(rw) = symbol {
2006            query_params.insert("symbol".to_string(), json!(rw));
2007        }
2008
2009        if let Some(rw) = recv_window {
2010            query_params.insert("recvWindow".to_string(), json!(rw));
2011        }
2012
2013        send_request::<Vec<models::TradeFeeResponseInner>>(
2014            &self.configuration,
2015            "/sapi/v1/asset/tradeFee",
2016            reqwest::Method::GET,
2017            query_params,
2018            body_params,
2019            if HAS_TIME_UNIT {
2020                self.configuration.time_unit
2021            } else {
2022                None
2023            },
2024            true,
2025        )
2026        .await
2027    }
2028
2029    async fn user_asset(
2030        &self,
2031        params: UserAssetParams,
2032    ) -> anyhow::Result<RestApiResponse<Vec<models::UserAssetResponseInner>>> {
2033        let UserAssetParams {
2034            asset,
2035            need_btc_valuation,
2036            recv_window,
2037        } = params;
2038
2039        let mut query_params = BTreeMap::new();
2040        let body_params = BTreeMap::new();
2041
2042        if let Some(rw) = asset {
2043            query_params.insert("asset".to_string(), json!(rw));
2044        }
2045
2046        if let Some(rw) = need_btc_valuation {
2047            query_params.insert("needBtcValuation".to_string(), json!(rw));
2048        }
2049
2050        if let Some(rw) = recv_window {
2051            query_params.insert("recvWindow".to_string(), json!(rw));
2052        }
2053
2054        send_request::<Vec<models::UserAssetResponseInner>>(
2055            &self.configuration,
2056            "/sapi/v3/asset/getUserAsset",
2057            reqwest::Method::POST,
2058            query_params,
2059            body_params,
2060            if HAS_TIME_UNIT {
2061                self.configuration.time_unit
2062            } else {
2063                None
2064            },
2065            true,
2066        )
2067        .await
2068    }
2069
2070    async fn user_universal_transfer(
2071        &self,
2072        params: UserUniversalTransferParams,
2073    ) -> anyhow::Result<RestApiResponse<models::UserUniversalTransferResponse>> {
2074        let UserUniversalTransferParams {
2075            r#type,
2076            asset,
2077            amount,
2078            from_symbol,
2079            to_symbol,
2080            recv_window,
2081        } = params;
2082
2083        let mut query_params = BTreeMap::new();
2084        let body_params = BTreeMap::new();
2085
2086        query_params.insert("type".to_string(), json!(r#type));
2087
2088        query_params.insert("asset".to_string(), json!(asset));
2089
2090        query_params.insert("amount".to_string(), json!(amount));
2091
2092        if let Some(rw) = from_symbol {
2093            query_params.insert("fromSymbol".to_string(), json!(rw));
2094        }
2095
2096        if let Some(rw) = to_symbol {
2097            query_params.insert("toSymbol".to_string(), json!(rw));
2098        }
2099
2100        if let Some(rw) = recv_window {
2101            query_params.insert("recvWindow".to_string(), json!(rw));
2102        }
2103
2104        send_request::<models::UserUniversalTransferResponse>(
2105            &self.configuration,
2106            "/sapi/v1/asset/transfer",
2107            reqwest::Method::POST,
2108            query_params,
2109            body_params,
2110            if HAS_TIME_UNIT {
2111                self.configuration.time_unit
2112            } else {
2113                None
2114            },
2115            true,
2116        )
2117        .await
2118    }
2119}
2120
2121#[cfg(all(test, feature = "wallet"))]
2122mod tests {
2123    use super::*;
2124    use crate::TOKIO_SHARED_RT;
2125    use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
2126    use async_trait::async_trait;
2127    use std::collections::HashMap;
2128
2129    struct DummyRestApiResponse<T> {
2130        inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
2131        status: u16,
2132        headers: HashMap<String, String>,
2133        rate_limits: Option<Vec<RestApiRateLimit>>,
2134    }
2135
2136    impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
2137        fn from(dummy: DummyRestApiResponse<T>) -> Self {
2138            Self {
2139                data_fn: dummy.inner,
2140                status: dummy.status,
2141                headers: dummy.headers,
2142                rate_limits: dummy.rate_limits,
2143            }
2144        }
2145    }
2146
2147    struct MockAssetApiClient {
2148        force_error: bool,
2149    }
2150
2151    #[async_trait]
2152    impl AssetApi for MockAssetApiClient {
2153        async fn asset_detail(
2154            &self,
2155            _params: AssetDetailParams,
2156        ) -> anyhow::Result<RestApiResponse<models::AssetDetailResponse>> {
2157            if self.force_error {
2158                return Err(ConnectorError::ConnectorClientError {
2159                    msg: "ResponseError".to_string(),
2160                    code: None,
2161                }
2162                .into());
2163            }
2164
2165            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!({}));
2166            let dummy_response: models::AssetDetailResponse =
2167                serde_json::from_value(resp_json.clone())
2168                    .expect("should parse into models::AssetDetailResponse");
2169
2170            let dummy = DummyRestApiResponse {
2171                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2172                status: 200,
2173                headers: HashMap::new(),
2174                rate_limits: None,
2175            };
2176
2177            Ok(dummy.into())
2178        }
2179
2180        async fn asset_dividend_record(
2181            &self,
2182            _params: AssetDividendRecordParams,
2183        ) -> anyhow::Result<RestApiResponse<models::AssetDividendRecordResponse>> {
2184            if self.force_error {
2185                return Err(ConnectorError::ConnectorClientError {
2186                    msg: "ResponseError".to_string(),
2187                    code: None,
2188                }
2189                .into());
2190            }
2191
2192            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!({}));
2193            let dummy_response: models::AssetDividendRecordResponse =
2194                serde_json::from_value(resp_json.clone())
2195                    .expect("should parse into models::AssetDividendRecordResponse");
2196
2197            let dummy = DummyRestApiResponse {
2198                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2199                status: 200,
2200                headers: HashMap::new(),
2201                rate_limits: None,
2202            };
2203
2204            Ok(dummy.into())
2205        }
2206
2207        async fn dust_convert(
2208            &self,
2209            _params: DustConvertParams,
2210        ) -> anyhow::Result<RestApiResponse<models::DustConvertResponse>> {
2211            if self.force_error {
2212                return Err(ConnectorError::ConnectorClientError {
2213                    msg: "ResponseError".to_string(),
2214                    code: None,
2215                }
2216                .into());
2217            }
2218
2219            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!({}));
2220            let dummy_response: models::DustConvertResponse =
2221                serde_json::from_value(resp_json.clone())
2222                    .expect("should parse into models::DustConvertResponse");
2223
2224            let dummy = DummyRestApiResponse {
2225                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2226                status: 200,
2227                headers: HashMap::new(),
2228                rate_limits: None,
2229            };
2230
2231            Ok(dummy.into())
2232        }
2233
2234        async fn dust_convertible_assets(
2235            &self,
2236            _params: DustConvertibleAssetsParams,
2237        ) -> anyhow::Result<RestApiResponse<models::DustConvertibleAssetsResponse>> {
2238            if self.force_error {
2239                return Err(ConnectorError::ConnectorClientError {
2240                    msg: "ResponseError".to_string(),
2241                    code: None,
2242                }
2243                .into());
2244            }
2245
2246            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!({}));
2247            let dummy_response: models::DustConvertibleAssetsResponse =
2248                serde_json::from_value(resp_json.clone())
2249                    .expect("should parse into models::DustConvertibleAssetsResponse");
2250
2251            let dummy = DummyRestApiResponse {
2252                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2253                status: 200,
2254                headers: HashMap::new(),
2255                rate_limits: None,
2256            };
2257
2258            Ok(dummy.into())
2259        }
2260
2261        async fn dust_transfer(
2262            &self,
2263            _params: DustTransferParams,
2264        ) -> anyhow::Result<RestApiResponse<models::DustTransferResponse>> {
2265            if self.force_error {
2266                return Err(ConnectorError::ConnectorClientError {
2267                    msg: "ResponseError".to_string(),
2268                    code: None,
2269                }
2270                .into());
2271            }
2272
2273            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!({}));
2274            let dummy_response: models::DustTransferResponse =
2275                serde_json::from_value(resp_json.clone())
2276                    .expect("should parse into models::DustTransferResponse");
2277
2278            let dummy = DummyRestApiResponse {
2279                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2280                status: 200,
2281                headers: HashMap::new(),
2282                rate_limits: None,
2283            };
2284
2285            Ok(dummy.into())
2286        }
2287
2288        async fn dustlog(
2289            &self,
2290            _params: DustlogParams,
2291        ) -> anyhow::Result<RestApiResponse<models::DustlogResponse>> {
2292            if self.force_error {
2293                return Err(ConnectorError::ConnectorClientError {
2294                    msg: "ResponseError".to_string(),
2295                    code: None,
2296                }
2297                .into());
2298            }
2299
2300            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!({}));
2301            let dummy_response: models::DustlogResponse = serde_json::from_value(resp_json.clone())
2302                .expect("should parse into models::DustlogResponse");
2303
2304            let dummy = DummyRestApiResponse {
2305                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2306                status: 200,
2307                headers: HashMap::new(),
2308                rate_limits: None,
2309            };
2310
2311            Ok(dummy.into())
2312        }
2313
2314        async fn funding_wallet(
2315            &self,
2316            _params: FundingWalletParams,
2317        ) -> anyhow::Result<RestApiResponse<Vec<models::FundingWalletResponseInner>>> {
2318            if self.force_error {
2319                return Err(ConnectorError::ConnectorClientError {
2320                    msg: "ResponseError".to_string(),
2321                    code: None,
2322                }
2323                .into());
2324            }
2325
2326            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!({}));
2327            let dummy_response: Vec<models::FundingWalletResponseInner> =
2328                serde_json::from_value(resp_json.clone())
2329                    .expect("should parse into Vec<models::FundingWalletResponseInner>");
2330
2331            let dummy = DummyRestApiResponse {
2332                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2333                status: 200,
2334                headers: HashMap::new(),
2335                rate_limits: None,
2336            };
2337
2338            Ok(dummy.into())
2339        }
2340
2341        async fn get_assets_that_can_be_converted_into_bnb(
2342            &self,
2343            _params: GetAssetsThatCanBeConvertedIntoBnbParams,
2344        ) -> anyhow::Result<RestApiResponse<models::GetAssetsThatCanBeConvertedIntoBnbResponse>>
2345        {
2346            if self.force_error {
2347                return Err(ConnectorError::ConnectorClientError {
2348                    msg: "ResponseError".to_string(),
2349                    code: None,
2350                }
2351                .into());
2352            }
2353
2354            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!({}));
2355            let dummy_response: models::GetAssetsThatCanBeConvertedIntoBnbResponse =
2356                serde_json::from_value(resp_json.clone())
2357                    .expect("should parse into models::GetAssetsThatCanBeConvertedIntoBnbResponse");
2358
2359            let dummy = DummyRestApiResponse {
2360                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2361                status: 200,
2362                headers: HashMap::new(),
2363                rate_limits: None,
2364            };
2365
2366            Ok(dummy.into())
2367        }
2368
2369        async fn get_cloud_mining_payment_and_refund_history(
2370            &self,
2371            _params: GetCloudMiningPaymentAndRefundHistoryParams,
2372        ) -> anyhow::Result<RestApiResponse<models::GetCloudMiningPaymentAndRefundHistoryResponse>>
2373        {
2374            if self.force_error {
2375                return Err(ConnectorError::ConnectorClientError {
2376                    msg: "ResponseError".to_string(),
2377                    code: None,
2378                }
2379                .into());
2380            }
2381
2382            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!({}));
2383            let dummy_response: models::GetCloudMiningPaymentAndRefundHistoryResponse =
2384                serde_json::from_value(resp_json.clone()).expect(
2385                    "should parse into models::GetCloudMiningPaymentAndRefundHistoryResponse",
2386                );
2387
2388            let dummy = DummyRestApiResponse {
2389                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2390                status: 200,
2391                headers: HashMap::new(),
2392                rate_limits: None,
2393            };
2394
2395            Ok(dummy.into())
2396        }
2397
2398        async fn get_open_symbol_list(
2399            &self,
2400        ) -> anyhow::Result<RestApiResponse<Vec<models::GetOpenSymbolListResponseInner>>> {
2401            if self.force_error {
2402                return Err(ConnectorError::ConnectorClientError {
2403                    msg: "ResponseError".to_string(),
2404                    code: None,
2405                }
2406                .into());
2407            }
2408
2409            let resp_json: Value =
2410                serde_json::from_str(r#"[{"openTime":1686161202000,"symbols":["BNBBTC"]}]"#)
2411                    .unwrap_or_else(|_| serde_json::json!({}));
2412            let dummy_response: Vec<models::GetOpenSymbolListResponseInner> =
2413                serde_json::from_value(resp_json.clone())
2414                    .expect("should parse into Vec<models::GetOpenSymbolListResponseInner>");
2415
2416            let dummy = DummyRestApiResponse {
2417                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2418                status: 200,
2419                headers: HashMap::new(),
2420                rate_limits: None,
2421            };
2422
2423            Ok(dummy.into())
2424        }
2425
2426        async fn get_spot_asset_tags(
2427            &self,
2428            _params: GetSpotAssetTagsParams,
2429        ) -> anyhow::Result<RestApiResponse<Vec<models::GetSpotAssetTagsResponseInner>>> {
2430            if self.force_error {
2431                return Err(ConnectorError::ConnectorClientError {
2432                    msg: "ResponseError".to_string(),
2433                    code: None,
2434                }
2435                .into());
2436            }
2437
2438            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!({}));
2439            let dummy_response: Vec<models::GetSpotAssetTagsResponseInner> =
2440                serde_json::from_value(resp_json.clone())
2441                    .expect("should parse into Vec<models::GetSpotAssetTagsResponseInner>");
2442
2443            let dummy = DummyRestApiResponse {
2444                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2445                status: 200,
2446                headers: HashMap::new(),
2447                rate_limits: None,
2448            };
2449
2450            Ok(dummy.into())
2451        }
2452
2453        async fn query_user_delegation_history(
2454            &self,
2455            _params: QueryUserDelegationHistoryParams,
2456        ) -> anyhow::Result<RestApiResponse<models::QueryUserDelegationHistoryResponse>> {
2457            if self.force_error {
2458                return Err(ConnectorError::ConnectorClientError {
2459                    msg: "ResponseError".to_string(),
2460                    code: None,
2461                }
2462                .into());
2463            }
2464
2465            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!({}));
2466            let dummy_response: models::QueryUserDelegationHistoryResponse =
2467                serde_json::from_value(resp_json.clone())
2468                    .expect("should parse into models::QueryUserDelegationHistoryResponse");
2469
2470            let dummy = DummyRestApiResponse {
2471                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2472                status: 200,
2473                headers: HashMap::new(),
2474                rate_limits: None,
2475            };
2476
2477            Ok(dummy.into())
2478        }
2479
2480        async fn query_user_universal_transfer_history(
2481            &self,
2482            _params: QueryUserUniversalTransferHistoryParams,
2483        ) -> anyhow::Result<RestApiResponse<models::QueryUserUniversalTransferHistoryResponse>>
2484        {
2485            if self.force_error {
2486                return Err(ConnectorError::ConnectorClientError {
2487                    msg: "ResponseError".to_string(),
2488                    code: None,
2489                }
2490                .into());
2491            }
2492
2493            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!({}));
2494            let dummy_response: models::QueryUserUniversalTransferHistoryResponse =
2495                serde_json::from_value(resp_json.clone())
2496                    .expect("should parse into models::QueryUserUniversalTransferHistoryResponse");
2497
2498            let dummy = DummyRestApiResponse {
2499                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2500                status: 200,
2501                headers: HashMap::new(),
2502                rate_limits: None,
2503            };
2504
2505            Ok(dummy.into())
2506        }
2507
2508        async fn query_user_wallet_balance(
2509            &self,
2510            _params: QueryUserWalletBalanceParams,
2511        ) -> anyhow::Result<RestApiResponse<Vec<models::QueryUserWalletBalanceResponseInner>>>
2512        {
2513            if self.force_error {
2514                return Err(ConnectorError::ConnectorClientError {
2515                    msg: "ResponseError".to_string(),
2516                    code: None,
2517                }
2518                .into());
2519            }
2520
2521            let resp_json: Value = serde_json::from_str(r#"[{"activate":true,"balance":"0","walletName":"Spot","assetBalances":[{"asset":"USDT","assetName":"TetherUS","free":"6.238383","locked":"0","freeze":"0","withdrawing":"0","btcValuation":"6.238383"}]}]"#).unwrap_or_else(|_| serde_json::json!({}));
2522            let dummy_response: Vec<models::QueryUserWalletBalanceResponseInner> =
2523                serde_json::from_value(resp_json.clone())
2524                    .expect("should parse into Vec<models::QueryUserWalletBalanceResponseInner>");
2525
2526            let dummy = DummyRestApiResponse {
2527                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2528                status: 200,
2529                headers: HashMap::new(),
2530                rate_limits: None,
2531            };
2532
2533            Ok(dummy.into())
2534        }
2535
2536        async fn toggle_bnb_burn_on_spot_trade_and_margin_interest(
2537            &self,
2538            _params: ToggleBnbBurnOnSpotTradeAndMarginInterestParams,
2539        ) -> anyhow::Result<
2540            RestApiResponse<models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse>,
2541        > {
2542            if self.force_error {
2543                return Err(ConnectorError::ConnectorClientError {
2544                    msg: "ResponseError".to_string(),
2545                    code: None,
2546                }
2547                .into());
2548            }
2549
2550            let resp_json: Value =
2551                serde_json::from_str(r#"{"spotBNBBurn":true,"interestBNBBurn":false}"#)
2552                    .unwrap_or_else(|_| serde_json::json!({}));
2553            let dummy_response: models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse =
2554                serde_json::from_value(resp_json.clone()).expect(
2555                    "should parse into models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse",
2556                );
2557
2558            let dummy = DummyRestApiResponse {
2559                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2560                status: 200,
2561                headers: HashMap::new(),
2562                rate_limits: None,
2563            };
2564
2565            Ok(dummy.into())
2566        }
2567
2568        async fn trade_fee(
2569            &self,
2570            _params: TradeFeeParams,
2571        ) -> anyhow::Result<RestApiResponse<Vec<models::TradeFeeResponseInner>>> {
2572            if self.force_error {
2573                return Err(ConnectorError::ConnectorClientError {
2574                    msg: "ResponseError".to_string(),
2575                    code: None,
2576                }
2577                .into());
2578            }
2579
2580            let resp_json: Value = serde_json::from_str(
2581                r#"[{"symbol":"ADABNB","makerCommission":"0.001","takerCommission":"0.001"}]"#,
2582            )
2583            .unwrap_or_else(|_| serde_json::json!({}));
2584            let dummy_response: Vec<models::TradeFeeResponseInner> =
2585                serde_json::from_value(resp_json.clone())
2586                    .expect("should parse into Vec<models::TradeFeeResponseInner>");
2587
2588            let dummy = DummyRestApiResponse {
2589                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2590                status: 200,
2591                headers: HashMap::new(),
2592                rate_limits: None,
2593            };
2594
2595            Ok(dummy.into())
2596        }
2597
2598        async fn user_asset(
2599            &self,
2600            _params: UserAssetParams,
2601        ) -> anyhow::Result<RestApiResponse<Vec<models::UserAssetResponseInner>>> {
2602            if self.force_error {
2603                return Err(ConnectorError::ConnectorClientError {
2604                    msg: "ResponseError".to_string(),
2605                    code: None,
2606                }
2607                .into());
2608            }
2609
2610            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!({}));
2611            let dummy_response: Vec<models::UserAssetResponseInner> =
2612                serde_json::from_value(resp_json.clone())
2613                    .expect("should parse into Vec<models::UserAssetResponseInner>");
2614
2615            let dummy = DummyRestApiResponse {
2616                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2617                status: 200,
2618                headers: HashMap::new(),
2619                rate_limits: None,
2620            };
2621
2622            Ok(dummy.into())
2623        }
2624
2625        async fn user_universal_transfer(
2626            &self,
2627            _params: UserUniversalTransferParams,
2628        ) -> anyhow::Result<RestApiResponse<models::UserUniversalTransferResponse>> {
2629            if self.force_error {
2630                return Err(ConnectorError::ConnectorClientError {
2631                    msg: "ResponseError".to_string(),
2632                    code: None,
2633                }
2634                .into());
2635            }
2636
2637            let resp_json: Value = serde_json::from_str(r#"{"tranId":13526853623}"#)
2638                .unwrap_or_else(|_| serde_json::json!({}));
2639            let dummy_response: models::UserUniversalTransferResponse =
2640                serde_json::from_value(resp_json.clone())
2641                    .expect("should parse into models::UserUniversalTransferResponse");
2642
2643            let dummy = DummyRestApiResponse {
2644                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2645                status: 200,
2646                headers: HashMap::new(),
2647                rate_limits: None,
2648            };
2649
2650            Ok(dummy.into())
2651        }
2652    }
2653
2654    #[test]
2655    fn asset_detail_required_params_success() {
2656        TOKIO_SHARED_RT.block_on(async {
2657            let client = MockAssetApiClient { force_error: false };
2658
2659            let params = AssetDetailParams::builder().build().unwrap();
2660
2661            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!({}));
2662            let expected_response : models::AssetDetailResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AssetDetailResponse");
2663
2664            let resp = client.asset_detail(params).await.expect("Expected a response");
2665            let data_future = resp.data();
2666            let actual_response = data_future.await.unwrap();
2667            assert_eq!(actual_response, expected_response);
2668        });
2669    }
2670
2671    #[test]
2672    fn asset_detail_optional_params_success() {
2673        TOKIO_SHARED_RT.block_on(async {
2674            let client = MockAssetApiClient { force_error: false };
2675
2676            let params = AssetDetailParams::builder().asset("BTC".to_string()).recv_window(5000).build().unwrap();
2677
2678            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!({}));
2679            let expected_response : models::AssetDetailResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AssetDetailResponse");
2680
2681            let resp = client.asset_detail(params).await.expect("Expected a response");
2682            let data_future = resp.data();
2683            let actual_response = data_future.await.unwrap();
2684            assert_eq!(actual_response, expected_response);
2685        });
2686    }
2687
2688    #[test]
2689    fn asset_detail_response_error() {
2690        TOKIO_SHARED_RT.block_on(async {
2691            let client = MockAssetApiClient { force_error: true };
2692
2693            let params = AssetDetailParams::builder().build().unwrap();
2694
2695            match client.asset_detail(params).await {
2696                Ok(_) => panic!("Expected an error"),
2697                Err(err) => {
2698                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2699                }
2700            }
2701        });
2702    }
2703
2704    #[test]
2705    fn asset_dividend_record_required_params_success() {
2706        TOKIO_SHARED_RT.block_on(async {
2707            let client = MockAssetApiClient { force_error: false };
2708
2709            let params = AssetDividendRecordParams::builder().build().unwrap();
2710
2711            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!({}));
2712            let expected_response : models::AssetDividendRecordResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AssetDividendRecordResponse");
2713
2714            let resp = client.asset_dividend_record(params).await.expect("Expected a response");
2715            let data_future = resp.data();
2716            let actual_response = data_future.await.unwrap();
2717            assert_eq!(actual_response, expected_response);
2718        });
2719    }
2720
2721    #[test]
2722    fn asset_dividend_record_optional_params_success() {
2723        TOKIO_SHARED_RT.block_on(async {
2724            let client = MockAssetApiClient { force_error: false };
2725
2726            let params = AssetDividendRecordParams::builder().asset("BTC".to_string()).start_time(1623319461670).end_time(1641782889000).limit(20).recv_window(5000).build().unwrap();
2727
2728            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!({}));
2729            let expected_response : models::AssetDividendRecordResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AssetDividendRecordResponse");
2730
2731            let resp = client.asset_dividend_record(params).await.expect("Expected a response");
2732            let data_future = resp.data();
2733            let actual_response = data_future.await.unwrap();
2734            assert_eq!(actual_response, expected_response);
2735        });
2736    }
2737
2738    #[test]
2739    fn asset_dividend_record_response_error() {
2740        TOKIO_SHARED_RT.block_on(async {
2741            let client = MockAssetApiClient { force_error: true };
2742
2743            let params = AssetDividendRecordParams::builder().build().unwrap();
2744
2745            match client.asset_dividend_record(params).await {
2746                Ok(_) => panic!("Expected an error"),
2747                Err(err) => {
2748                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2749                }
2750            }
2751        });
2752    }
2753
2754    #[test]
2755    fn dust_convert_required_params_success() {
2756        TOKIO_SHARED_RT.block_on(async {
2757            let client = MockAssetApiClient { force_error: false };
2758
2759            let params = DustConvertParams::builder("USDT".to_string(),).build().unwrap();
2760
2761            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!({}));
2762            let expected_response : models::DustConvertResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustConvertResponse");
2763
2764            let resp = client.dust_convert(params).await.expect("Expected a response");
2765            let data_future = resp.data();
2766            let actual_response = data_future.await.unwrap();
2767            assert_eq!(actual_response, expected_response);
2768        });
2769    }
2770
2771    #[test]
2772    fn dust_convert_optional_params_success() {
2773        TOKIO_SHARED_RT.block_on(async {
2774            let client = MockAssetApiClient { force_error: false };
2775
2776            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();
2777
2778            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!({}));
2779            let expected_response : models::DustConvertResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustConvertResponse");
2780
2781            let resp = client.dust_convert(params).await.expect("Expected a response");
2782            let data_future = resp.data();
2783            let actual_response = data_future.await.unwrap();
2784            assert_eq!(actual_response, expected_response);
2785        });
2786    }
2787
2788    #[test]
2789    fn dust_convert_response_error() {
2790        TOKIO_SHARED_RT.block_on(async {
2791            let client = MockAssetApiClient { force_error: true };
2792
2793            let params = DustConvertParams::builder("USDT".to_string())
2794                .build()
2795                .unwrap();
2796
2797            match client.dust_convert(params).await {
2798                Ok(_) => panic!("Expected an error"),
2799                Err(err) => {
2800                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2801                }
2802            }
2803        });
2804    }
2805
2806    #[test]
2807    fn dust_convertible_assets_required_params_success() {
2808        TOKIO_SHARED_RT.block_on(async {
2809            let client = MockAssetApiClient { force_error: false };
2810
2811            let params = DustConvertibleAssetsParams::builder("BTC".to_string(),).build().unwrap();
2812
2813            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!({}));
2814            let expected_response : models::DustConvertibleAssetsResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustConvertibleAssetsResponse");
2815
2816            let resp = client.dust_convertible_assets(params).await.expect("Expected a response");
2817            let data_future = resp.data();
2818            let actual_response = data_future.await.unwrap();
2819            assert_eq!(actual_response, expected_response);
2820        });
2821    }
2822
2823    #[test]
2824    fn dust_convertible_assets_optional_params_success() {
2825        TOKIO_SHARED_RT.block_on(async {
2826            let client = MockAssetApiClient { force_error: false };
2827
2828            let params = DustConvertibleAssetsParams::builder("BTC".to_string(),).account_type("SPOT".to_string()).dust_quota_asset_to_target_asset_price(dec!(1.0)).build().unwrap();
2829
2830            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!({}));
2831            let expected_response : models::DustConvertibleAssetsResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustConvertibleAssetsResponse");
2832
2833            let resp = client.dust_convertible_assets(params).await.expect("Expected a response");
2834            let data_future = resp.data();
2835            let actual_response = data_future.await.unwrap();
2836            assert_eq!(actual_response, expected_response);
2837        });
2838    }
2839
2840    #[test]
2841    fn dust_convertible_assets_response_error() {
2842        TOKIO_SHARED_RT.block_on(async {
2843            let client = MockAssetApiClient { force_error: true };
2844
2845            let params = DustConvertibleAssetsParams::builder("BTC".to_string())
2846                .build()
2847                .unwrap();
2848
2849            match client.dust_convertible_assets(params).await {
2850                Ok(_) => panic!("Expected an error"),
2851                Err(err) => {
2852                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2853                }
2854            }
2855        });
2856    }
2857
2858    #[test]
2859    fn dust_transfer_required_params_success() {
2860        TOKIO_SHARED_RT.block_on(async {
2861            let client = MockAssetApiClient { force_error: false };
2862
2863            let params = DustTransferParams::builder("BTC".to_string(),).build().unwrap();
2864
2865            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!({}));
2866            let expected_response : models::DustTransferResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustTransferResponse");
2867
2868            let resp = client.dust_transfer(params).await.expect("Expected a response");
2869            let data_future = resp.data();
2870            let actual_response = data_future.await.unwrap();
2871            assert_eq!(actual_response, expected_response);
2872        });
2873    }
2874
2875    #[test]
2876    fn dust_transfer_optional_params_success() {
2877        TOKIO_SHARED_RT.block_on(async {
2878            let client = MockAssetApiClient { force_error: false };
2879
2880            let params = DustTransferParams::builder("BTC".to_string(),).account_type(DustTransferAccountTypeEnum::Spot).recv_window(5000).build().unwrap();
2881
2882            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!({}));
2883            let expected_response : models::DustTransferResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustTransferResponse");
2884
2885            let resp = client.dust_transfer(params).await.expect("Expected a response");
2886            let data_future = resp.data();
2887            let actual_response = data_future.await.unwrap();
2888            assert_eq!(actual_response, expected_response);
2889        });
2890    }
2891
2892    #[test]
2893    fn dust_transfer_response_error() {
2894        TOKIO_SHARED_RT.block_on(async {
2895            let client = MockAssetApiClient { force_error: true };
2896
2897            let params = DustTransferParams::builder("BTC".to_string())
2898                .build()
2899                .unwrap();
2900
2901            match client.dust_transfer(params).await {
2902                Ok(_) => panic!("Expected an error"),
2903                Err(err) => {
2904                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2905                }
2906            }
2907        });
2908    }
2909
2910    #[test]
2911    fn dustlog_required_params_success() {
2912        TOKIO_SHARED_RT.block_on(async {
2913            let client = MockAssetApiClient { force_error: false };
2914
2915            let params = DustlogParams::builder().build().unwrap();
2916
2917            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!({}));
2918            let expected_response : models::DustlogResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustlogResponse");
2919
2920            let resp = client.dustlog(params).await.expect("Expected a response");
2921            let data_future = resp.data();
2922            let actual_response = data_future.await.unwrap();
2923            assert_eq!(actual_response, expected_response);
2924        });
2925    }
2926
2927    #[test]
2928    fn dustlog_optional_params_success() {
2929        TOKIO_SHARED_RT.block_on(async {
2930            let client = MockAssetApiClient { force_error: false };
2931
2932            let params = DustlogParams::builder().account_type(DustlogAccountTypeEnum::Spot).start_time(1623319461670).end_time(1641782889000).recv_window(5000).build().unwrap();
2933
2934            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!({}));
2935            let expected_response : models::DustlogResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustlogResponse");
2936
2937            let resp = client.dustlog(params).await.expect("Expected a response");
2938            let data_future = resp.data();
2939            let actual_response = data_future.await.unwrap();
2940            assert_eq!(actual_response, expected_response);
2941        });
2942    }
2943
2944    #[test]
2945    fn dustlog_response_error() {
2946        TOKIO_SHARED_RT.block_on(async {
2947            let client = MockAssetApiClient { force_error: true };
2948
2949            let params = DustlogParams::builder().build().unwrap();
2950
2951            match client.dustlog(params).await {
2952                Ok(_) => panic!("Expected an error"),
2953                Err(err) => {
2954                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2955                }
2956            }
2957        });
2958    }
2959
2960    #[test]
2961    fn funding_wallet_required_params_success() {
2962        TOKIO_SHARED_RT.block_on(async {
2963            let client = MockAssetApiClient { force_error: false };
2964
2965            let params = FundingWalletParams::builder().build().unwrap();
2966
2967            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!({}));
2968            let expected_response : Vec<models::FundingWalletResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::FundingWalletResponseInner>");
2969
2970            let resp = client.funding_wallet(params).await.expect("Expected a response");
2971            let data_future = resp.data();
2972            let actual_response = data_future.await.unwrap();
2973            assert_eq!(actual_response, expected_response);
2974        });
2975    }
2976
2977    #[test]
2978    fn funding_wallet_optional_params_success() {
2979        TOKIO_SHARED_RT.block_on(async {
2980            let client = MockAssetApiClient { force_error: false };
2981
2982            let params = FundingWalletParams::builder().asset("BTC".to_string()).need_btc_valuation(true).recv_window(5000).build().unwrap();
2983
2984            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!({}));
2985            let expected_response : Vec<models::FundingWalletResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::FundingWalletResponseInner>");
2986
2987            let resp = client.funding_wallet(params).await.expect("Expected a response");
2988            let data_future = resp.data();
2989            let actual_response = data_future.await.unwrap();
2990            assert_eq!(actual_response, expected_response);
2991        });
2992    }
2993
2994    #[test]
2995    fn funding_wallet_response_error() {
2996        TOKIO_SHARED_RT.block_on(async {
2997            let client = MockAssetApiClient { force_error: true };
2998
2999            let params = FundingWalletParams::builder().build().unwrap();
3000
3001            match client.funding_wallet(params).await {
3002                Ok(_) => panic!("Expected an error"),
3003                Err(err) => {
3004                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3005                }
3006            }
3007        });
3008    }
3009
3010    #[test]
3011    fn get_assets_that_can_be_converted_into_bnb_required_params_success() {
3012        TOKIO_SHARED_RT.block_on(async {
3013            let client = MockAssetApiClient { force_error: false };
3014
3015            let params = GetAssetsThatCanBeConvertedIntoBnbParams::builder().build().unwrap();
3016
3017            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!({}));
3018            let expected_response : models::GetAssetsThatCanBeConvertedIntoBnbResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetAssetsThatCanBeConvertedIntoBnbResponse");
3019
3020            let resp = client.get_assets_that_can_be_converted_into_bnb(params).await.expect("Expected a response");
3021            let data_future = resp.data();
3022            let actual_response = data_future.await.unwrap();
3023            assert_eq!(actual_response, expected_response);
3024        });
3025    }
3026
3027    #[test]
3028    fn get_assets_that_can_be_converted_into_bnb_optional_params_success() {
3029        TOKIO_SHARED_RT.block_on(async {
3030            let client = MockAssetApiClient { force_error: false };
3031
3032            let params = GetAssetsThatCanBeConvertedIntoBnbParams::builder().account_type(GetAssetsThatCanBeConvertedIntoBnbAccountTypeEnum::Spot).recv_window(5000).build().unwrap();
3033
3034            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!({}));
3035            let expected_response : models::GetAssetsThatCanBeConvertedIntoBnbResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetAssetsThatCanBeConvertedIntoBnbResponse");
3036
3037            let resp = client.get_assets_that_can_be_converted_into_bnb(params).await.expect("Expected a response");
3038            let data_future = resp.data();
3039            let actual_response = data_future.await.unwrap();
3040            assert_eq!(actual_response, expected_response);
3041        });
3042    }
3043
3044    #[test]
3045    fn get_assets_that_can_be_converted_into_bnb_response_error() {
3046        TOKIO_SHARED_RT.block_on(async {
3047            let client = MockAssetApiClient { force_error: true };
3048
3049            let params = GetAssetsThatCanBeConvertedIntoBnbParams::builder()
3050                .build()
3051                .unwrap();
3052
3053            match client
3054                .get_assets_that_can_be_converted_into_bnb(params)
3055                .await
3056            {
3057                Ok(_) => panic!("Expected an error"),
3058                Err(err) => {
3059                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3060                }
3061            }
3062        });
3063    }
3064
3065    #[test]
3066    fn get_cloud_mining_payment_and_refund_history_required_params_success() {
3067        TOKIO_SHARED_RT.block_on(async {
3068            let client = MockAssetApiClient { force_error: false };
3069
3070            let params = GetCloudMiningPaymentAndRefundHistoryParams::builder(1623319461670,1641782889000,).build().unwrap();
3071
3072            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!({}));
3073            let expected_response : models::GetCloudMiningPaymentAndRefundHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetCloudMiningPaymentAndRefundHistoryResponse");
3074
3075            let resp = client.get_cloud_mining_payment_and_refund_history(params).await.expect("Expected a response");
3076            let data_future = resp.data();
3077            let actual_response = data_future.await.unwrap();
3078            assert_eq!(actual_response, expected_response);
3079        });
3080    }
3081
3082    #[test]
3083    fn get_cloud_mining_payment_and_refund_history_optional_params_success() {
3084        TOKIO_SHARED_RT.block_on(async {
3085            let client = MockAssetApiClient { force_error: false };
3086
3087            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();
3088
3089            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!({}));
3090            let expected_response : models::GetCloudMiningPaymentAndRefundHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetCloudMiningPaymentAndRefundHistoryResponse");
3091
3092            let resp = client.get_cloud_mining_payment_and_refund_history(params).await.expect("Expected a response");
3093            let data_future = resp.data();
3094            let actual_response = data_future.await.unwrap();
3095            assert_eq!(actual_response, expected_response);
3096        });
3097    }
3098
3099    #[test]
3100    fn get_cloud_mining_payment_and_refund_history_response_error() {
3101        TOKIO_SHARED_RT.block_on(async {
3102            let client = MockAssetApiClient { force_error: true };
3103
3104            let params =
3105                GetCloudMiningPaymentAndRefundHistoryParams::builder(1623319461670, 1641782889000)
3106                    .build()
3107                    .unwrap();
3108
3109            match client
3110                .get_cloud_mining_payment_and_refund_history(params)
3111                .await
3112            {
3113                Ok(_) => panic!("Expected an error"),
3114                Err(err) => {
3115                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3116                }
3117            }
3118        });
3119    }
3120
3121    #[test]
3122    fn get_open_symbol_list_required_params_success() {
3123        TOKIO_SHARED_RT.block_on(async {
3124            let client = MockAssetApiClient { force_error: false };
3125
3126            let resp_json: Value =
3127                serde_json::from_str(r#"[{"openTime":1686161202000,"symbols":["BNBBTC"]}]"#)
3128                    .unwrap_or_else(|_| serde_json::json!({}));
3129            let expected_response: Vec<models::GetOpenSymbolListResponseInner> =
3130                serde_json::from_value(resp_json.clone())
3131                    .expect("should parse into Vec<models::GetOpenSymbolListResponseInner>");
3132
3133            let resp = client
3134                .get_open_symbol_list()
3135                .await
3136                .expect("Expected a response");
3137            let data_future = resp.data();
3138            let actual_response = data_future.await.unwrap();
3139            assert_eq!(actual_response, expected_response);
3140        });
3141    }
3142
3143    #[test]
3144    fn get_open_symbol_list_optional_params_success() {
3145        TOKIO_SHARED_RT.block_on(async {
3146            let client = MockAssetApiClient { force_error: false };
3147
3148            let resp_json: Value =
3149                serde_json::from_str(r#"[{"openTime":1686161202000,"symbols":["BNBBTC"]}]"#)
3150                    .unwrap_or_else(|_| serde_json::json!({}));
3151            let expected_response: Vec<models::GetOpenSymbolListResponseInner> =
3152                serde_json::from_value(resp_json.clone())
3153                    .expect("should parse into Vec<models::GetOpenSymbolListResponseInner>");
3154
3155            let resp = client
3156                .get_open_symbol_list()
3157                .await
3158                .expect("Expected a response");
3159            let data_future = resp.data();
3160            let actual_response = data_future.await.unwrap();
3161            assert_eq!(actual_response, expected_response);
3162        });
3163    }
3164
3165    #[test]
3166    fn get_open_symbol_list_response_error() {
3167        TOKIO_SHARED_RT.block_on(async {
3168            let client = MockAssetApiClient { force_error: true };
3169
3170            match client.get_open_symbol_list().await {
3171                Ok(_) => panic!("Expected an error"),
3172                Err(err) => {
3173                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3174                }
3175            }
3176        });
3177    }
3178
3179    #[test]
3180    fn get_spot_asset_tags_required_params_success() {
3181        TOKIO_SHARED_RT.block_on(async {
3182            let client = MockAssetApiClient { force_error: false };
3183
3184            let params = GetSpotAssetTagsParams::builder().build().unwrap();
3185
3186            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!({}));
3187            let expected_response : Vec<models::GetSpotAssetTagsResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::GetSpotAssetTagsResponseInner>");
3188
3189            let resp = client.get_spot_asset_tags(params).await.expect("Expected a response");
3190            let data_future = resp.data();
3191            let actual_response = data_future.await.unwrap();
3192            assert_eq!(actual_response, expected_response);
3193        });
3194    }
3195
3196    #[test]
3197    fn get_spot_asset_tags_optional_params_success() {
3198        TOKIO_SHARED_RT.block_on(async {
3199            let client = MockAssetApiClient { force_error: false };
3200
3201            let params = GetSpotAssetTagsParams::builder().tag("Layer1_Layer2,BSC".to_string()).build().unwrap();
3202
3203            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!({}));
3204            let expected_response : Vec<models::GetSpotAssetTagsResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::GetSpotAssetTagsResponseInner>");
3205
3206            let resp = client.get_spot_asset_tags(params).await.expect("Expected a response");
3207            let data_future = resp.data();
3208            let actual_response = data_future.await.unwrap();
3209            assert_eq!(actual_response, expected_response);
3210        });
3211    }
3212
3213    #[test]
3214    fn get_spot_asset_tags_response_error() {
3215        TOKIO_SHARED_RT.block_on(async {
3216            let client = MockAssetApiClient { force_error: true };
3217
3218            let params = GetSpotAssetTagsParams::builder().build().unwrap();
3219
3220            match client.get_spot_asset_tags(params).await {
3221                Ok(_) => panic!("Expected an error"),
3222                Err(err) => {
3223                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3224                }
3225            }
3226        });
3227    }
3228
3229    #[test]
3230    fn query_user_delegation_history_required_params_success() {
3231        TOKIO_SHARED_RT.block_on(async {
3232            let client = MockAssetApiClient { force_error: false };
3233
3234            let params = QueryUserDelegationHistoryParams::builder("abc@test.com".to_string(),1623319461670,1641782889000,).build().unwrap();
3235
3236            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!({}));
3237            let expected_response : models::QueryUserDelegationHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::QueryUserDelegationHistoryResponse");
3238
3239            let resp = client.query_user_delegation_history(params).await.expect("Expected a response");
3240            let data_future = resp.data();
3241            let actual_response = data_future.await.unwrap();
3242            assert_eq!(actual_response, expected_response);
3243        });
3244    }
3245
3246    #[test]
3247    fn query_user_delegation_history_optional_params_success() {
3248        TOKIO_SHARED_RT.block_on(async {
3249            let client = MockAssetApiClient { force_error: false };
3250
3251            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();
3252
3253            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!({}));
3254            let expected_response : models::QueryUserDelegationHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::QueryUserDelegationHistoryResponse");
3255
3256            let resp = client.query_user_delegation_history(params).await.expect("Expected a response");
3257            let data_future = resp.data();
3258            let actual_response = data_future.await.unwrap();
3259            assert_eq!(actual_response, expected_response);
3260        });
3261    }
3262
3263    #[test]
3264    fn query_user_delegation_history_response_error() {
3265        TOKIO_SHARED_RT.block_on(async {
3266            let client = MockAssetApiClient { force_error: true };
3267
3268            let params = QueryUserDelegationHistoryParams::builder(
3269                "abc@test.com".to_string(),
3270                1623319461670,
3271                1641782889000,
3272            )
3273            .build()
3274            .unwrap();
3275
3276            match client.query_user_delegation_history(params).await {
3277                Ok(_) => panic!("Expected an error"),
3278                Err(err) => {
3279                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3280                }
3281            }
3282        });
3283    }
3284
3285    #[test]
3286    fn query_user_universal_transfer_history_required_params_success() {
3287        TOKIO_SHARED_RT.block_on(async {
3288            let client = MockAssetApiClient { force_error: false };
3289
3290            let params = QueryUserUniversalTransferHistoryParams::builder("r#type_example".to_string(),).build().unwrap();
3291
3292            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!({}));
3293            let expected_response : models::QueryUserUniversalTransferHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::QueryUserUniversalTransferHistoryResponse");
3294
3295            let resp = client.query_user_universal_transfer_history(params).await.expect("Expected a response");
3296            let data_future = resp.data();
3297            let actual_response = data_future.await.unwrap();
3298            assert_eq!(actual_response, expected_response);
3299        });
3300    }
3301
3302    #[test]
3303    fn query_user_universal_transfer_history_optional_params_success() {
3304        TOKIO_SHARED_RT.block_on(async {
3305            let client = MockAssetApiClient { force_error: false };
3306
3307            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();
3308
3309            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!({}));
3310            let expected_response : models::QueryUserUniversalTransferHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::QueryUserUniversalTransferHistoryResponse");
3311
3312            let resp = client.query_user_universal_transfer_history(params).await.expect("Expected a response");
3313            let data_future = resp.data();
3314            let actual_response = data_future.await.unwrap();
3315            assert_eq!(actual_response, expected_response);
3316        });
3317    }
3318
3319    #[test]
3320    fn query_user_universal_transfer_history_response_error() {
3321        TOKIO_SHARED_RT.block_on(async {
3322            let client = MockAssetApiClient { force_error: true };
3323
3324            let params =
3325                QueryUserUniversalTransferHistoryParams::builder("r#type_example".to_string())
3326                    .build()
3327                    .unwrap();
3328
3329            match client.query_user_universal_transfer_history(params).await {
3330                Ok(_) => panic!("Expected an error"),
3331                Err(err) => {
3332                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3333                }
3334            }
3335        });
3336    }
3337
3338    #[test]
3339    fn query_user_wallet_balance_required_params_success() {
3340        TOKIO_SHARED_RT.block_on(async {
3341            let client = MockAssetApiClient { force_error: false };
3342
3343            let params = QueryUserWalletBalanceParams::builder().build().unwrap();
3344
3345            let resp_json: Value = serde_json::from_str(r#"[{"activate":true,"balance":"0","walletName":"Spot","assetBalances":[{"asset":"USDT","assetName":"TetherUS","free":"6.238383","locked":"0","freeze":"0","withdrawing":"0","btcValuation":"6.238383"}]}]"#).unwrap_or_else(|_| serde_json::json!({}));
3346            let expected_response : Vec<models::QueryUserWalletBalanceResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::QueryUserWalletBalanceResponseInner>");
3347
3348            let resp = client.query_user_wallet_balance(params).await.expect("Expected a response");
3349            let data_future = resp.data();
3350            let actual_response = data_future.await.unwrap();
3351            assert_eq!(actual_response, expected_response);
3352        });
3353    }
3354
3355    #[test]
3356    fn query_user_wallet_balance_optional_params_success() {
3357        TOKIO_SHARED_RT.block_on(async {
3358            let client = MockAssetApiClient { force_error: false };
3359
3360            let params = QueryUserWalletBalanceParams::builder().quote_asset("BTC".to_string()).need_balance_detail(false).recv_window(5000).build().unwrap();
3361
3362            let resp_json: Value = serde_json::from_str(r#"[{"activate":true,"balance":"0","walletName":"Spot","assetBalances":[{"asset":"USDT","assetName":"TetherUS","free":"6.238383","locked":"0","freeze":"0","withdrawing":"0","btcValuation":"6.238383"}]}]"#).unwrap_or_else(|_| serde_json::json!({}));
3363            let expected_response : Vec<models::QueryUserWalletBalanceResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::QueryUserWalletBalanceResponseInner>");
3364
3365            let resp = client.query_user_wallet_balance(params).await.expect("Expected a response");
3366            let data_future = resp.data();
3367            let actual_response = data_future.await.unwrap();
3368            assert_eq!(actual_response, expected_response);
3369        });
3370    }
3371
3372    #[test]
3373    fn query_user_wallet_balance_response_error() {
3374        TOKIO_SHARED_RT.block_on(async {
3375            let client = MockAssetApiClient { force_error: true };
3376
3377            let params = QueryUserWalletBalanceParams::builder().build().unwrap();
3378
3379            match client.query_user_wallet_balance(params).await {
3380                Ok(_) => panic!("Expected an error"),
3381                Err(err) => {
3382                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3383                }
3384            }
3385        });
3386    }
3387
3388    #[test]
3389    fn toggle_bnb_burn_on_spot_trade_and_margin_interest_required_params_success() {
3390        TOKIO_SHARED_RT.block_on(async {
3391            let client = MockAssetApiClient { force_error: false };
3392
3393            let params = ToggleBnbBurnOnSpotTradeAndMarginInterestParams::builder()
3394                .build()
3395                .unwrap();
3396
3397            let resp_json: Value =
3398                serde_json::from_str(r#"{"spotBNBBurn":true,"interestBNBBurn":false}"#)
3399                    .unwrap_or_else(|_| serde_json::json!({}));
3400            let expected_response: models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse =
3401                serde_json::from_value(resp_json.clone()).expect(
3402                    "should parse into models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse",
3403                );
3404
3405            let resp = client
3406                .toggle_bnb_burn_on_spot_trade_and_margin_interest(params)
3407                .await
3408                .expect("Expected a response");
3409            let data_future = resp.data();
3410            let actual_response = data_future.await.unwrap();
3411            assert_eq!(actual_response, expected_response);
3412        });
3413    }
3414
3415    #[test]
3416    fn toggle_bnb_burn_on_spot_trade_and_margin_interest_optional_params_success() {
3417        TOKIO_SHARED_RT.block_on(async {
3418            let client = MockAssetApiClient { force_error: false };
3419
3420            let params = ToggleBnbBurnOnSpotTradeAndMarginInterestParams::builder()
3421                .spot_bnb_burn("true".to_string())
3422                .interest_bnb_burn("true".to_string())
3423                .recv_window(5000)
3424                .build()
3425                .unwrap();
3426
3427            let resp_json: Value =
3428                serde_json::from_str(r#"{"spotBNBBurn":true,"interestBNBBurn":false}"#)
3429                    .unwrap_or_else(|_| serde_json::json!({}));
3430            let expected_response: models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse =
3431                serde_json::from_value(resp_json.clone()).expect(
3432                    "should parse into models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse",
3433                );
3434
3435            let resp = client
3436                .toggle_bnb_burn_on_spot_trade_and_margin_interest(params)
3437                .await
3438                .expect("Expected a response");
3439            let data_future = resp.data();
3440            let actual_response = data_future.await.unwrap();
3441            assert_eq!(actual_response, expected_response);
3442        });
3443    }
3444
3445    #[test]
3446    fn toggle_bnb_burn_on_spot_trade_and_margin_interest_response_error() {
3447        TOKIO_SHARED_RT.block_on(async {
3448            let client = MockAssetApiClient { force_error: true };
3449
3450            let params = ToggleBnbBurnOnSpotTradeAndMarginInterestParams::builder()
3451                .build()
3452                .unwrap();
3453
3454            match client
3455                .toggle_bnb_burn_on_spot_trade_and_margin_interest(params)
3456                .await
3457            {
3458                Ok(_) => panic!("Expected an error"),
3459                Err(err) => {
3460                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3461                }
3462            }
3463        });
3464    }
3465
3466    #[test]
3467    fn trade_fee_required_params_success() {
3468        TOKIO_SHARED_RT.block_on(async {
3469            let client = MockAssetApiClient { force_error: false };
3470
3471            let params = TradeFeeParams::builder().build().unwrap();
3472
3473            let resp_json: Value = serde_json::from_str(
3474                r#"[{"symbol":"ADABNB","makerCommission":"0.001","takerCommission":"0.001"}]"#,
3475            )
3476            .unwrap_or_else(|_| serde_json::json!({}));
3477            let expected_response: Vec<models::TradeFeeResponseInner> =
3478                serde_json::from_value(resp_json.clone())
3479                    .expect("should parse into Vec<models::TradeFeeResponseInner>");
3480
3481            let resp = client.trade_fee(params).await.expect("Expected a response");
3482            let data_future = resp.data();
3483            let actual_response = data_future.await.unwrap();
3484            assert_eq!(actual_response, expected_response);
3485        });
3486    }
3487
3488    #[test]
3489    fn trade_fee_optional_params_success() {
3490        TOKIO_SHARED_RT.block_on(async {
3491            let client = MockAssetApiClient { force_error: false };
3492
3493            let params = TradeFeeParams::builder()
3494                .symbol("ADABNB".to_string())
3495                .recv_window(5000)
3496                .build()
3497                .unwrap();
3498
3499            let resp_json: Value = serde_json::from_str(
3500                r#"[{"symbol":"ADABNB","makerCommission":"0.001","takerCommission":"0.001"}]"#,
3501            )
3502            .unwrap_or_else(|_| serde_json::json!({}));
3503            let expected_response: Vec<models::TradeFeeResponseInner> =
3504                serde_json::from_value(resp_json.clone())
3505                    .expect("should parse into Vec<models::TradeFeeResponseInner>");
3506
3507            let resp = client.trade_fee(params).await.expect("Expected a response");
3508            let data_future = resp.data();
3509            let actual_response = data_future.await.unwrap();
3510            assert_eq!(actual_response, expected_response);
3511        });
3512    }
3513
3514    #[test]
3515    fn trade_fee_response_error() {
3516        TOKIO_SHARED_RT.block_on(async {
3517            let client = MockAssetApiClient { force_error: true };
3518
3519            let params = TradeFeeParams::builder().build().unwrap();
3520
3521            match client.trade_fee(params).await {
3522                Ok(_) => panic!("Expected an error"),
3523                Err(err) => {
3524                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3525                }
3526            }
3527        });
3528    }
3529
3530    #[test]
3531    fn user_asset_required_params_success() {
3532        TOKIO_SHARED_RT.block_on(async {
3533            let client = MockAssetApiClient { force_error: false };
3534
3535            let params = UserAssetParams::builder().build().unwrap();
3536
3537            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!({}));
3538            let expected_response : Vec<models::UserAssetResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::UserAssetResponseInner>");
3539
3540            let resp = client.user_asset(params).await.expect("Expected a response");
3541            let data_future = resp.data();
3542            let actual_response = data_future.await.unwrap();
3543            assert_eq!(actual_response, expected_response);
3544        });
3545    }
3546
3547    #[test]
3548    fn user_asset_optional_params_success() {
3549        TOKIO_SHARED_RT.block_on(async {
3550            let client = MockAssetApiClient { force_error: false };
3551
3552            let params = UserAssetParams::builder().asset("BTC".to_string()).need_btc_valuation(true).recv_window(5000).build().unwrap();
3553
3554            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!({}));
3555            let expected_response : Vec<models::UserAssetResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::UserAssetResponseInner>");
3556
3557            let resp = client.user_asset(params).await.expect("Expected a response");
3558            let data_future = resp.data();
3559            let actual_response = data_future.await.unwrap();
3560            assert_eq!(actual_response, expected_response);
3561        });
3562    }
3563
3564    #[test]
3565    fn user_asset_response_error() {
3566        TOKIO_SHARED_RT.block_on(async {
3567            let client = MockAssetApiClient { force_error: true };
3568
3569            let params = UserAssetParams::builder().build().unwrap();
3570
3571            match client.user_asset(params).await {
3572                Ok(_) => panic!("Expected an error"),
3573                Err(err) => {
3574                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3575                }
3576            }
3577        });
3578    }
3579
3580    #[test]
3581    fn user_universal_transfer_required_params_success() {
3582        TOKIO_SHARED_RT.block_on(async {
3583            let client = MockAssetApiClient { force_error: false };
3584
3585            let params = UserUniversalTransferParams::builder(
3586                UserUniversalTransferTypeEnum::MainUmfuture,
3587                "BTC".to_string(),
3588                dec!(1.0),
3589            )
3590            .build()
3591            .unwrap();
3592
3593            let resp_json: Value = serde_json::from_str(r#"{"tranId":13526853623}"#)
3594                .unwrap_or_else(|_| serde_json::json!({}));
3595            let expected_response: models::UserUniversalTransferResponse =
3596                serde_json::from_value(resp_json.clone())
3597                    .expect("should parse into models::UserUniversalTransferResponse");
3598
3599            let resp = client
3600                .user_universal_transfer(params)
3601                .await
3602                .expect("Expected a response");
3603            let data_future = resp.data();
3604            let actual_response = data_future.await.unwrap();
3605            assert_eq!(actual_response, expected_response);
3606        });
3607    }
3608
3609    #[test]
3610    fn user_universal_transfer_optional_params_success() {
3611        TOKIO_SHARED_RT.block_on(async {
3612            let client = MockAssetApiClient { force_error: false };
3613
3614            let params = UserUniversalTransferParams::builder(
3615                UserUniversalTransferTypeEnum::MainUmfuture,
3616                "BTC".to_string(),
3617                dec!(1.0),
3618            )
3619            .from_symbol(UserUniversalTransferFromSymbolEnum::IsolatedmarginMargin)
3620            .to_symbol(UserUniversalTransferToSymbolEnum::MarginIsolatedmargin)
3621            .recv_window(5000)
3622            .build()
3623            .unwrap();
3624
3625            let resp_json: Value = serde_json::from_str(r#"{"tranId":13526853623}"#)
3626                .unwrap_or_else(|_| serde_json::json!({}));
3627            let expected_response: models::UserUniversalTransferResponse =
3628                serde_json::from_value(resp_json.clone())
3629                    .expect("should parse into models::UserUniversalTransferResponse");
3630
3631            let resp = client
3632                .user_universal_transfer(params)
3633                .await
3634                .expect("Expected a response");
3635            let data_future = resp.data();
3636            let actual_response = data_future.await.unwrap();
3637            assert_eq!(actual_response, expected_response);
3638        });
3639    }
3640
3641    #[test]
3642    fn user_universal_transfer_response_error() {
3643        TOKIO_SHARED_RT.block_on(async {
3644            let client = MockAssetApiClient { force_error: true };
3645
3646            let params = UserUniversalTransferParams::builder(
3647                UserUniversalTransferTypeEnum::MainUmfuture,
3648                "BTC".to_string(),
3649                dec!(1.0),
3650            )
3651            .build()
3652            .unwrap();
3653
3654            match client.user_universal_transfer(params).await {
3655                Ok(_) => panic!("Expected an error"),
3656                Err(err) => {
3657                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3658                }
3659            }
3660        });
3661    }
3662}