1#![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 CapitalApi: Send + Sync {
34 async fn all_coins_information(
35 &self,
36 params: AllCoinsInformationParams,
37 ) -> anyhow::Result<RestApiResponse<Vec<models::AllCoinsInformationResponseInner>>>;
38 async fn deposit_address(
39 &self,
40 params: DepositAddressParams,
41 ) -> anyhow::Result<RestApiResponse<models::DepositAddressResponse>>;
42 async fn deposit_history(
43 &self,
44 params: DepositHistoryParams,
45 ) -> anyhow::Result<RestApiResponse<Vec<models::DepositHistoryResponseInner>>>;
46 async fn fetch_deposit_address_list_with_network(
47 &self,
48 params: FetchDepositAddressListWithNetworkParams,
49 ) -> anyhow::Result<RestApiResponse<Vec<models::FetchDepositAddressListWithNetworkResponseInner>>>;
50 async fn fetch_withdraw_address_list(
51 &self,
52 ) -> anyhow::Result<RestApiResponse<Vec<models::FetchWithdrawAddressListResponseInner>>>;
53 async fn fetch_withdraw_quota(
54 &self,
55 ) -> anyhow::Result<RestApiResponse<models::FetchWithdrawQuotaResponse>>;
56 async fn one_click_arrival_deposit_apply(
57 &self,
58 params: OneClickArrivalDepositApplyParams,
59 ) -> anyhow::Result<RestApiResponse<models::OneClickArrivalDepositApplyResponse>>;
60 async fn withdraw(
61 &self,
62 params: WithdrawParams,
63 ) -> anyhow::Result<RestApiResponse<models::WithdrawResponse>>;
64 async fn withdraw_history(
65 &self,
66 params: WithdrawHistoryParams,
67 ) -> anyhow::Result<RestApiResponse<Vec<models::WithdrawHistoryResponseInner>>>;
68}
69
70#[derive(Debug, Clone)]
71pub struct CapitalApiClient {
72 configuration: ConfigurationRestApi,
73}
74
75impl CapitalApiClient {
76 pub fn new(configuration: ConfigurationRestApi) -> Self {
77 Self { configuration }
78 }
79}
80
81#[allow(non_camel_case_types)]
82#[derive(Debug, Clone, Serialize, Deserialize)]
83pub enum DepositHistoryStatusEnum {
84 #[serde(rename = "0")]
85 Status0,
86 #[serde(rename = "1")]
87 Status1,
88 #[serde(rename = "2")]
89 Status2,
90 #[serde(rename = "6")]
91 Status6,
92 #[serde(rename = "7")]
93 Status7,
94 #[serde(rename = "8")]
95 Status8,
96}
97
98impl DepositHistoryStatusEnum {
99 #[must_use]
100 pub fn as_str(&self) -> &'static str {
101 match self {
102 Self::Status0 => "0",
103 Self::Status1 => "1",
104 Self::Status2 => "2",
105 Self::Status6 => "6",
106 Self::Status7 => "7",
107 Self::Status8 => "8",
108 }
109 }
110}
111
112impl std::str::FromStr for DepositHistoryStatusEnum {
113 type Err = Box<dyn std::error::Error + Send + Sync>;
114
115 fn from_str(s: &str) -> Result<Self, Self::Err> {
116 match s {
117 "0" => Ok(Self::Status0),
118 "1" => Ok(Self::Status1),
119 "2" => Ok(Self::Status2),
120 "6" => Ok(Self::Status6),
121 "7" => Ok(Self::Status7),
122 "8" => Ok(Self::Status8),
123 other => Err(format!("invalid DepositHistoryStatusEnum: {}", other).into()),
124 }
125 }
126}
127
128#[derive(Clone, Debug, Builder, Deserialize, Default)]
133#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
134pub struct AllCoinsInformationParams {
135 #[builder(setter(into), default)]
140 #[serde(rename = "recvWindow", default)]
141 pub recv_window: Option<i64>,
142}
143
144impl AllCoinsInformationParams {
145 #[must_use]
148 pub fn builder() -> AllCoinsInformationParamsBuilder {
149 AllCoinsInformationParamsBuilder::default()
150 }
151}
152#[derive(Clone, Debug, Builder, Deserialize)]
157#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
158pub struct DepositAddressParams {
159 #[builder(setter(into))]
163 #[serde(rename = "coin")]
164 pub coin: String,
165 #[builder(setter(into), default)]
170 #[serde(rename = "network", default)]
171 pub network: Option<String>,
172 #[builder(setter(into), default)]
177 #[serde(rename = "amount", default)]
178 pub amount: Option<rust_decimal::Decimal>,
179 #[builder(setter(into), default)]
184 #[serde(rename = "recvWindow", default)]
185 pub recv_window: Option<i64>,
186}
187
188impl DepositAddressParams {
189 #[must_use]
196 pub fn builder(coin: String) -> DepositAddressParamsBuilder {
197 DepositAddressParamsBuilder::default().coin(coin)
198 }
199}
200#[derive(Clone, Debug, Builder, Deserialize, Default)]
205#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
206pub struct DepositHistoryParams {
207 #[builder(setter(into), default)]
211 #[serde(rename = "includeSource", default)]
212 pub include_source: Option<bool>,
213 #[builder(setter(into), default)]
218 #[serde(rename = "coin", default)]
219 pub coin: Option<String>,
220 #[builder(setter(into), default)]
224 #[serde(rename = "status", default)]
225 pub status: Option<DepositHistoryStatusEnum>,
226 #[builder(setter(into), default)]
230 #[serde(rename = "startTime", default)]
231 pub start_time: Option<i64>,
232 #[builder(setter(into), default)]
236 #[serde(rename = "endTime", default)]
237 pub end_time: Option<i64>,
238 #[builder(setter(into), default)]
243 #[serde(rename = "offset", default)]
244 pub offset: Option<i64>,
245 #[builder(setter(into), default)]
250 #[serde(rename = "limit", default)]
251 pub limit: Option<i64>,
252 #[builder(setter(into), default)]
257 #[serde(rename = "recvWindow", default)]
258 pub recv_window: Option<i64>,
259 #[builder(setter(into), default)]
264 #[serde(rename = "txId", default)]
265 pub tx_id: Option<String>,
266}
267
268impl DepositHistoryParams {
269 #[must_use]
272 pub fn builder() -> DepositHistoryParamsBuilder {
273 DepositHistoryParamsBuilder::default()
274 }
275}
276#[derive(Clone, Debug, Builder, Deserialize)]
281#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
282pub struct FetchDepositAddressListWithNetworkParams {
283 #[builder(setter(into))]
287 #[serde(rename = "coin")]
288 pub coin: String,
289 #[builder(setter(into), default)]
293 #[serde(rename = "network", default)]
294 pub network: Option<String>,
295}
296
297impl FetchDepositAddressListWithNetworkParams {
298 #[must_use]
305 pub fn builder(coin: String) -> FetchDepositAddressListWithNetworkParamsBuilder {
306 FetchDepositAddressListWithNetworkParamsBuilder::default().coin(coin)
307 }
308}
309#[derive(Clone, Debug, Builder, Deserialize, Default)]
314#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
315pub struct OneClickArrivalDepositApplyParams {
316 #[builder(setter(into), default)]
320 #[serde(rename = "depositId", default)]
321 pub deposit_id: Option<i64>,
322 #[builder(setter(into), default)]
326 #[serde(rename = "txId", default)]
327 pub tx_id: Option<String>,
328 #[builder(setter(into), default)]
332 #[serde(rename = "subAccountId", default)]
333 pub sub_account_id: Option<String>,
334 #[builder(setter(into), default)]
338 #[serde(rename = "subUserId", default)]
339 pub sub_user_id: Option<i64>,
340}
341
342impl OneClickArrivalDepositApplyParams {
343 #[must_use]
346 pub fn builder() -> OneClickArrivalDepositApplyParamsBuilder {
347 OneClickArrivalDepositApplyParamsBuilder::default()
348 }
349}
350#[derive(Clone, Debug, Builder, Deserialize)]
355#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
356pub struct WithdrawParams {
357 #[builder(setter(into))]
362 #[serde(rename = "coin")]
363 pub coin: String,
364 #[builder(setter(into))]
368 #[serde(rename = "address")]
369 pub address: String,
370 #[builder(setter(into))]
374 #[serde(rename = "amount")]
375 pub amount: rust_decimal::Decimal,
376 #[builder(setter(into), default)]
381 #[serde(rename = "withdrawOrderId", default)]
382 pub withdraw_order_id: Option<String>,
383 #[builder(setter(into), default)]
387 #[serde(rename = "network", default)]
388 pub network: Option<String>,
389 #[builder(setter(into), default)]
393 #[serde(rename = "addressTag", default)]
394 pub address_tag: Option<String>,
395 #[builder(setter(into), default)]
400 #[serde(rename = "transactionFeeFlag", default)]
401 pub transaction_fee_flag: Option<bool>,
402 #[builder(setter(into), default)]
407 #[serde(rename = "name", default)]
408 pub name: Option<String>,
409 #[builder(setter(into), default)]
414 #[serde(rename = "walletType", default)]
415 pub wallet_type: Option<i64>,
416 #[builder(setter(into), default)]
421 #[serde(rename = "recvWindow", default)]
422 pub recv_window: Option<i64>,
423}
424
425impl WithdrawParams {
426 #[must_use]
435 pub fn builder(
436 coin: String,
437 address: String,
438 amount: rust_decimal::Decimal,
439 ) -> WithdrawParamsBuilder {
440 WithdrawParamsBuilder::default()
441 .coin(coin)
442 .address(address)
443 .amount(amount)
444 }
445}
446#[derive(Clone, Debug, Builder, Deserialize, Default)]
451#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
452pub struct WithdrawHistoryParams {
453 #[builder(setter(into), default)]
458 #[serde(rename = "coin", default)]
459 pub coin: Option<String>,
460 #[builder(setter(into), default)]
465 #[serde(rename = "withdrawOrderId", default)]
466 pub withdraw_order_id: Option<String>,
467 #[builder(setter(into), default)]
471 #[serde(rename = "status", default)]
472 pub status: Option<i64>,
473 #[builder(setter(into), default)]
477 #[serde(rename = "offset", default)]
478 pub offset: Option<i64>,
479 #[builder(setter(into), default)]
484 #[serde(rename = "limit", default)]
485 pub limit: Option<i64>,
486 #[builder(setter(into), default)]
490 #[serde(rename = "idList", default)]
491 pub id_list: Option<String>,
492 #[builder(setter(into), default)]
496 #[serde(rename = "startTime", default)]
497 pub start_time: Option<i64>,
498 #[builder(setter(into), default)]
502 #[serde(rename = "endTime", default)]
503 pub end_time: Option<i64>,
504 #[builder(setter(into), default)]
509 #[serde(rename = "recvWindow", default)]
510 pub recv_window: Option<i64>,
511}
512
513impl WithdrawHistoryParams {
514 #[must_use]
517 pub fn builder() -> WithdrawHistoryParamsBuilder {
518 WithdrawHistoryParamsBuilder::default()
519 }
520}
521
522#[async_trait]
523impl CapitalApi for CapitalApiClient {
524 async fn all_coins_information(
525 &self,
526 params: AllCoinsInformationParams,
527 ) -> anyhow::Result<RestApiResponse<Vec<models::AllCoinsInformationResponseInner>>> {
528 let AllCoinsInformationParams { recv_window } = params;
529
530 let mut query_params = BTreeMap::new();
531 let body_params = BTreeMap::new();
532
533 if let Some(rw) = recv_window {
534 query_params.insert("recvWindow".to_string(), json!(rw));
535 }
536
537 send_request::<Vec<models::AllCoinsInformationResponseInner>>(
538 &self.configuration,
539 "/sapi/v1/capital/config/getall",
540 reqwest::Method::GET,
541 query_params,
542 body_params,
543 if HAS_TIME_UNIT {
544 self.configuration.time_unit
545 } else {
546 None
547 },
548 true,
549 )
550 .await
551 }
552
553 async fn deposit_address(
554 &self,
555 params: DepositAddressParams,
556 ) -> anyhow::Result<RestApiResponse<models::DepositAddressResponse>> {
557 let DepositAddressParams {
558 coin,
559 network,
560 amount,
561 recv_window,
562 } = params;
563
564 let mut query_params = BTreeMap::new();
565 let body_params = BTreeMap::new();
566
567 query_params.insert("coin".to_string(), json!(coin));
568
569 if let Some(rw) = network {
570 query_params.insert("network".to_string(), json!(rw));
571 }
572
573 if let Some(rw) = amount {
574 query_params.insert("amount".to_string(), json!(rw));
575 }
576
577 if let Some(rw) = recv_window {
578 query_params.insert("recvWindow".to_string(), json!(rw));
579 }
580
581 send_request::<models::DepositAddressResponse>(
582 &self.configuration,
583 "/sapi/v1/capital/deposit/address",
584 reqwest::Method::GET,
585 query_params,
586 body_params,
587 if HAS_TIME_UNIT {
588 self.configuration.time_unit
589 } else {
590 None
591 },
592 true,
593 )
594 .await
595 }
596
597 async fn deposit_history(
598 &self,
599 params: DepositHistoryParams,
600 ) -> anyhow::Result<RestApiResponse<Vec<models::DepositHistoryResponseInner>>> {
601 let DepositHistoryParams {
602 include_source,
603 coin,
604 status,
605 start_time,
606 end_time,
607 offset,
608 limit,
609 recv_window,
610 tx_id,
611 } = params;
612
613 let mut query_params = BTreeMap::new();
614 let body_params = BTreeMap::new();
615
616 if let Some(rw) = include_source {
617 query_params.insert("includeSource".to_string(), json!(rw));
618 }
619
620 if let Some(rw) = coin {
621 query_params.insert("coin".to_string(), json!(rw));
622 }
623
624 if let Some(rw) = status {
625 query_params.insert("status".to_string(), json!(rw));
626 }
627
628 if let Some(rw) = start_time {
629 query_params.insert("startTime".to_string(), json!(rw));
630 }
631
632 if let Some(rw) = end_time {
633 query_params.insert("endTime".to_string(), json!(rw));
634 }
635
636 if let Some(rw) = offset {
637 query_params.insert("offset".to_string(), json!(rw));
638 }
639
640 if let Some(rw) = limit {
641 query_params.insert("limit".to_string(), json!(rw));
642 }
643
644 if let Some(rw) = recv_window {
645 query_params.insert("recvWindow".to_string(), json!(rw));
646 }
647
648 if let Some(rw) = tx_id {
649 query_params.insert("txId".to_string(), json!(rw));
650 }
651
652 send_request::<Vec<models::DepositHistoryResponseInner>>(
653 &self.configuration,
654 "/sapi/v1/capital/deposit/hisrec",
655 reqwest::Method::GET,
656 query_params,
657 body_params,
658 if HAS_TIME_UNIT {
659 self.configuration.time_unit
660 } else {
661 None
662 },
663 true,
664 )
665 .await
666 }
667
668 async fn fetch_deposit_address_list_with_network(
669 &self,
670 params: FetchDepositAddressListWithNetworkParams,
671 ) -> anyhow::Result<RestApiResponse<Vec<models::FetchDepositAddressListWithNetworkResponseInner>>>
672 {
673 let FetchDepositAddressListWithNetworkParams { coin, network } = params;
674
675 let mut query_params = BTreeMap::new();
676 let body_params = BTreeMap::new();
677
678 query_params.insert("coin".to_string(), json!(coin));
679
680 if let Some(rw) = network {
681 query_params.insert("network".to_string(), json!(rw));
682 }
683
684 send_request::<Vec<models::FetchDepositAddressListWithNetworkResponseInner>>(
685 &self.configuration,
686 "/sapi/v1/capital/deposit/address/list",
687 reqwest::Method::GET,
688 query_params,
689 body_params,
690 if HAS_TIME_UNIT {
691 self.configuration.time_unit
692 } else {
693 None
694 },
695 true,
696 )
697 .await
698 }
699
700 async fn fetch_withdraw_address_list(
701 &self,
702 ) -> anyhow::Result<RestApiResponse<Vec<models::FetchWithdrawAddressListResponseInner>>> {
703 let query_params = BTreeMap::new();
704 let body_params = BTreeMap::new();
705
706 send_request::<Vec<models::FetchWithdrawAddressListResponseInner>>(
707 &self.configuration,
708 "/sapi/v1/capital/withdraw/address/list",
709 reqwest::Method::GET,
710 query_params,
711 body_params,
712 if HAS_TIME_UNIT {
713 self.configuration.time_unit
714 } else {
715 None
716 },
717 true,
718 )
719 .await
720 }
721
722 async fn fetch_withdraw_quota(
723 &self,
724 ) -> anyhow::Result<RestApiResponse<models::FetchWithdrawQuotaResponse>> {
725 let query_params = BTreeMap::new();
726 let body_params = BTreeMap::new();
727
728 send_request::<models::FetchWithdrawQuotaResponse>(
729 &self.configuration,
730 "/sapi/v1/capital/withdraw/quota",
731 reqwest::Method::GET,
732 query_params,
733 body_params,
734 if HAS_TIME_UNIT {
735 self.configuration.time_unit
736 } else {
737 None
738 },
739 true,
740 )
741 .await
742 }
743
744 async fn one_click_arrival_deposit_apply(
745 &self,
746 params: OneClickArrivalDepositApplyParams,
747 ) -> anyhow::Result<RestApiResponse<models::OneClickArrivalDepositApplyResponse>> {
748 let OneClickArrivalDepositApplyParams {
749 deposit_id,
750 tx_id,
751 sub_account_id,
752 sub_user_id,
753 } = params;
754
755 let mut query_params = BTreeMap::new();
756 let body_params = BTreeMap::new();
757
758 if let Some(rw) = deposit_id {
759 query_params.insert("depositId".to_string(), json!(rw));
760 }
761
762 if let Some(rw) = tx_id {
763 query_params.insert("txId".to_string(), json!(rw));
764 }
765
766 if let Some(rw) = sub_account_id {
767 query_params.insert("subAccountId".to_string(), json!(rw));
768 }
769
770 if let Some(rw) = sub_user_id {
771 query_params.insert("subUserId".to_string(), json!(rw));
772 }
773
774 send_request::<models::OneClickArrivalDepositApplyResponse>(
775 &self.configuration,
776 "/sapi/v1/capital/deposit/credit-apply",
777 reqwest::Method::POST,
778 query_params,
779 body_params,
780 if HAS_TIME_UNIT {
781 self.configuration.time_unit
782 } else {
783 None
784 },
785 true,
786 )
787 .await
788 }
789
790 async fn withdraw(
791 &self,
792 params: WithdrawParams,
793 ) -> anyhow::Result<RestApiResponse<models::WithdrawResponse>> {
794 let WithdrawParams {
795 coin,
796 address,
797 amount,
798 withdraw_order_id,
799 network,
800 address_tag,
801 transaction_fee_flag,
802 name,
803 wallet_type,
804 recv_window,
805 } = params;
806
807 let mut query_params = BTreeMap::new();
808 let body_params = BTreeMap::new();
809
810 query_params.insert("coin".to_string(), json!(coin));
811
812 if let Some(rw) = withdraw_order_id {
813 query_params.insert("withdrawOrderId".to_string(), json!(rw));
814 }
815
816 if let Some(rw) = network {
817 query_params.insert("network".to_string(), json!(rw));
818 }
819
820 query_params.insert("address".to_string(), json!(address));
821
822 if let Some(rw) = address_tag {
823 query_params.insert("addressTag".to_string(), json!(rw));
824 }
825
826 query_params.insert("amount".to_string(), json!(amount));
827
828 if let Some(rw) = transaction_fee_flag {
829 query_params.insert("transactionFeeFlag".to_string(), json!(rw));
830 }
831
832 if let Some(rw) = name {
833 query_params.insert("name".to_string(), json!(rw));
834 }
835
836 if let Some(rw) = wallet_type {
837 query_params.insert("walletType".to_string(), json!(rw));
838 }
839
840 if let Some(rw) = recv_window {
841 query_params.insert("recvWindow".to_string(), json!(rw));
842 }
843
844 send_request::<models::WithdrawResponse>(
845 &self.configuration,
846 "/sapi/v1/capital/withdraw/apply",
847 reqwest::Method::POST,
848 query_params,
849 body_params,
850 if HAS_TIME_UNIT {
851 self.configuration.time_unit
852 } else {
853 None
854 },
855 true,
856 )
857 .await
858 }
859
860 async fn withdraw_history(
861 &self,
862 params: WithdrawHistoryParams,
863 ) -> anyhow::Result<RestApiResponse<Vec<models::WithdrawHistoryResponseInner>>> {
864 let WithdrawHistoryParams {
865 coin,
866 withdraw_order_id,
867 status,
868 offset,
869 limit,
870 id_list,
871 start_time,
872 end_time,
873 recv_window,
874 } = params;
875
876 let mut query_params = BTreeMap::new();
877 let body_params = BTreeMap::new();
878
879 if let Some(rw) = coin {
880 query_params.insert("coin".to_string(), json!(rw));
881 }
882
883 if let Some(rw) = withdraw_order_id {
884 query_params.insert("withdrawOrderId".to_string(), json!(rw));
885 }
886
887 if let Some(rw) = status {
888 query_params.insert("status".to_string(), json!(rw));
889 }
890
891 if let Some(rw) = offset {
892 query_params.insert("offset".to_string(), json!(rw));
893 }
894
895 if let Some(rw) = limit {
896 query_params.insert("limit".to_string(), json!(rw));
897 }
898
899 if let Some(rw) = id_list {
900 query_params.insert("idList".to_string(), json!(rw));
901 }
902
903 if let Some(rw) = start_time {
904 query_params.insert("startTime".to_string(), json!(rw));
905 }
906
907 if let Some(rw) = end_time {
908 query_params.insert("endTime".to_string(), json!(rw));
909 }
910
911 if let Some(rw) = recv_window {
912 query_params.insert("recvWindow".to_string(), json!(rw));
913 }
914
915 send_request::<Vec<models::WithdrawHistoryResponseInner>>(
916 &self.configuration,
917 "/sapi/v1/capital/withdraw/history",
918 reqwest::Method::GET,
919 query_params,
920 body_params,
921 if HAS_TIME_UNIT {
922 self.configuration.time_unit
923 } else {
924 None
925 },
926 true,
927 )
928 .await
929 }
930}
931
932#[cfg(all(test, feature = "wallet"))]
933mod tests {
934 use super::*;
935 use crate::TOKIO_SHARED_RT;
936 use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
937 use async_trait::async_trait;
938 use std::collections::HashMap;
939
940 struct DummyRestApiResponse<T> {
941 inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
942 status: u16,
943 headers: HashMap<String, String>,
944 rate_limits: Option<Vec<RestApiRateLimit>>,
945 }
946
947 impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
948 fn from(dummy: DummyRestApiResponse<T>) -> Self {
949 Self {
950 data_fn: dummy.inner,
951 status: dummy.status,
952 headers: dummy.headers,
953 rate_limits: dummy.rate_limits,
954 }
955 }
956 }
957
958 struct MockCapitalApiClient {
959 force_error: bool,
960 }
961
962 #[async_trait]
963 impl CapitalApi for MockCapitalApiClient {
964 async fn all_coins_information(
965 &self,
966 _params: AllCoinsInformationParams,
967 ) -> anyhow::Result<RestApiResponse<Vec<models::AllCoinsInformationResponseInner>>>
968 {
969 if self.force_error {
970 return Err(ConnectorError::ConnectorClientError {
971 msg: "ResponseError".to_string(),
972 code: None,
973 }
974 .into());
975 }
976
977 let resp_json: Value = serde_json::from_str(r#"[{"coin":"1MBABYDOGE","depositAllEnable":true,"withdrawAllEnable":true,"name":"1M x BABYDOGE","free":"34941.1","locked":"0","freeze":"0","withdrawing":"0","ipoing":"0","ipoable":"0","storage":"0","isLegalMoney":false,"trading":true,"networkList":[{"network":"BSC","coin":"1MBABYDOGE","withdrawIntegerMultiple":"0.01","isDefault":false,"depositEnable":true,"withdrawEnable":true,"depositDesc":"","withdrawDesc":"","specialTips":"","specialWithdrawTips":"","name":"BNB Smart Chain (BEP20)","resetAddressStatus":false,"addressRegex":"^(0x)[0-9A-Fa-f]{40}$","memoRegex":"","withdrawFee":"10","withdrawMin":"20","withdrawMax":"9999999999","withdrawInternalMin":"0.01","depositDust":"0.01","minConfirm":5,"unLockConfirm":0,"sameAddress":false,"withdrawTag":false,"estimatedArrivalTime":1,"busy":false,"contractAddressUrl":"https://bscscan.com/token/","contractAddress":"0xc748673057861a797275cd8a068abb95a902e8de","denomination":1000000}]}]"#).unwrap_or_else(|_| serde_json::json!({}));
978 let dummy_response: Vec<models::AllCoinsInformationResponseInner> =
979 serde_json::from_value(resp_json.clone())
980 .expect("should parse into Vec<models::AllCoinsInformationResponseInner>");
981
982 let dummy = DummyRestApiResponse {
983 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
984 status: 200,
985 headers: HashMap::new(),
986 rate_limits: None,
987 };
988
989 Ok(dummy.into())
990 }
991
992 async fn deposit_address(
993 &self,
994 _params: DepositAddressParams,
995 ) -> anyhow::Result<RestApiResponse<models::DepositAddressResponse>> {
996 if self.force_error {
997 return Err(ConnectorError::ConnectorClientError {
998 msg: "ResponseError".to_string(),
999 code: None,
1000 }
1001 .into());
1002 }
1003
1004 let resp_json: Value = serde_json::from_str(r#"{"address":"1HPn8Rx2y6nNSfagQBKy27GB99Vbzg89wv","coin":"BTC","tag":"","url":"https://btc.com/1HPn8Rx2y6nNSfagQBKy27GB99Vbzg89wv"}"#).unwrap_or_else(|_| serde_json::json!({}));
1005 let dummy_response: models::DepositAddressResponse =
1006 serde_json::from_value(resp_json.clone())
1007 .expect("should parse into models::DepositAddressResponse");
1008
1009 let dummy = DummyRestApiResponse {
1010 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1011 status: 200,
1012 headers: HashMap::new(),
1013 rate_limits: None,
1014 };
1015
1016 Ok(dummy.into())
1017 }
1018
1019 async fn deposit_history(
1020 &self,
1021 _params: DepositHistoryParams,
1022 ) -> anyhow::Result<RestApiResponse<Vec<models::DepositHistoryResponseInner>>> {
1023 if self.force_error {
1024 return Err(ConnectorError::ConnectorClientError {
1025 msg: "ResponseError".to_string(),
1026 code: None,
1027 }
1028 .into());
1029 }
1030
1031 let resp_json: Value = serde_json::from_str(r#"[{"id":"769800519366885376","amount":"0.001","coin":"BNB","network":"BNB","status":1,"address":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","addressTag":"101764890","txId":"98A3EA560C6B3336D348B6C83F0F95ECE4F1F5919E94BD006E5BF3BF264FACFC","insertTime":1661493146000,"completeTime":1661493146000,"transferType":0,"confirmTimes":"1/1","unlockConfirm":0,"walletType":0,"travelRuleStatus":0}]"#).unwrap_or_else(|_| serde_json::json!({}));
1032 let dummy_response: Vec<models::DepositHistoryResponseInner> =
1033 serde_json::from_value(resp_json.clone())
1034 .expect("should parse into Vec<models::DepositHistoryResponseInner>");
1035
1036 let dummy = DummyRestApiResponse {
1037 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1038 status: 200,
1039 headers: HashMap::new(),
1040 rate_limits: None,
1041 };
1042
1043 Ok(dummy.into())
1044 }
1045
1046 async fn fetch_deposit_address_list_with_network(
1047 &self,
1048 _params: FetchDepositAddressListWithNetworkParams,
1049 ) -> anyhow::Result<
1050 RestApiResponse<Vec<models::FetchDepositAddressListWithNetworkResponseInner>>,
1051 > {
1052 if self.force_error {
1053 return Err(ConnectorError::ConnectorClientError {
1054 msg: "ResponseError".to_string(),
1055 code: None,
1056 }
1057 .into());
1058 }
1059
1060 let resp_json: Value = serde_json::from_str(r#"[{"coin":"ETH","address":"0xD316E95Fd9E8E237Cb11f8200Babbc5D8D177BA4","tag":"","isDefault":0}]"#).unwrap_or_else(|_| serde_json::json!({}));
1061 let dummy_response : Vec<models::FetchDepositAddressListWithNetworkResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::FetchDepositAddressListWithNetworkResponseInner>");
1062
1063 let dummy = DummyRestApiResponse {
1064 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1065 status: 200,
1066 headers: HashMap::new(),
1067 rate_limits: None,
1068 };
1069
1070 Ok(dummy.into())
1071 }
1072
1073 async fn fetch_withdraw_address_list(
1074 &self,
1075 ) -> anyhow::Result<RestApiResponse<Vec<models::FetchWithdrawAddressListResponseInner>>>
1076 {
1077 if self.force_error {
1078 return Err(ConnectorError::ConnectorClientError {
1079 msg: "ResponseError".to_string(),
1080 code: None,
1081 }
1082 .into());
1083 }
1084
1085 let resp_json: Value = serde_json::from_str(r#"[{"address":"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","addressTag":"","coin":"BTC","name":"Satoshi","network":"BTC","origin":"bla","originType":"others","whiteStatus":true}]"#).unwrap_or_else(|_| serde_json::json!({}));
1086 let dummy_response: Vec<models::FetchWithdrawAddressListResponseInner> =
1087 serde_json::from_value(resp_json.clone())
1088 .expect("should parse into Vec<models::FetchWithdrawAddressListResponseInner>");
1089
1090 let dummy = DummyRestApiResponse {
1091 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1092 status: 200,
1093 headers: HashMap::new(),
1094 rate_limits: None,
1095 };
1096
1097 Ok(dummy.into())
1098 }
1099
1100 async fn fetch_withdraw_quota(
1101 &self,
1102 ) -> anyhow::Result<RestApiResponse<models::FetchWithdrawQuotaResponse>> {
1103 if self.force_error {
1104 return Err(ConnectorError::ConnectorClientError {
1105 msg: "ResponseError".to_string(),
1106 code: None,
1107 }
1108 .into());
1109 }
1110
1111 let resp_json: Value =
1112 serde_json::from_str(r#"{"wdQuota":"10000","usedWdQuota":"1000"}"#)
1113 .unwrap_or_else(|_| serde_json::json!({}));
1114 let dummy_response: models::FetchWithdrawQuotaResponse =
1115 serde_json::from_value(resp_json.clone())
1116 .expect("should parse into models::FetchWithdrawQuotaResponse");
1117
1118 let dummy = DummyRestApiResponse {
1119 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1120 status: 200,
1121 headers: HashMap::new(),
1122 rate_limits: None,
1123 };
1124
1125 Ok(dummy.into())
1126 }
1127
1128 async fn one_click_arrival_deposit_apply(
1129 &self,
1130 _params: OneClickArrivalDepositApplyParams,
1131 ) -> anyhow::Result<RestApiResponse<models::OneClickArrivalDepositApplyResponse>> {
1132 if self.force_error {
1133 return Err(ConnectorError::ConnectorClientError {
1134 msg: "ResponseError".to_string(),
1135 code: None,
1136 }
1137 .into());
1138 }
1139
1140 let resp_json: Value = serde_json::from_str(
1141 r#"{"code":"000000","message":"success","data":true,"success":true}"#,
1142 )
1143 .unwrap_or_else(|_| serde_json::json!({}));
1144 let dummy_response: models::OneClickArrivalDepositApplyResponse =
1145 serde_json::from_value(resp_json.clone())
1146 .expect("should parse into models::OneClickArrivalDepositApplyResponse");
1147
1148 let dummy = DummyRestApiResponse {
1149 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1150 status: 200,
1151 headers: HashMap::new(),
1152 rate_limits: None,
1153 };
1154
1155 Ok(dummy.into())
1156 }
1157
1158 async fn withdraw(
1159 &self,
1160 _params: WithdrawParams,
1161 ) -> anyhow::Result<RestApiResponse<models::WithdrawResponse>> {
1162 if self.force_error {
1163 return Err(ConnectorError::ConnectorClientError {
1164 msg: "ResponseError".to_string(),
1165 code: None,
1166 }
1167 .into());
1168 }
1169
1170 let resp_json: Value =
1171 serde_json::from_str(r#"{"id":"7213fea8e94b4a5593d507237e5a555b"}"#)
1172 .unwrap_or_else(|_| serde_json::json!({}));
1173 let dummy_response: models::WithdrawResponse =
1174 serde_json::from_value(resp_json.clone())
1175 .expect("should parse into models::WithdrawResponse");
1176
1177 let dummy = DummyRestApiResponse {
1178 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1179 status: 200,
1180 headers: HashMap::new(),
1181 rate_limits: None,
1182 };
1183
1184 Ok(dummy.into())
1185 }
1186
1187 async fn withdraw_history(
1188 &self,
1189 _params: WithdrawHistoryParams,
1190 ) -> anyhow::Result<RestApiResponse<Vec<models::WithdrawHistoryResponseInner>>> {
1191 if self.force_error {
1192 return Err(ConnectorError::ConnectorClientError {
1193 msg: "ResponseError".to_string(),
1194 code: None,
1195 }
1196 .into());
1197 }
1198
1199 let resp_json: Value = serde_json::from_str(r#"[{"id":"b6ae22b3aa844210a7041aee7589627c","amount":"8.91000000","transactionFee":"0.004","coin":"USDT","status":6,"address":"0x94df8b352de7f46f64b01d3666bf6e936e44ce60","txId":"0xb5ef8c13b968a406cc62a93a8bd80f9e9a906ef1b3fcf20a2e48573c17659268","applyTime":"2019-10-12 11:12:02","network":"ETH","transferType":0,"withdrawOrderId":"WITHDRAWtest123","info":"The address is not valid. Please confirm with the recipient","confirmNo":3,"walletType":1,"txKey":"","completeTime":"2023-03-23 16:52:41"}]"#).unwrap_or_else(|_| serde_json::json!({}));
1200 let dummy_response: Vec<models::WithdrawHistoryResponseInner> =
1201 serde_json::from_value(resp_json.clone())
1202 .expect("should parse into Vec<models::WithdrawHistoryResponseInner>");
1203
1204 let dummy = DummyRestApiResponse {
1205 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1206 status: 200,
1207 headers: HashMap::new(),
1208 rate_limits: None,
1209 };
1210
1211 Ok(dummy.into())
1212 }
1213 }
1214
1215 #[test]
1216 fn all_coins_information_required_params_success() {
1217 TOKIO_SHARED_RT.block_on(async {
1218 let client = MockCapitalApiClient { force_error: false };
1219
1220 let params = AllCoinsInformationParams::builder().build().unwrap();
1221
1222 let resp_json: Value = serde_json::from_str(r#"[{"coin":"1MBABYDOGE","depositAllEnable":true,"withdrawAllEnable":true,"name":"1M x BABYDOGE","free":"34941.1","locked":"0","freeze":"0","withdrawing":"0","ipoing":"0","ipoable":"0","storage":"0","isLegalMoney":false,"trading":true,"networkList":[{"network":"BSC","coin":"1MBABYDOGE","withdrawIntegerMultiple":"0.01","isDefault":false,"depositEnable":true,"withdrawEnable":true,"depositDesc":"","withdrawDesc":"","specialTips":"","specialWithdrawTips":"","name":"BNB Smart Chain (BEP20)","resetAddressStatus":false,"addressRegex":"^(0x)[0-9A-Fa-f]{40}$","memoRegex":"","withdrawFee":"10","withdrawMin":"20","withdrawMax":"9999999999","withdrawInternalMin":"0.01","depositDust":"0.01","minConfirm":5,"unLockConfirm":0,"sameAddress":false,"withdrawTag":false,"estimatedArrivalTime":1,"busy":false,"contractAddressUrl":"https://bscscan.com/token/","contractAddress":"0xc748673057861a797275cd8a068abb95a902e8de","denomination":1000000}]}]"#).unwrap_or_else(|_| serde_json::json!({}));
1223 let expected_response : Vec<models::AllCoinsInformationResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AllCoinsInformationResponseInner>");
1224
1225 let resp = client.all_coins_information(params).await.expect("Expected a response");
1226 let data_future = resp.data();
1227 let actual_response = data_future.await.unwrap();
1228 assert_eq!(actual_response, expected_response);
1229 });
1230 }
1231
1232 #[test]
1233 fn all_coins_information_optional_params_success() {
1234 TOKIO_SHARED_RT.block_on(async {
1235 let client = MockCapitalApiClient { force_error: false };
1236
1237 let params = AllCoinsInformationParams::builder().recv_window(5000).build().unwrap();
1238
1239 let resp_json: Value = serde_json::from_str(r#"[{"coin":"1MBABYDOGE","depositAllEnable":true,"withdrawAllEnable":true,"name":"1M x BABYDOGE","free":"34941.1","locked":"0","freeze":"0","withdrawing":"0","ipoing":"0","ipoable":"0","storage":"0","isLegalMoney":false,"trading":true,"networkList":[{"network":"BSC","coin":"1MBABYDOGE","withdrawIntegerMultiple":"0.01","isDefault":false,"depositEnable":true,"withdrawEnable":true,"depositDesc":"","withdrawDesc":"","specialTips":"","specialWithdrawTips":"","name":"BNB Smart Chain (BEP20)","resetAddressStatus":false,"addressRegex":"^(0x)[0-9A-Fa-f]{40}$","memoRegex":"","withdrawFee":"10","withdrawMin":"20","withdrawMax":"9999999999","withdrawInternalMin":"0.01","depositDust":"0.01","minConfirm":5,"unLockConfirm":0,"sameAddress":false,"withdrawTag":false,"estimatedArrivalTime":1,"busy":false,"contractAddressUrl":"https://bscscan.com/token/","contractAddress":"0xc748673057861a797275cd8a068abb95a902e8de","denomination":1000000}]}]"#).unwrap_or_else(|_| serde_json::json!({}));
1240 let expected_response : Vec<models::AllCoinsInformationResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AllCoinsInformationResponseInner>");
1241
1242 let resp = client.all_coins_information(params).await.expect("Expected a response");
1243 let data_future = resp.data();
1244 let actual_response = data_future.await.unwrap();
1245 assert_eq!(actual_response, expected_response);
1246 });
1247 }
1248
1249 #[test]
1250 fn all_coins_information_response_error() {
1251 TOKIO_SHARED_RT.block_on(async {
1252 let client = MockCapitalApiClient { force_error: true };
1253
1254 let params = AllCoinsInformationParams::builder().build().unwrap();
1255
1256 match client.all_coins_information(params).await {
1257 Ok(_) => panic!("Expected an error"),
1258 Err(err) => {
1259 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1260 }
1261 }
1262 });
1263 }
1264
1265 #[test]
1266 fn deposit_address_required_params_success() {
1267 TOKIO_SHARED_RT.block_on(async {
1268 let client = MockCapitalApiClient { force_error: false };
1269
1270 let params = DepositAddressParams::builder("BTC".to_string(),).build().unwrap();
1271
1272 let resp_json: Value = serde_json::from_str(r#"{"address":"1HPn8Rx2y6nNSfagQBKy27GB99Vbzg89wv","coin":"BTC","tag":"","url":"https://btc.com/1HPn8Rx2y6nNSfagQBKy27GB99Vbzg89wv"}"#).unwrap_or_else(|_| serde_json::json!({}));
1273 let expected_response : models::DepositAddressResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DepositAddressResponse");
1274
1275 let resp = client.deposit_address(params).await.expect("Expected a response");
1276 let data_future = resp.data();
1277 let actual_response = data_future.await.unwrap();
1278 assert_eq!(actual_response, expected_response);
1279 });
1280 }
1281
1282 #[test]
1283 fn deposit_address_optional_params_success() {
1284 TOKIO_SHARED_RT.block_on(async {
1285 let client = MockCapitalApiClient { force_error: false };
1286
1287 let params = DepositAddressParams::builder("BTC".to_string(),).network("network_example".to_string()).amount(dec!(1.0)).recv_window(5000).build().unwrap();
1288
1289 let resp_json: Value = serde_json::from_str(r#"{"address":"1HPn8Rx2y6nNSfagQBKy27GB99Vbzg89wv","coin":"BTC","tag":"","url":"https://btc.com/1HPn8Rx2y6nNSfagQBKy27GB99Vbzg89wv"}"#).unwrap_or_else(|_| serde_json::json!({}));
1290 let expected_response : models::DepositAddressResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DepositAddressResponse");
1291
1292 let resp = client.deposit_address(params).await.expect("Expected a response");
1293 let data_future = resp.data();
1294 let actual_response = data_future.await.unwrap();
1295 assert_eq!(actual_response, expected_response);
1296 });
1297 }
1298
1299 #[test]
1300 fn deposit_address_response_error() {
1301 TOKIO_SHARED_RT.block_on(async {
1302 let client = MockCapitalApiClient { force_error: true };
1303
1304 let params = DepositAddressParams::builder("BTC".to_string())
1305 .build()
1306 .unwrap();
1307
1308 match client.deposit_address(params).await {
1309 Ok(_) => panic!("Expected an error"),
1310 Err(err) => {
1311 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1312 }
1313 }
1314 });
1315 }
1316
1317 #[test]
1318 fn deposit_history_required_params_success() {
1319 TOKIO_SHARED_RT.block_on(async {
1320 let client = MockCapitalApiClient { force_error: false };
1321
1322 let params = DepositHistoryParams::builder().build().unwrap();
1323
1324 let resp_json: Value = serde_json::from_str(r#"[{"id":"769800519366885376","amount":"0.001","coin":"BNB","network":"BNB","status":1,"address":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","addressTag":"101764890","txId":"98A3EA560C6B3336D348B6C83F0F95ECE4F1F5919E94BD006E5BF3BF264FACFC","insertTime":1661493146000,"completeTime":1661493146000,"transferType":0,"confirmTimes":"1/1","unlockConfirm":0,"walletType":0,"travelRuleStatus":0}]"#).unwrap_or_else(|_| serde_json::json!({}));
1325 let expected_response : Vec<models::DepositHistoryResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::DepositHistoryResponseInner>");
1326
1327 let resp = client.deposit_history(params).await.expect("Expected a response");
1328 let data_future = resp.data();
1329 let actual_response = data_future.await.unwrap();
1330 assert_eq!(actual_response, expected_response);
1331 });
1332 }
1333
1334 #[test]
1335 fn deposit_history_optional_params_success() {
1336 TOKIO_SHARED_RT.block_on(async {
1337 let client = MockCapitalApiClient { force_error: false };
1338
1339 let params = DepositHistoryParams::builder().include_source(false).coin("BTC".to_string()).status(DepositHistoryStatusEnum::Status0).start_time(1623319461670).end_time(1641782889000).offset(0).limit(1000).recv_window(5000).tx_id("1".to_string()).build().unwrap();
1340
1341 let resp_json: Value = serde_json::from_str(r#"[{"id":"769800519366885376","amount":"0.001","coin":"BNB","network":"BNB","status":1,"address":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","addressTag":"101764890","txId":"98A3EA560C6B3336D348B6C83F0F95ECE4F1F5919E94BD006E5BF3BF264FACFC","insertTime":1661493146000,"completeTime":1661493146000,"transferType":0,"confirmTimes":"1/1","unlockConfirm":0,"walletType":0,"travelRuleStatus":0}]"#).unwrap_or_else(|_| serde_json::json!({}));
1342 let expected_response : Vec<models::DepositHistoryResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::DepositHistoryResponseInner>");
1343
1344 let resp = client.deposit_history(params).await.expect("Expected a response");
1345 let data_future = resp.data();
1346 let actual_response = data_future.await.unwrap();
1347 assert_eq!(actual_response, expected_response);
1348 });
1349 }
1350
1351 #[test]
1352 fn deposit_history_response_error() {
1353 TOKIO_SHARED_RT.block_on(async {
1354 let client = MockCapitalApiClient { force_error: true };
1355
1356 let params = DepositHistoryParams::builder().build().unwrap();
1357
1358 match client.deposit_history(params).await {
1359 Ok(_) => panic!("Expected an error"),
1360 Err(err) => {
1361 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1362 }
1363 }
1364 });
1365 }
1366
1367 #[test]
1368 fn fetch_deposit_address_list_with_network_required_params_success() {
1369 TOKIO_SHARED_RT.block_on(async {
1370 let client = MockCapitalApiClient { force_error: false };
1371
1372 let params = FetchDepositAddressListWithNetworkParams::builder("BTC".to_string(),).build().unwrap();
1373
1374 let resp_json: Value = serde_json::from_str(r#"[{"coin":"ETH","address":"0xD316E95Fd9E8E237Cb11f8200Babbc5D8D177BA4","tag":"","isDefault":0}]"#).unwrap_or_else(|_| serde_json::json!({}));
1375 let expected_response : Vec<models::FetchDepositAddressListWithNetworkResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::FetchDepositAddressListWithNetworkResponseInner>");
1376
1377 let resp = client.fetch_deposit_address_list_with_network(params).await.expect("Expected a response");
1378 let data_future = resp.data();
1379 let actual_response = data_future.await.unwrap();
1380 assert_eq!(actual_response, expected_response);
1381 });
1382 }
1383
1384 #[test]
1385 fn fetch_deposit_address_list_with_network_optional_params_success() {
1386 TOKIO_SHARED_RT.block_on(async {
1387 let client = MockCapitalApiClient { force_error: false };
1388
1389 let params = FetchDepositAddressListWithNetworkParams::builder("BTC".to_string(),).network("network_example".to_string()).build().unwrap();
1390
1391 let resp_json: Value = serde_json::from_str(r#"[{"coin":"ETH","address":"0xD316E95Fd9E8E237Cb11f8200Babbc5D8D177BA4","tag":"","isDefault":0}]"#).unwrap_or_else(|_| serde_json::json!({}));
1392 let expected_response : Vec<models::FetchDepositAddressListWithNetworkResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::FetchDepositAddressListWithNetworkResponseInner>");
1393
1394 let resp = client.fetch_deposit_address_list_with_network(params).await.expect("Expected a response");
1395 let data_future = resp.data();
1396 let actual_response = data_future.await.unwrap();
1397 assert_eq!(actual_response, expected_response);
1398 });
1399 }
1400
1401 #[test]
1402 fn fetch_deposit_address_list_with_network_response_error() {
1403 TOKIO_SHARED_RT.block_on(async {
1404 let client = MockCapitalApiClient { force_error: true };
1405
1406 let params = FetchDepositAddressListWithNetworkParams::builder("BTC".to_string())
1407 .build()
1408 .unwrap();
1409
1410 match client.fetch_deposit_address_list_with_network(params).await {
1411 Ok(_) => panic!("Expected an error"),
1412 Err(err) => {
1413 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1414 }
1415 }
1416 });
1417 }
1418
1419 #[test]
1420 fn fetch_withdraw_address_list_required_params_success() {
1421 TOKIO_SHARED_RT.block_on(async {
1422 let client = MockCapitalApiClient { force_error: false };
1423
1424
1425 let resp_json: Value = serde_json::from_str(r#"[{"address":"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","addressTag":"","coin":"BTC","name":"Satoshi","network":"BTC","origin":"bla","originType":"others","whiteStatus":true}]"#).unwrap_or_else(|_| serde_json::json!({}));
1426 let expected_response : Vec<models::FetchWithdrawAddressListResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::FetchWithdrawAddressListResponseInner>");
1427
1428 let resp = client.fetch_withdraw_address_list().await.expect("Expected a response");
1429 let data_future = resp.data();
1430 let actual_response = data_future.await.unwrap();
1431 assert_eq!(actual_response, expected_response);
1432 });
1433 }
1434
1435 #[test]
1436 fn fetch_withdraw_address_list_optional_params_success() {
1437 TOKIO_SHARED_RT.block_on(async {
1438 let client = MockCapitalApiClient { force_error: false };
1439
1440
1441 let resp_json: Value = serde_json::from_str(r#"[{"address":"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","addressTag":"","coin":"BTC","name":"Satoshi","network":"BTC","origin":"bla","originType":"others","whiteStatus":true}]"#).unwrap_or_else(|_| serde_json::json!({}));
1442 let expected_response : Vec<models::FetchWithdrawAddressListResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::FetchWithdrawAddressListResponseInner>");
1443
1444 let resp = client.fetch_withdraw_address_list().await.expect("Expected a response");
1445 let data_future = resp.data();
1446 let actual_response = data_future.await.unwrap();
1447 assert_eq!(actual_response, expected_response);
1448 });
1449 }
1450
1451 #[test]
1452 fn fetch_withdraw_address_list_response_error() {
1453 TOKIO_SHARED_RT.block_on(async {
1454 let client = MockCapitalApiClient { force_error: true };
1455
1456 match client.fetch_withdraw_address_list().await {
1457 Ok(_) => panic!("Expected an error"),
1458 Err(err) => {
1459 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1460 }
1461 }
1462 });
1463 }
1464
1465 #[test]
1466 fn fetch_withdraw_quota_required_params_success() {
1467 TOKIO_SHARED_RT.block_on(async {
1468 let client = MockCapitalApiClient { force_error: false };
1469
1470 let resp_json: Value =
1471 serde_json::from_str(r#"{"wdQuota":"10000","usedWdQuota":"1000"}"#)
1472 .unwrap_or_else(|_| serde_json::json!({}));
1473 let expected_response: models::FetchWithdrawQuotaResponse =
1474 serde_json::from_value(resp_json.clone())
1475 .expect("should parse into models::FetchWithdrawQuotaResponse");
1476
1477 let resp = client
1478 .fetch_withdraw_quota()
1479 .await
1480 .expect("Expected a response");
1481 let data_future = resp.data();
1482 let actual_response = data_future.await.unwrap();
1483 assert_eq!(actual_response, expected_response);
1484 });
1485 }
1486
1487 #[test]
1488 fn fetch_withdraw_quota_optional_params_success() {
1489 TOKIO_SHARED_RT.block_on(async {
1490 let client = MockCapitalApiClient { force_error: false };
1491
1492 let resp_json: Value =
1493 serde_json::from_str(r#"{"wdQuota":"10000","usedWdQuota":"1000"}"#)
1494 .unwrap_or_else(|_| serde_json::json!({}));
1495 let expected_response: models::FetchWithdrawQuotaResponse =
1496 serde_json::from_value(resp_json.clone())
1497 .expect("should parse into models::FetchWithdrawQuotaResponse");
1498
1499 let resp = client
1500 .fetch_withdraw_quota()
1501 .await
1502 .expect("Expected a response");
1503 let data_future = resp.data();
1504 let actual_response = data_future.await.unwrap();
1505 assert_eq!(actual_response, expected_response);
1506 });
1507 }
1508
1509 #[test]
1510 fn fetch_withdraw_quota_response_error() {
1511 TOKIO_SHARED_RT.block_on(async {
1512 let client = MockCapitalApiClient { force_error: true };
1513
1514 match client.fetch_withdraw_quota().await {
1515 Ok(_) => panic!("Expected an error"),
1516 Err(err) => {
1517 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1518 }
1519 }
1520 });
1521 }
1522
1523 #[test]
1524 fn one_click_arrival_deposit_apply_required_params_success() {
1525 TOKIO_SHARED_RT.block_on(async {
1526 let client = MockCapitalApiClient { force_error: false };
1527
1528 let params = OneClickArrivalDepositApplyParams::builder()
1529 .build()
1530 .unwrap();
1531
1532 let resp_json: Value = serde_json::from_str(
1533 r#"{"code":"000000","message":"success","data":true,"success":true}"#,
1534 )
1535 .unwrap_or_else(|_| serde_json::json!({}));
1536 let expected_response: models::OneClickArrivalDepositApplyResponse =
1537 serde_json::from_value(resp_json.clone())
1538 .expect("should parse into models::OneClickArrivalDepositApplyResponse");
1539
1540 let resp = client
1541 .one_click_arrival_deposit_apply(params)
1542 .await
1543 .expect("Expected a response");
1544 let data_future = resp.data();
1545 let actual_response = data_future.await.unwrap();
1546 assert_eq!(actual_response, expected_response);
1547 });
1548 }
1549
1550 #[test]
1551 fn one_click_arrival_deposit_apply_optional_params_success() {
1552 TOKIO_SHARED_RT.block_on(async {
1553 let client = MockCapitalApiClient { force_error: false };
1554
1555 let params = OneClickArrivalDepositApplyParams::builder()
1556 .deposit_id(1)
1557 .tx_id("1".to_string())
1558 .sub_account_id("1".to_string())
1559 .sub_user_id(1)
1560 .build()
1561 .unwrap();
1562
1563 let resp_json: Value = serde_json::from_str(
1564 r#"{"code":"000000","message":"success","data":true,"success":true}"#,
1565 )
1566 .unwrap_or_else(|_| serde_json::json!({}));
1567 let expected_response: models::OneClickArrivalDepositApplyResponse =
1568 serde_json::from_value(resp_json.clone())
1569 .expect("should parse into models::OneClickArrivalDepositApplyResponse");
1570
1571 let resp = client
1572 .one_click_arrival_deposit_apply(params)
1573 .await
1574 .expect("Expected a response");
1575 let data_future = resp.data();
1576 let actual_response = data_future.await.unwrap();
1577 assert_eq!(actual_response, expected_response);
1578 });
1579 }
1580
1581 #[test]
1582 fn one_click_arrival_deposit_apply_response_error() {
1583 TOKIO_SHARED_RT.block_on(async {
1584 let client = MockCapitalApiClient { force_error: true };
1585
1586 let params = OneClickArrivalDepositApplyParams::builder()
1587 .build()
1588 .unwrap();
1589
1590 match client.one_click_arrival_deposit_apply(params).await {
1591 Ok(_) => panic!("Expected an error"),
1592 Err(err) => {
1593 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1594 }
1595 }
1596 });
1597 }
1598
1599 #[test]
1600 fn withdraw_required_params_success() {
1601 TOKIO_SHARED_RT.block_on(async {
1602 let client = MockCapitalApiClient { force_error: false };
1603
1604 let params = WithdrawParams::builder(
1605 "BTC".to_string(),
1606 "address_example".to_string(),
1607 dec!(1.0),
1608 )
1609 .build()
1610 .unwrap();
1611
1612 let resp_json: Value =
1613 serde_json::from_str(r#"{"id":"7213fea8e94b4a5593d507237e5a555b"}"#)
1614 .unwrap_or_else(|_| serde_json::json!({}));
1615 let expected_response: models::WithdrawResponse =
1616 serde_json::from_value(resp_json.clone())
1617 .expect("should parse into models::WithdrawResponse");
1618
1619 let resp = client.withdraw(params).await.expect("Expected a response");
1620 let data_future = resp.data();
1621 let actual_response = data_future.await.unwrap();
1622 assert_eq!(actual_response, expected_response);
1623 });
1624 }
1625
1626 #[test]
1627 fn withdraw_optional_params_success() {
1628 TOKIO_SHARED_RT.block_on(async {
1629 let client = MockCapitalApiClient { force_error: false };
1630
1631 let params = WithdrawParams::builder(
1632 "BTC".to_string(),
1633 "address_example".to_string(),
1634 dec!(1.0),
1635 )
1636 .withdraw_order_id("1".to_string())
1637 .network("network_example".to_string())
1638 .address_tag("address_tag_example".to_string())
1639 .transaction_fee_flag(true)
1640 .name("name_example".to_string())
1641 .wallet_type(0)
1642 .recv_window(5000)
1643 .build()
1644 .unwrap();
1645
1646 let resp_json: Value =
1647 serde_json::from_str(r#"{"id":"7213fea8e94b4a5593d507237e5a555b"}"#)
1648 .unwrap_or_else(|_| serde_json::json!({}));
1649 let expected_response: models::WithdrawResponse =
1650 serde_json::from_value(resp_json.clone())
1651 .expect("should parse into models::WithdrawResponse");
1652
1653 let resp = client.withdraw(params).await.expect("Expected a response");
1654 let data_future = resp.data();
1655 let actual_response = data_future.await.unwrap();
1656 assert_eq!(actual_response, expected_response);
1657 });
1658 }
1659
1660 #[test]
1661 fn withdraw_response_error() {
1662 TOKIO_SHARED_RT.block_on(async {
1663 let client = MockCapitalApiClient { force_error: true };
1664
1665 let params = WithdrawParams::builder(
1666 "BTC".to_string(),
1667 "address_example".to_string(),
1668 dec!(1.0),
1669 )
1670 .build()
1671 .unwrap();
1672
1673 match client.withdraw(params).await {
1674 Ok(_) => panic!("Expected an error"),
1675 Err(err) => {
1676 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1677 }
1678 }
1679 });
1680 }
1681
1682 #[test]
1683 fn withdraw_history_required_params_success() {
1684 TOKIO_SHARED_RT.block_on(async {
1685 let client = MockCapitalApiClient { force_error: false };
1686
1687 let params = WithdrawHistoryParams::builder().build().unwrap();
1688
1689 let resp_json: Value = serde_json::from_str(r#"[{"id":"b6ae22b3aa844210a7041aee7589627c","amount":"8.91000000","transactionFee":"0.004","coin":"USDT","status":6,"address":"0x94df8b352de7f46f64b01d3666bf6e936e44ce60","txId":"0xb5ef8c13b968a406cc62a93a8bd80f9e9a906ef1b3fcf20a2e48573c17659268","applyTime":"2019-10-12 11:12:02","network":"ETH","transferType":0,"withdrawOrderId":"WITHDRAWtest123","info":"The address is not valid. Please confirm with the recipient","confirmNo":3,"walletType":1,"txKey":"","completeTime":"2023-03-23 16:52:41"}]"#).unwrap_or_else(|_| serde_json::json!({}));
1690 let expected_response : Vec<models::WithdrawHistoryResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::WithdrawHistoryResponseInner>");
1691
1692 let resp = client.withdraw_history(params).await.expect("Expected a response");
1693 let data_future = resp.data();
1694 let actual_response = data_future.await.unwrap();
1695 assert_eq!(actual_response, expected_response);
1696 });
1697 }
1698
1699 #[test]
1700 fn withdraw_history_optional_params_success() {
1701 TOKIO_SHARED_RT.block_on(async {
1702 let client = MockCapitalApiClient { force_error: false };
1703
1704 let params = WithdrawHistoryParams::builder().coin("BTC".to_string()).withdraw_order_id("1".to_string()).status(0).offset(0).limit(1000).id_list("id_list_example".to_string()).start_time(1623319461670).end_time(1641782889000).recv_window(5000).build().unwrap();
1705
1706 let resp_json: Value = serde_json::from_str(r#"[{"id":"b6ae22b3aa844210a7041aee7589627c","amount":"8.91000000","transactionFee":"0.004","coin":"USDT","status":6,"address":"0x94df8b352de7f46f64b01d3666bf6e936e44ce60","txId":"0xb5ef8c13b968a406cc62a93a8bd80f9e9a906ef1b3fcf20a2e48573c17659268","applyTime":"2019-10-12 11:12:02","network":"ETH","transferType":0,"withdrawOrderId":"WITHDRAWtest123","info":"The address is not valid. Please confirm with the recipient","confirmNo":3,"walletType":1,"txKey":"","completeTime":"2023-03-23 16:52:41"}]"#).unwrap_or_else(|_| serde_json::json!({}));
1707 let expected_response : Vec<models::WithdrawHistoryResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::WithdrawHistoryResponseInner>");
1708
1709 let resp = client.withdraw_history(params).await.expect("Expected a response");
1710 let data_future = resp.data();
1711 let actual_response = data_future.await.unwrap();
1712 assert_eq!(actual_response, expected_response);
1713 });
1714 }
1715
1716 #[test]
1717 fn withdraw_history_response_error() {
1718 TOKIO_SHARED_RT.block_on(async {
1719 let client = MockCapitalApiClient { force_error: true };
1720
1721 let params = WithdrawHistoryParams::builder().build().unwrap();
1722
1723 match client.withdraw_history(params).await {
1724 Ok(_) => panic!("Expected an error"),
1725 Err(err) => {
1726 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1727 }
1728 }
1729 });
1730 }
1731}