1use rust_decimal::{Decimal, serde::str_option::deserialize as option_decimal};
2use serde::{Deserialize, Serialize};
3use serde_aux::prelude::{
4 deserialize_number_from_string as number,
5 deserialize_option_number_from_string as option_number,
6};
7
8use crate::{
9 AccountType, DepositStatus, Side, Timestamp, TransferStatus, WithdrawStatus, enums::Category,
10 serde::empty_string_as_none,
11};
12
13#[derive(Debug, Serialize, Clone)]
19#[serde(rename_all = "camelCase")]
20pub struct InternalTransferRequest {
21 pub transfer_id: String,
23 pub coin: String,
25 pub amount: Decimal,
27 pub from_account_type: AccountType,
29 pub to_account_type: AccountType,
31}
32
33impl InternalTransferRequest {
34 pub fn new(
36 transfer_id: impl Into<String>,
37 coin: impl Into<String>,
38 amount: Decimal,
39 from_account_type: AccountType,
40 to_account_type: AccountType,
41 ) -> Self {
42 let transfer_id: String = transfer_id.into();
43 let coin: String = coin.into();
44 Self {
45 transfer_id,
46 coin,
47 amount,
48 from_account_type,
49 to_account_type,
50 }
51 }
52}
53
54#[derive(Debug, Deserialize, PartialEq)]
57#[serde(rename_all = "camelCase")]
58pub struct TransferResult {
59 pub transfer_id: String,
61 pub status: TransferStatus,
63}
64
65#[derive(Clone, Debug, Serialize)]
70#[serde(rename_all = "camelCase")]
71pub struct GetInternalTransferRecordsParams {
72 #[serde(skip_serializing_if = "Option::is_none")]
74 pub transfer_id: Option<String>,
75 #[serde(skip_serializing_if = "Option::is_none")]
77 pub coin: Option<String>,
78 #[serde(skip_serializing_if = "Option::is_none")]
80 pub status: Option<TransferStatus>,
81 #[serde(skip_serializing_if = "Option::is_none")]
83 pub start_time: Option<Timestamp>,
84 #[serde(skip_serializing_if = "Option::is_none")]
86 pub end_time: Option<Timestamp>,
87 #[serde(skip_serializing_if = "Option::is_none")]
89 pub limit: Option<u64>,
90 #[serde(skip_serializing_if = "Option::is_none")]
92 pub cursor: Option<String>,
93}
94
95impl GetInternalTransferRecordsParams {
96 pub fn new() -> Self {
98 Self {
99 transfer_id: None,
100 coin: None,
101 status: None,
102 start_time: None,
103 end_time: None,
104 limit: None,
105 cursor: None,
106 }
107 }
108
109 pub fn with_transfer_id(mut self, v: impl Into<String>) -> Self {
111 self.transfer_id = Some(v.into());
112 self
113 }
114 pub fn with_coin(mut self, v: impl Into<String>) -> Self {
116 self.coin = Some(v.into());
117 self
118 }
119 pub fn with_status(mut self, v: TransferStatus) -> Self {
121 self.status = Some(v);
122 self
123 }
124 pub fn with_start_time(mut self, v: Timestamp) -> Self {
126 self.start_time = Some(v);
127 self
128 }
129 pub fn with_end_time(mut self, v: Timestamp) -> Self {
131 self.end_time = Some(v);
132 self
133 }
134 pub fn with_limit(mut self, v: u64) -> Self {
136 self.limit = Some(v);
137 self
138 }
139 pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
141 self.cursor = Some(v.into());
142 self
143 }
144}
145
146impl Default for GetInternalTransferRecordsParams {
147 fn default() -> Self {
148 Self::new()
149 }
150}
151
152#[derive(Debug, Deserialize, PartialEq)]
154#[serde(rename_all = "camelCase")]
155pub struct InternalTransferEntry {
156 pub transfer_id: String,
158 pub coin: String,
160 pub amount: Decimal,
162 pub from_account_type: AccountType,
164 pub to_account_type: AccountType,
166 #[serde(deserialize_with = "number")]
168 pub timestamp: Timestamp,
169 pub status: TransferStatus,
171}
172
173#[derive(Debug, Serialize, Clone)]
181#[serde(rename_all = "camelCase")]
182pub struct UniversalTransferRequest {
183 pub transfer_id: String,
185 pub coin: String,
187 pub amount: Decimal,
189 pub from_member_id: i64,
191 pub to_member_id: i64,
193 pub from_account_type: AccountType,
195 pub to_account_type: AccountType,
197}
198
199impl UniversalTransferRequest {
200 pub fn new(
202 transfer_id: impl Into<String>,
203 coin: impl Into<String>,
204 amount: Decimal,
205 from_member_id: i64,
206 to_member_id: i64,
207 from_account_type: AccountType,
208 to_account_type: AccountType,
209 ) -> Self {
210 let transfer_id: String = transfer_id.into();
211 let coin: String = coin.into();
212 Self {
213 transfer_id,
214 coin,
215 amount,
216 from_member_id,
217 to_member_id,
218 from_account_type,
219 to_account_type,
220 }
221 }
222}
223
224#[derive(Clone, Debug, Serialize)]
229#[serde(rename_all = "camelCase")]
230pub struct GetUniversalTransferRecordsParams {
231 #[serde(skip_serializing_if = "Option::is_none")]
233 pub transfer_id: Option<String>,
234 #[serde(skip_serializing_if = "Option::is_none")]
236 pub coin: Option<String>,
237 #[serde(skip_serializing_if = "Option::is_none")]
239 pub status: Option<TransferStatus>,
240 #[serde(skip_serializing_if = "Option::is_none")]
242 pub start_time: Option<Timestamp>,
243 #[serde(skip_serializing_if = "Option::is_none")]
245 pub end_time: Option<Timestamp>,
246 #[serde(skip_serializing_if = "Option::is_none")]
248 pub limit: Option<u64>,
249 #[serde(skip_serializing_if = "Option::is_none")]
251 pub cursor: Option<String>,
252}
253
254impl GetUniversalTransferRecordsParams {
255 pub fn new() -> Self {
257 Self {
258 transfer_id: None,
259 coin: None,
260 status: None,
261 start_time: None,
262 end_time: None,
263 limit: None,
264 cursor: None,
265 }
266 }
267
268 pub fn with_transfer_id(mut self, v: impl Into<String>) -> Self {
270 self.transfer_id = Some(v.into());
271 self
272 }
273 pub fn with_coin(mut self, v: impl Into<String>) -> Self {
275 self.coin = Some(v.into());
276 self
277 }
278 pub fn with_status(mut self, v: TransferStatus) -> Self {
280 self.status = Some(v);
281 self
282 }
283 pub fn with_start_time(mut self, v: Timestamp) -> Self {
285 self.start_time = Some(v);
286 self
287 }
288 pub fn with_end_time(mut self, v: Timestamp) -> Self {
290 self.end_time = Some(v);
291 self
292 }
293 pub fn with_limit(mut self, v: u64) -> Self {
295 self.limit = Some(v);
296 self
297 }
298 pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
300 self.cursor = Some(v.into());
301 self
302 }
303}
304
305impl Default for GetUniversalTransferRecordsParams {
306 fn default() -> Self {
307 Self::new()
308 }
309}
310
311#[derive(Debug, Deserialize, PartialEq)]
313#[serde(rename_all = "camelCase")]
314pub struct UniversalTransferEntry {
315 pub transfer_id: String,
317 pub coin: String,
319 pub amount: Decimal,
321 pub from_member_id: String,
323 pub to_member_id: String,
325 pub from_account_type: AccountType,
327 pub to_account_type: AccountType,
329 #[serde(deserialize_with = "number")]
331 pub timestamp: Timestamp,
332 pub status: TransferStatus,
334}
335
336#[derive(Debug, Serialize, Clone)]
341#[serde(rename_all = "camelCase")]
342pub struct GetTransferableCoinsParams {
343 pub from_account_type: AccountType,
345 pub to_account_type: AccountType,
347}
348
349impl GetTransferableCoinsParams {
350 pub fn new(from_account_type: AccountType, to_account_type: AccountType) -> Self {
352 Self {
353 from_account_type,
354 to_account_type,
355 }
356 }
357}
358
359#[derive(Debug, Serialize, Clone)]
368#[serde(rename_all = "camelCase")]
369pub struct SaveTransferSubMemberRequest {
370 pub sub_member_ids: String,
372}
373
374impl SaveTransferSubMemberRequest {
375 pub fn new(sub_member_ids: impl Into<String>) -> Self {
377 let sub_member_ids: String = sub_member_ids.into();
378 Self { sub_member_ids }
379 }
380}
381
382#[derive(Debug, Deserialize, PartialEq)]
387#[serde(rename_all = "camelCase")]
388pub struct TransferableSubMembers {
389 pub sub_member_ids: Vec<String>,
391 pub transferable_sub_member_ids: Vec<String>,
393}
394
395#[derive(Clone, Debug, Serialize)]
400#[serde(rename_all = "camelCase")]
401pub struct GetAccountCoinBalanceParams {
402 pub account_type: AccountType,
404 pub coin: String,
406 #[serde(skip_serializing_if = "Option::is_none")]
409 pub member_id: Option<String>,
410 #[serde(skip_serializing_if = "Option::is_none")]
413 pub to_member_id: Option<String>,
414 #[serde(skip_serializing_if = "Option::is_none")]
416 pub to_account_type: Option<AccountType>,
417 #[serde(skip_serializing_if = "Option::is_none")]
419 pub with_bonus: Option<i64>,
420 #[serde(skip_serializing_if = "Option::is_none")]
423 pub with_transfer_safe_amount: Option<i64>,
424 #[serde(skip_serializing_if = "Option::is_none")]
427 pub with_ltv_transfer_safe_amount: Option<i64>,
428}
429
430impl GetAccountCoinBalanceParams {
431 pub fn new(account_type: AccountType, coin: impl Into<String>) -> Self {
433 let coin: String = coin.into();
434 Self {
435 account_type,
436 coin,
437 member_id: None,
438 to_member_id: None,
439 to_account_type: None,
440 with_bonus: None,
441 with_transfer_safe_amount: None,
442 with_ltv_transfer_safe_amount: None,
443 }
444 }
445
446 pub fn with_member_id(mut self, v: impl Into<String>) -> Self {
448 self.member_id = Some(v.into());
449 self
450 }
451 pub fn with_to_member_id(mut self, v: impl Into<String>) -> Self {
453 self.to_member_id = Some(v.into());
454 self
455 }
456 pub fn with_to_account_type(mut self, v: AccountType) -> Self {
458 self.to_account_type = Some(v);
459 self
460 }
461 pub fn with_bonus(mut self, v: i64) -> Self {
463 self.with_bonus = Some(v);
464 self
465 }
466 pub fn with_transfer_safe_amount(mut self, v: i64) -> Self {
468 self.with_transfer_safe_amount = Some(v);
469 self
470 }
471 pub fn with_ltv_transfer_safe_amount(mut self, v: i64) -> Self {
473 self.with_ltv_transfer_safe_amount = Some(v);
474 self
475 }
476}
477
478#[derive(Debug, Deserialize, PartialEq)]
480#[serde(rename_all = "camelCase")]
481pub struct AccountCoinBalance {
482 pub account_type: AccountType,
484 pub biz_type: i64,
486 pub account_id: String,
488 pub member_id: String,
490 pub balance: CoinBalance,
492}
493
494#[derive(Debug, Deserialize, PartialEq)]
496#[serde(rename_all = "camelCase")]
497pub struct CoinBalance {
498 pub coin: String,
500 pub wallet_balance: Decimal,
502 pub transfer_balance: Decimal,
504 pub bonus: Decimal,
506 #[serde(default, deserialize_with = "option_decimal")]
508 pub transfer_safe_amount: Option<Decimal>,
509 #[serde(default, deserialize_with = "option_decimal")]
511 pub ltv_transfer_safe_amount: Option<Decimal>,
512}
513
514#[derive(Debug, Serialize, Clone)]
518#[serde(rename_all = "camelCase")]
519pub struct GetAssetInfoParams {
520 pub account_type: AccountType,
522 #[serde(skip_serializing_if = "Option::is_none")]
524 pub coin: Option<String>,
525}
526
527impl GetAssetInfoParams {
528 pub fn new(account_type: AccountType) -> Self {
530 Self {
531 account_type,
532 coin: None,
533 }
534 }
535
536 pub fn with_coin(mut self, v: impl Into<String>) -> Self {
538 self.coin = Some(v.into());
539 self
540 }
541}
542
543#[derive(Debug, Deserialize, PartialEq)]
545#[serde(rename_all = "camelCase")]
546pub struct AssetInfoResult {
547 pub spot: SpotAssetInfo,
549}
550
551#[derive(Debug, Deserialize, PartialEq)]
553#[serde(rename_all = "camelCase")]
554pub struct SpotAssetInfo {
555 pub status: String,
557 pub assets: Vec<SpotAsset>,
559}
560
561#[derive(Debug, Deserialize, PartialEq)]
563#[serde(rename_all = "camelCase")]
564pub struct SpotAsset {
565 pub coin: String,
567 pub frozen: Decimal,
569 pub free: Decimal,
571 pub withdraw: Decimal,
573}
574
575#[derive(Clone, Debug, Serialize)]
582#[serde(rename_all = "camelCase")]
583pub struct GetDepositAllowedCoinInfoParams {
584 #[serde(skip_serializing_if = "Option::is_none")]
586 pub coin: Option<String>,
587 #[serde(skip_serializing_if = "Option::is_none")]
589 pub chain: Option<String>,
590 #[serde(skip_serializing_if = "Option::is_none")]
592 pub limit: Option<u64>,
593 #[serde(skip_serializing_if = "Option::is_none")]
595 pub cursor: Option<String>,
596}
597
598impl GetDepositAllowedCoinInfoParams {
599 pub fn new() -> Self {
601 Self {
602 coin: None,
603 chain: None,
604 limit: None,
605 cursor: None,
606 }
607 }
608
609 pub fn with_coin(mut self, v: impl Into<String>) -> Self {
611 self.coin = Some(v.into());
612 self
613 }
614 pub fn with_chain(mut self, v: impl Into<String>) -> Self {
616 self.chain = Some(v.into());
617 self
618 }
619 pub fn with_limit(mut self, v: u64) -> Self {
621 self.limit = Some(v);
622 self
623 }
624 pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
626 self.cursor = Some(v.into());
627 self
628 }
629}
630
631impl Default for GetDepositAllowedCoinInfoParams {
632 fn default() -> Self {
633 Self::new()
634 }
635}
636
637#[derive(Debug, Deserialize, PartialEq)]
639#[serde(rename_all = "camelCase")]
640pub struct DepositAllowedCoinInfoResult {
641 pub config_list: Vec<DepositCoinConfig>,
643 #[serde(default, deserialize_with = "empty_string_as_none")]
645 pub next_page_cursor: Option<String>,
646}
647
648#[derive(Debug, Deserialize, PartialEq)]
650#[serde(rename_all = "camelCase")]
651pub struct DepositCoinConfig {
652 pub coin: String,
654 pub chain: String,
656 pub coin_show_name: String,
658 pub chain_type: String,
660 #[serde(deserialize_with = "number")]
662 pub block_confirm_number: u32,
663 pub min_deposit_amount: Decimal,
665}
666
667#[derive(Clone, Debug, Serialize)]
672#[serde(rename_all = "camelCase")]
673pub struct GetDepositRecordsParams {
674 #[serde(skip_serializing_if = "Option::is_none")]
676 pub id: Option<String>,
677 #[serde(skip_serializing_if = "Option::is_none")]
679 pub tx_id: Option<String>,
680 #[serde(skip_serializing_if = "Option::is_none")]
682 pub coin: Option<String>,
683 #[serde(skip_serializing_if = "Option::is_none")]
685 pub start_time: Option<Timestamp>,
686 #[serde(skip_serializing_if = "Option::is_none")]
688 pub end_time: Option<Timestamp>,
689 #[serde(skip_serializing_if = "Option::is_none")]
691 pub limit: Option<u64>,
692 #[serde(skip_serializing_if = "Option::is_none")]
694 pub cursor: Option<String>,
695}
696
697impl GetDepositRecordsParams {
698 pub fn new() -> Self {
700 Self {
701 id: None,
702 tx_id: None,
703 coin: None,
704 start_time: None,
705 end_time: None,
706 limit: None,
707 cursor: None,
708 }
709 }
710
711 pub fn with_id(mut self, v: impl Into<String>) -> Self {
713 self.id = Some(v.into());
714 self
715 }
716 pub fn with_tx_id(mut self, v: impl Into<String>) -> Self {
718 self.tx_id = Some(v.into());
719 self
720 }
721 pub fn with_coin(mut self, v: impl Into<String>) -> Self {
723 self.coin = Some(v.into());
724 self
725 }
726 pub fn with_start_time(mut self, v: Timestamp) -> Self {
728 self.start_time = Some(v);
729 self
730 }
731 pub fn with_end_time(mut self, v: Timestamp) -> Self {
733 self.end_time = Some(v);
734 self
735 }
736 pub fn with_limit(mut self, v: u64) -> Self {
738 self.limit = Some(v);
739 self
740 }
741 pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
743 self.cursor = Some(v.into());
744 self
745 }
746}
747
748impl Default for GetDepositRecordsParams {
749 fn default() -> Self {
750 Self::new()
751 }
752}
753
754#[derive(Clone, Debug, Serialize)]
757#[serde(rename_all = "camelCase")]
758pub struct GetSubDepositRecordsParams {
759 pub sub_member_id: String,
761 #[serde(skip_serializing_if = "Option::is_none")]
763 pub id: Option<String>,
764 #[serde(skip_serializing_if = "Option::is_none")]
766 pub tx_id: Option<String>,
767 #[serde(skip_serializing_if = "Option::is_none")]
769 pub coin: Option<String>,
770 #[serde(skip_serializing_if = "Option::is_none")]
772 pub start_time: Option<Timestamp>,
773 #[serde(skip_serializing_if = "Option::is_none")]
775 pub end_time: Option<Timestamp>,
776 #[serde(skip_serializing_if = "Option::is_none")]
778 pub limit: Option<u64>,
779 #[serde(skip_serializing_if = "Option::is_none")]
781 pub cursor: Option<String>,
782}
783
784impl GetSubDepositRecordsParams {
785 pub fn new(sub_member_id: impl Into<String>) -> Self {
787 let sub_member_id: String = sub_member_id.into();
788 Self {
789 sub_member_id,
790 id: None,
791 tx_id: None,
792 coin: None,
793 start_time: None,
794 end_time: None,
795 limit: None,
796 cursor: None,
797 }
798 }
799
800 pub fn with_id(mut self, v: impl Into<String>) -> Self {
802 self.id = Some(v.into());
803 self
804 }
805 pub fn with_tx_id(mut self, v: impl Into<String>) -> Self {
807 self.tx_id = Some(v.into());
808 self
809 }
810 pub fn with_coin(mut self, v: impl Into<String>) -> Self {
812 self.coin = Some(v.into());
813 self
814 }
815 pub fn with_start_time(mut self, v: Timestamp) -> Self {
817 self.start_time = Some(v);
818 self
819 }
820 pub fn with_end_time(mut self, v: Timestamp) -> Self {
822 self.end_time = Some(v);
823 self
824 }
825 pub fn with_limit(mut self, v: u64) -> Self {
827 self.limit = Some(v);
828 self
829 }
830 pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
832 self.cursor = Some(v.into());
833 self
834 }
835}
836
837#[derive(Debug, Deserialize, PartialEq)]
839#[serde(rename_all = "camelCase")]
840pub struct DepositRecords {
841 pub rows: Vec<DepositRecord>,
843 #[serde(default, deserialize_with = "empty_string_as_none")]
845 pub next_page_cursor: Option<String>,
846}
847
848#[derive(Debug, Deserialize, PartialEq)]
850#[serde(rename_all = "camelCase")]
851pub struct DepositRecord {
852 pub id: String,
854 pub coin: String,
856 pub chain: String,
858 pub amount: Decimal,
860 #[serde(default, deserialize_with = "empty_string_as_none")]
862 pub tx_id: Option<String>,
863 pub status: DepositStatus,
865 pub to_address: String,
867 #[serde(default, deserialize_with = "empty_string_as_none")]
869 pub tag: Option<String>,
870 pub deposit_fee: Decimal,
872 #[serde(deserialize_with = "option_number")]
874 pub success_at: Option<Timestamp>,
875 pub confirmations: String,
877 pub tx_index: String,
879 pub block_hash: String,
881 pub batch_release_limit: String,
883 pub deposit_type: i64,
885 #[serde(default, deserialize_with = "empty_string_as_none")]
887 pub from_address: Option<String>,
888 #[serde(default, deserialize_with = "empty_string_as_none")]
890 pub tax_deposit_records_id: Option<String>,
891 #[serde(default)]
893 pub tax_status: Option<i64>,
894 #[serde(default)]
896 pub travel_rule_status: Option<i64>,
897}
898
899#[derive(Debug, Serialize, Clone)]
904#[serde(rename_all = "camelCase")]
905pub struct GetDepositAddressParams {
906 pub coin: String,
908 #[serde(skip_serializing_if = "Option::is_none")]
910 pub chain_type: Option<String>,
911}
912
913impl GetDepositAddressParams {
914 pub fn new(coin: impl Into<String>) -> Self {
916 let coin: String = coin.into();
917 Self {
918 coin,
919 chain_type: None,
920 }
921 }
922
923 pub fn with_chain_type(mut self, v: impl Into<String>) -> Self {
925 self.chain_type = Some(v.into());
926 self
927 }
928}
929
930#[derive(Debug, Serialize, Clone)]
935#[serde(rename_all = "camelCase")]
936pub struct GetSubDepositAddressParams {
937 pub coin: String,
939 pub chain_type: String,
941 pub sub_member_id: String,
943}
944
945impl GetSubDepositAddressParams {
946 pub fn new(
948 coin: impl Into<String>,
949 chain_type: impl Into<String>,
950 sub_member_id: impl Into<String>,
951 ) -> Self {
952 let coin: String = coin.into();
953 let chain_type: String = chain_type.into();
954 let sub_member_id: String = sub_member_id.into();
955 Self {
956 coin,
957 chain_type,
958 sub_member_id,
959 }
960 }
961}
962
963#[derive(Debug, Deserialize, PartialEq)]
965#[serde(rename_all = "camelCase")]
966pub struct DepositAddress {
967 pub coin: String,
969 pub chains: Vec<DepositChain>,
971}
972
973#[derive(Debug, Deserialize, PartialEq)]
975#[serde(rename_all = "camelCase")]
976pub struct DepositChain {
977 pub chain_type: String,
979 pub address_deposit: String,
981 #[serde(default, deserialize_with = "empty_string_as_none")]
983 pub tag_deposit: Option<String>,
984 pub chain: String,
986 pub batch_release_limit: String,
988 #[serde(default, deserialize_with = "empty_string_as_none")]
990 pub contract_address: Option<String>,
991}
992
993#[derive(Clone, Debug, Serialize)]
1000#[serde(rename_all = "camelCase")]
1001pub struct GetWithdrawalRecordsParams {
1002 #[serde(skip_serializing_if = "Option::is_none")]
1004 pub withdraw_id: Option<String>,
1005 #[serde(skip_serializing_if = "Option::is_none")]
1007 pub tx_id: Option<String>,
1008 #[serde(skip_serializing_if = "Option::is_none")]
1010 pub coin: Option<String>,
1011 #[serde(skip_serializing_if = "Option::is_none")]
1013 pub withdraw_type: Option<i64>,
1014 #[serde(skip_serializing_if = "Option::is_none")]
1016 pub start_time: Option<Timestamp>,
1017 #[serde(skip_serializing_if = "Option::is_none")]
1019 pub end_time: Option<Timestamp>,
1020 #[serde(skip_serializing_if = "Option::is_none")]
1022 pub limit: Option<u64>,
1023 #[serde(skip_serializing_if = "Option::is_none")]
1025 pub cursor: Option<String>,
1026}
1027
1028impl GetWithdrawalRecordsParams {
1029 pub fn new() -> Self {
1031 Self {
1032 withdraw_id: None,
1033 tx_id: None,
1034 coin: None,
1035 withdraw_type: None,
1036 start_time: None,
1037 end_time: None,
1038 limit: None,
1039 cursor: None,
1040 }
1041 }
1042
1043 pub fn with_withdraw_id(mut self, v: impl Into<String>) -> Self {
1045 self.withdraw_id = Some(v.into());
1046 self
1047 }
1048 pub fn with_tx_id(mut self, v: impl Into<String>) -> Self {
1050 self.tx_id = Some(v.into());
1051 self
1052 }
1053 pub fn with_coin(mut self, v: impl Into<String>) -> Self {
1055 self.coin = Some(v.into());
1056 self
1057 }
1058 pub fn with_withdraw_type(mut self, v: i64) -> Self {
1060 self.withdraw_type = Some(v);
1061 self
1062 }
1063 pub fn with_start_time(mut self, v: Timestamp) -> Self {
1065 self.start_time = Some(v);
1066 self
1067 }
1068 pub fn with_end_time(mut self, v: Timestamp) -> Self {
1070 self.end_time = Some(v);
1071 self
1072 }
1073 pub fn with_limit(mut self, v: u64) -> Self {
1075 self.limit = Some(v);
1076 self
1077 }
1078 pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
1080 self.cursor = Some(v.into());
1081 self
1082 }
1083}
1084
1085impl Default for GetWithdrawalRecordsParams {
1086 fn default() -> Self {
1087 Self::new()
1088 }
1089}
1090
1091#[derive(Debug, Deserialize, PartialEq)]
1093#[serde(rename_all = "camelCase")]
1094pub struct WithdrawRecords {
1095 pub rows: Vec<WithdrawRecord>,
1097 #[serde(default, deserialize_with = "empty_string_as_none")]
1099 pub next_page_cursor: Option<String>,
1100}
1101
1102#[derive(Debug, Deserialize, PartialEq)]
1104#[serde(rename_all = "camelCase")]
1105pub struct WithdrawRecord {
1106 #[serde(default, deserialize_with = "empty_string_as_none")]
1108 pub tx_id: Option<String>,
1109 pub coin: String,
1111 pub chain: String,
1113 pub amount: Decimal,
1115 pub withdraw_fee: Decimal,
1117 pub status: WithdrawStatus,
1119 pub to_address: String,
1121 #[serde(default, deserialize_with = "empty_string_as_none")]
1123 pub tag: Option<String>,
1124 #[serde(deserialize_with = "number")]
1126 pub create_time: Timestamp,
1127 #[serde(deserialize_with = "number")]
1129 pub update_time: Timestamp,
1130 pub withdraw_id: String,
1132 pub withdraw_type: i64,
1134 #[serde(default, deserialize_with = "option_decimal")]
1136 pub tax: Option<Decimal>,
1137 #[serde(default, deserialize_with = "option_decimal")]
1139 pub tax_rate: Option<Decimal>,
1140 #[serde(default, deserialize_with = "empty_string_as_none")]
1142 pub tax_type: Option<String>,
1143}
1144
1145#[derive(Debug, Serialize, Clone)]
1149#[serde(rename_all = "camelCase")]
1150pub struct WithdrawRequest {
1151 pub coin: String,
1153 pub address: String,
1155 pub amount: Decimal,
1157 pub timestamp: i64,
1159 pub account_type: String,
1163 #[serde(skip_serializing_if = "Option::is_none")]
1166 pub chain: Option<String>,
1167 #[serde(skip_serializing_if = "Option::is_none")]
1169 pub tag: Option<String>,
1170 #[serde(skip_serializing_if = "Option::is_none")]
1174 pub force_chain: Option<i64>,
1175 #[serde(skip_serializing_if = "Option::is_none")]
1178 pub fee_type: Option<i64>,
1179 #[serde(skip_serializing_if = "Option::is_none")]
1181 pub request_id: Option<String>,
1182}
1183
1184impl WithdrawRequest {
1185 pub fn new(
1187 coin: impl Into<String>,
1188 address: impl Into<String>,
1189 amount: Decimal,
1190 timestamp: i64,
1191 account_type: impl Into<String>,
1192 ) -> Self {
1193 let coin: String = coin.into();
1194 let address: String = address.into();
1195 let account_type: String = account_type.into();
1196 Self {
1197 coin,
1198 address,
1199 amount,
1200 timestamp,
1201 account_type,
1202 chain: None,
1203 tag: None,
1204 force_chain: None,
1205 fee_type: None,
1206 request_id: None,
1207 }
1208 }
1209
1210 pub fn with_chain(mut self, v: impl Into<String>) -> Self {
1212 self.chain = Some(v.into());
1213 self
1214 }
1215 pub fn with_tag(mut self, v: impl Into<String>) -> Self {
1217 self.tag = Some(v.into());
1218 self
1219 }
1220 pub fn with_force_chain(mut self, v: i64) -> Self {
1222 self.force_chain = Some(v);
1223 self
1224 }
1225 pub fn with_fee_type(mut self, v: i64) -> Self {
1227 self.fee_type = Some(v);
1228 self
1229 }
1230 pub fn with_request_id(mut self, v: impl Into<String>) -> Self {
1232 self.request_id = Some(v.into());
1233 self
1234 }
1235}
1236
1237#[derive(Debug, Deserialize, PartialEq)]
1239pub struct WithdrawResult {
1240 pub id: String,
1242}
1243
1244#[derive(Debug, Serialize, Clone)]
1248pub struct CancelWithdrawalRequest {
1249 pub id: String,
1251}
1252
1253impl CancelWithdrawalRequest {
1254 pub fn new(id: impl Into<String>) -> Self {
1256 let id: String = id.into();
1257 Self { id }
1258 }
1259}
1260
1261#[derive(Debug, Deserialize, PartialEq)]
1263pub struct CancelWithdrawalResult {
1264 pub status: i64,
1266}
1267
1268#[derive(Debug, Serialize, Clone)]
1273#[serde(rename_all = "camelCase")]
1274pub struct GetWithdrawableAmountParams {
1275 pub coin: String,
1277}
1278
1279impl GetWithdrawableAmountParams {
1280 pub fn new(coin: impl Into<String>) -> Self {
1282 let coin: String = coin.into();
1283 Self { coin }
1284 }
1285}
1286
1287#[derive(Debug, Deserialize, PartialEq)]
1289#[serde(rename_all = "camelCase")]
1290pub struct WithdrawableAmountResult {
1291 pub limit_amount_usd: Decimal,
1294 pub withdrawable_amount: WithdrawableAmountByWallet,
1296}
1297
1298#[derive(Debug, Deserialize, PartialEq)]
1300pub struct WithdrawableAmountByWallet {
1301 #[serde(rename = "SPOT")]
1303 pub spot: Option<WithdrawableAmountEntry>,
1304 #[serde(rename = "FUND")]
1306 pub fund: Option<WithdrawableAmountEntry>,
1307 #[serde(rename = "UTA")]
1309 pub uta: Option<WithdrawableAmountEntry>,
1310 #[serde(rename = "EARN")]
1312 pub earn: Option<WithdrawableAmountEntry>,
1313}
1314
1315#[derive(Debug, Deserialize, PartialEq)]
1317#[serde(rename_all = "camelCase")]
1318pub struct WithdrawableAmountEntry {
1319 pub coin: String,
1321 pub withdrawable_amount: Decimal,
1323 pub available_balance: Decimal,
1325}
1326
1327#[derive(Debug, Serialize, Clone)]
1333#[serde(rename_all = "camelCase")]
1334pub struct GetCoinInfoParams {
1335 #[serde(skip_serializing_if = "Option::is_none")]
1337 pub coin: Option<String>,
1338}
1339
1340impl GetCoinInfoParams {
1341 pub fn new() -> Self {
1343 Self { coin: None }
1344 }
1345
1346 pub fn with_coin(mut self, v: impl Into<String>) -> Self {
1348 self.coin = Some(v.into());
1349 self
1350 }
1351}
1352
1353impl Default for GetCoinInfoParams {
1354 fn default() -> Self {
1355 Self::new()
1356 }
1357}
1358
1359#[derive(Debug, Deserialize, PartialEq)]
1361#[serde(rename_all = "camelCase")]
1362pub struct CoinInfoResult {
1363 pub rows: Vec<CoinInfo>,
1365}
1366
1367#[derive(Debug, Deserialize, PartialEq)]
1369#[serde(rename_all = "camelCase")]
1370pub struct CoinInfo {
1371 pub name: String,
1373 pub coin: String,
1375 pub chains: Vec<CoinChain>,
1377}
1378
1379#[derive(Debug, Deserialize, PartialEq)]
1381#[serde(rename_all = "camelCase")]
1382pub struct CoinChain {
1383 pub chain: String,
1385 pub chain_type: String,
1387 pub confirmation: String,
1389 #[serde(default, deserialize_with = "empty_string_as_none")]
1391 pub withdraw_fee: Option<Decimal>,
1392 #[serde(default, deserialize_with = "empty_string_as_none")]
1394 pub deposit_min: Option<Decimal>,
1395 #[serde(default, deserialize_with = "empty_string_as_none")]
1397 pub withdraw_min: Option<Decimal>,
1398 pub min_accuracy: String,
1400 pub chain_deposit: String,
1402 pub chain_withdraw: String,
1404 #[serde(default, deserialize_with = "empty_string_as_none")]
1406 pub withdraw_percentage_fee: Option<Decimal>,
1407 #[serde(default, deserialize_with = "empty_string_as_none")]
1409 pub contract_address: Option<String>,
1410 pub safe_confirm_number: String,
1412 pub withdraw_max: String,
1414}
1415
1416#[derive(Clone, Debug, Serialize)]
1421#[serde(rename_all = "camelCase")]
1422pub struct GetExchangeOrderRecordParams {
1423 #[serde(skip_serializing_if = "Option::is_none")]
1425 pub from_coin: Option<String>,
1426 #[serde(skip_serializing_if = "Option::is_none")]
1428 pub to_coin: Option<String>,
1429 #[serde(skip_serializing_if = "Option::is_none")]
1431 pub limit: Option<u64>,
1432 #[serde(skip_serializing_if = "Option::is_none")]
1434 pub cursor: Option<String>,
1435}
1436
1437impl GetExchangeOrderRecordParams {
1438 pub fn new() -> Self {
1440 Self {
1441 from_coin: None,
1442 to_coin: None,
1443 limit: None,
1444 cursor: None,
1445 }
1446 }
1447
1448 pub fn with_from_coin(mut self, v: impl Into<String>) -> Self {
1450 self.from_coin = Some(v.into());
1451 self
1452 }
1453 pub fn with_to_coin(mut self, v: impl Into<String>) -> Self {
1455 self.to_coin = Some(v.into());
1456 self
1457 }
1458 pub fn with_limit(mut self, v: u64) -> Self {
1460 self.limit = Some(v);
1461 self
1462 }
1463 pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
1465 self.cursor = Some(v.into());
1466 self
1467 }
1468}
1469
1470impl Default for GetExchangeOrderRecordParams {
1471 fn default() -> Self {
1472 Self::new()
1473 }
1474}
1475
1476#[derive(Debug, Deserialize, PartialEq)]
1478#[serde(rename_all = "camelCase")]
1479pub struct ExchangeOrderRecords {
1480 pub order_body: Vec<ExchangeOrderRecord>,
1482 #[serde(default, deserialize_with = "empty_string_as_none")]
1484 pub next_page_cursor: Option<String>,
1485}
1486
1487#[derive(Debug, Deserialize, PartialEq)]
1489#[serde(rename_all = "camelCase")]
1490pub struct ExchangeOrderRecord {
1491 pub from_coin: String,
1493 pub from_amount: Decimal,
1495 pub to_coin: String,
1497 pub to_amount: Decimal,
1499 pub exchange_rate: Decimal,
1501 #[serde(deserialize_with = "number")]
1503 pub created_time: Timestamp,
1504 pub exchange_tx_id: String,
1506}
1507
1508#[derive(Clone, Debug, Serialize)]
1513#[serde(rename_all = "camelCase")]
1514pub struct GetDeliveryRecordParams {
1515 pub category: Category,
1517 #[serde(skip_serializing_if = "Option::is_none")]
1519 pub symbol: Option<String>,
1520 #[serde(skip_serializing_if = "Option::is_none")]
1522 pub start_time: Option<Timestamp>,
1523 #[serde(skip_serializing_if = "Option::is_none")]
1525 pub end_time: Option<Timestamp>,
1526 #[serde(skip_serializing_if = "Option::is_none")]
1528 pub exp_date: Option<String>,
1529 #[serde(skip_serializing_if = "Option::is_none")]
1531 pub limit: Option<u64>,
1532 #[serde(skip_serializing_if = "Option::is_none")]
1534 pub cursor: Option<String>,
1535}
1536
1537impl GetDeliveryRecordParams {
1538 pub fn new(category: Category) -> Self {
1540 Self {
1541 category,
1542 symbol: None,
1543 start_time: None,
1544 end_time: None,
1545 exp_date: None,
1546 limit: None,
1547 cursor: None,
1548 }
1549 }
1550
1551 pub fn with_symbol(mut self, v: impl Into<String>) -> Self {
1553 self.symbol = Some(v.into());
1554 self
1555 }
1556 pub fn with_start_time(mut self, v: Timestamp) -> Self {
1558 self.start_time = Some(v);
1559 self
1560 }
1561 pub fn with_end_time(mut self, v: Timestamp) -> Self {
1563 self.end_time = Some(v);
1564 self
1565 }
1566 pub fn with_exp_date(mut self, v: impl Into<String>) -> Self {
1568 self.exp_date = Some(v.into());
1569 self
1570 }
1571 pub fn with_limit(mut self, v: u64) -> Self {
1573 self.limit = Some(v);
1574 self
1575 }
1576 pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
1578 self.cursor = Some(v.into());
1579 self
1580 }
1581}
1582
1583#[derive(Debug, Deserialize, PartialEq)]
1585#[serde(rename_all = "camelCase")]
1586pub struct DeliveryRecord {
1587 pub delivery_time: Timestamp,
1589 pub symbol: String,
1591 pub side: Side,
1593 pub position: Decimal,
1595 pub entry_price: Decimal,
1597 pub delivery_price: Decimal,
1599 #[serde(default, deserialize_with = "option_decimal")]
1601 pub strike: Option<Decimal>,
1602 pub fee: Decimal,
1604 pub delivery_rpl: Decimal,
1606}
1607
1608#[derive(Clone, Debug, Serialize)]
1613#[serde(rename_all = "camelCase")]
1614pub struct GetSettlementRecordParams {
1615 pub category: Category,
1617 #[serde(skip_serializing_if = "Option::is_none")]
1619 pub symbol: Option<String>,
1620 #[serde(skip_serializing_if = "Option::is_none")]
1622 pub start_time: Option<Timestamp>,
1623 #[serde(skip_serializing_if = "Option::is_none")]
1625 pub end_time: Option<Timestamp>,
1626 #[serde(skip_serializing_if = "Option::is_none")]
1628 pub limit: Option<u64>,
1629 #[serde(skip_serializing_if = "Option::is_none")]
1631 pub cursor: Option<String>,
1632}
1633
1634impl GetSettlementRecordParams {
1635 pub fn new(category: Category) -> Self {
1637 Self {
1638 category,
1639 symbol: None,
1640 start_time: None,
1641 end_time: None,
1642 limit: None,
1643 cursor: None,
1644 }
1645 }
1646
1647 pub fn with_symbol(mut self, v: impl Into<String>) -> Self {
1649 self.symbol = Some(v.into());
1650 self
1651 }
1652 pub fn with_start_time(mut self, v: Timestamp) -> Self {
1654 self.start_time = Some(v);
1655 self
1656 }
1657 pub fn with_end_time(mut self, v: Timestamp) -> Self {
1659 self.end_time = Some(v);
1660 self
1661 }
1662 pub fn with_limit(mut self, v: u64) -> Self {
1664 self.limit = Some(v);
1665 self
1666 }
1667 pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
1669 self.cursor = Some(v.into());
1670 self
1671 }
1672}
1673
1674#[derive(Debug, Deserialize, PartialEq)]
1676#[serde(rename_all = "camelCase")]
1677pub struct SettlementRecord {
1678 pub symbol: String,
1680 pub side: Side,
1682 pub size: Decimal,
1684 pub session_avg_price: Decimal,
1686 pub mark_price: Decimal,
1688 pub realised_pnl: Decimal,
1690 #[serde(deserialize_with = "number")]
1692 pub created_time: Timestamp,
1693}
1694
1695#[derive(Debug, Serialize, Clone)]
1699#[serde(rename_all = "camelCase")]
1700pub struct GetCoinGreeksParams {
1701 #[serde(skip_serializing_if = "Option::is_none")]
1703 pub base_coin: Option<String>,
1704}
1705
1706impl GetCoinGreeksParams {
1707 pub fn new() -> Self {
1709 Self { base_coin: None }
1710 }
1711
1712 pub fn with_base_coin(mut self, v: impl Into<String>) -> Self {
1714 self.base_coin = Some(v.into());
1715 self
1716 }
1717}
1718
1719impl Default for GetCoinGreeksParams {
1720 fn default() -> Self {
1721 Self::new()
1722 }
1723}
1724
1725#[derive(Debug, Deserialize, PartialEq)]
1727#[serde(rename_all = "camelCase")]
1728pub struct CoinGreeks {
1729 pub base_coin: String,
1731 pub total_delta: Decimal,
1733 pub total_gamma: Decimal,
1735 pub total_vega: Decimal,
1737 pub total_theta: Decimal,
1739}
1740
1741#[cfg(test)]
1742mod tests {
1743 use super::*;
1744
1745 #[test]
1746 fn coin_chain_with_empty_limits() {
1747 let json = r#"{"rows":[{"name":"USDT","coin":"USDT","remainAmount":"100","chains":[{
1749 "chainType":"X","confirmation":"","withdrawFee":"","depositMin":"","withdrawMin":"",
1750 "chain":"X","chainDeposit":"0","chainWithdraw":"0","minAccuracy":"8",
1751 "withdrawPercentageFee":"","contractAddress":"","safeConfirmNumber":"","withdrawMax":""
1752 }]}]}"#;
1753
1754 let result: CoinInfoResult = serde_json::from_str(json).unwrap();
1755
1756 let chain = &result.rows[0].chains[0];
1757 assert_eq!(chain.deposit_min, None);
1758 assert_eq!(chain.withdraw_fee, None);
1759 assert_eq!(chain.contract_address, None);
1760 }
1761
1762 #[test]
1763 fn deposit_coin_config_with_numeric_block_confirm_number() {
1764 let json = r#"{"configList":[{"coin":"USDT","chain":"ETH","coinShowName":"USDT",
1765 "chainType":"ERC20","blockConfirmNumber":1,"minDepositAmount":"0.01"}],
1766 "nextPageCursor":""}"#;
1767
1768 let result: DepositAllowedCoinInfoResult = serde_json::from_str(json).unwrap();
1769
1770 assert_eq!(result.config_list[0].block_confirm_number, 1);
1771 }
1772}