Skip to main content

binance_api_client/models/
wallet.rs

1//! Wallet API response models.
2//!
3//! Models for the Binance Wallet SAPI endpoints.
4
5use serde::{Deserialize, Serialize};
6use serde_repr::{Deserialize_repr, Serialize_repr};
7
8use super::string_or_float;
9
10/// System status response.
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct SystemStatus {
13    /// Status: 0 = normal, 1 = system maintenance
14    pub status: u32,
15    /// Status message (e.g., "normal", "system_maintenance")
16    pub msg: String,
17}
18
19impl SystemStatus {
20    /// Returns true if the system is operating normally.
21    pub fn is_normal(&self) -> bool {
22        self.status == 0
23    }
24}
25
26/// Coin network information.
27#[derive(Debug, Clone, Serialize, Deserialize)]
28#[serde(rename_all = "camelCase")]
29pub struct CoinNetwork {
30    /// Address regex pattern.
31    #[serde(default)]
32    pub address_regex: Option<String>,
33    /// Coin name.
34    pub coin: String,
35    /// Deposit description.
36    #[serde(default)]
37    pub deposit_desc: Option<String>,
38    /// Whether deposits are enabled.
39    pub deposit_enable: bool,
40    /// Whether this is the default network.
41    pub is_default: bool,
42    /// Memo regex pattern.
43    #[serde(default)]
44    pub memo_regex: Option<String>,
45    /// Minimum confirmations for deposit.
46    pub min_confirm: u32,
47    /// Network name.
48    pub name: String,
49    /// Network identifier.
50    pub network: String,
51    /// Whether special tips are available.
52    #[serde(default)]
53    pub special_tips: Option<String>,
54    /// Unlock confirmations required.
55    #[serde(default)]
56    pub un_lock_confirm: Option<u32>,
57    /// Withdraw description.
58    #[serde(default)]
59    pub withdraw_desc: Option<String>,
60    /// Whether withdrawals are enabled.
61    pub withdraw_enable: bool,
62    /// Withdrawal fee.
63    #[serde(with = "string_or_float")]
64    pub withdraw_fee: f64,
65    /// Withdrawal integer multiple.
66    #[serde(default, with = "string_or_float_option")]
67    pub withdraw_integer_multiple: Option<f64>,
68    /// Maximum withdrawal amount.
69    #[serde(with = "string_or_float")]
70    pub withdraw_max: f64,
71    /// Minimum withdrawal amount.
72    #[serde(with = "string_or_float")]
73    pub withdraw_min: f64,
74    /// Whether same address is supported.
75    #[serde(default)]
76    pub same_address: Option<bool>,
77    /// Estimated arrival time.
78    #[serde(default)]
79    pub estimated_arrival_time: Option<u64>,
80    /// Whether the network is busy.
81    #[serde(default)]
82    pub busy: Option<bool>,
83}
84
85/// Coin information from wallet config.
86#[derive(Debug, Clone, Serialize, Deserialize)]
87#[serde(rename_all = "camelCase")]
88pub struct CoinInfo {
89    /// Coin symbol (e.g., "BTC").
90    pub coin: String,
91    /// Whether deposit is available for all networks.
92    pub deposit_all_enable: bool,
93    /// Free balance.
94    #[serde(with = "string_or_float")]
95    pub free: f64,
96    /// Freeze balance.
97    #[serde(with = "string_or_float")]
98    pub freeze: f64,
99    /// IPO-able balance.
100    #[serde(with = "string_or_float")]
101    pub ipoable: f64,
102    /// IPOING balance.
103    #[serde(with = "string_or_float")]
104    pub ipoing: f64,
105    /// Whether legal money.
106    pub is_legal_money: bool,
107    /// Locked balance.
108    #[serde(with = "string_or_float")]
109    pub locked: f64,
110    /// Full coin name.
111    pub name: String,
112    /// Available networks for this coin.
113    pub network_list: Vec<CoinNetwork>,
114    /// Storage balance.
115    #[serde(with = "string_or_float")]
116    pub storage: f64,
117    /// Whether trading is enabled.
118    pub trading: bool,
119    /// Whether withdraw is available for all networks.
120    pub withdraw_all_enable: bool,
121    /// Withdrawing balance.
122    #[serde(with = "string_or_float")]
123    pub withdrawing: f64,
124}
125
126/// Deposit address information.
127#[derive(Debug, Clone, Serialize, Deserialize)]
128#[serde(rename_all = "camelCase")]
129pub struct DepositAddress {
130    /// Deposit address.
131    pub address: String,
132    /// Coin symbol.
133    pub coin: String,
134    /// Tag/memo (if applicable).
135    pub tag: String,
136    /// URL for address (optional).
137    #[serde(default)]
138    pub url: Option<String>,
139}
140
141/// Deposit record from history.
142#[derive(Debug, Clone, Serialize, Deserialize)]
143#[serde(rename_all = "camelCase")]
144pub struct DepositRecord {
145    /// Deposit amount.
146    #[serde(with = "string_or_float")]
147    pub amount: f64,
148    /// Coin symbol.
149    pub coin: String,
150    /// Network used.
151    pub network: String,
152    /// Deposit status.
153    pub status: DepositStatus,
154    /// Deposit address.
155    pub address: String,
156    /// Address tag (if applicable).
157    #[serde(default)]
158    pub address_tag: Option<String>,
159    /// Transaction ID.
160    pub tx_id: String,
161    /// Insert time (timestamp).
162    pub insert_time: u64,
163    /// Transfer type.
164    #[serde(default)]
165    pub transfer_type: Option<u32>,
166    /// Confirm times.
167    #[serde(default)]
168    pub confirm_times: Option<String>,
169    /// Unlock confirm.
170    #[serde(default)]
171    pub unlock_confirm: Option<u32>,
172    /// Unique ID.
173    #[serde(default)]
174    pub id: Option<String>,
175}
176
177/// Deposit status.
178#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
179#[repr(u8)]
180pub enum DepositStatus {
181    /// Pending
182    Pending = 0,
183    /// Success
184    Success = 1,
185    /// Success (credited but cannot withdraw)
186    CreditedCannotWithdraw = 6,
187}
188
189/// Withdrawal record from history.
190#[derive(Debug, Clone, Serialize, Deserialize)]
191#[serde(rename_all = "camelCase")]
192pub struct WithdrawRecord {
193    /// Withdrawal address.
194    pub address: String,
195    /// Amount.
196    #[serde(with = "string_or_float")]
197    pub amount: f64,
198    /// Apply time.
199    pub apply_time: String,
200    /// Coin symbol.
201    pub coin: String,
202    /// Withdrawal ID.
203    pub id: String,
204    /// Withdraw order ID (user-supplied).
205    #[serde(default)]
206    pub withdraw_order_id: Option<String>,
207    /// Network used.
208    pub network: String,
209    /// Transfer type.
210    #[serde(default)]
211    pub transfer_type: Option<u32>,
212    /// Status.
213    pub status: WithdrawStatus,
214    /// Transaction fee.
215    #[serde(with = "string_or_float")]
216    pub transaction_fee: f64,
217    /// Confirm number.
218    #[serde(default)]
219    pub confirm_no: Option<u32>,
220    /// Additional info.
221    #[serde(default)]
222    pub info: Option<String>,
223    /// Transaction ID.
224    #[serde(default)]
225    pub tx_id: Option<String>,
226}
227
228/// Withdrawal status.
229#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
230#[repr(u8)]
231pub enum WithdrawStatus {
232    /// Email sent
233    EmailSent = 0,
234    /// Cancelled
235    Cancelled = 1,
236    /// Awaiting approval
237    AwaitingApproval = 2,
238    /// Rejected
239    Rejected = 3,
240    /// Processing
241    Processing = 4,
242    /// Failure
243    Failure = 5,
244    /// Completed
245    Completed = 6,
246}
247
248/// Withdrawal request response.
249#[derive(Debug, Clone, Serialize, Deserialize)]
250pub struct WithdrawResponse {
251    /// Withdrawal ID.
252    pub id: String,
253}
254
255/// Asset detail information.
256#[derive(Debug, Clone, Serialize, Deserialize)]
257#[serde(rename_all = "camelCase")]
258pub struct AssetDetail {
259    /// Minimum withdrawal amount.
260    #[serde(with = "string_or_float")]
261    pub min_withdraw_amount: f64,
262    /// Whether deposit is enabled.
263    pub deposit_status: bool,
264    /// Withdrawal fee.
265    #[serde(with = "string_or_float")]
266    pub withdraw_fee: f64,
267    /// Whether withdrawal is enabled.
268    pub withdraw_status: bool,
269    /// Deposit tip (optional).
270    #[serde(default)]
271    pub deposit_tip: Option<String>,
272}
273
274/// Trade fee information.
275#[derive(Debug, Clone, Serialize, Deserialize)]
276#[serde(rename_all = "camelCase")]
277pub struct TradeFee {
278    /// Symbol.
279    pub symbol: String,
280    /// Maker commission.
281    #[serde(with = "string_or_float")]
282    pub maker_commission: f64,
283    /// Taker commission.
284    #[serde(with = "string_or_float")]
285    pub taker_commission: f64,
286}
287
288/// Universal transfer type.
289#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
290#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
291pub enum UniversalTransferType {
292    /// Spot to USDM Futures
293    MainUmfuture,
294    /// Spot to COINM Futures
295    MainCmfuture,
296    /// Spot to Margin (cross)
297    MainMargin,
298    /// USDM Futures to Spot
299    UmfutureMain,
300    /// USDM Futures to Margin (cross)
301    UmfutureMargin,
302    /// COINM Futures to Spot
303    CmfutureMain,
304    /// COINM Futures to Margin (cross)
305    CmfutureMargin,
306    /// Margin (cross) to Spot
307    MarginMain,
308    /// Margin (cross) to USDM Futures
309    MarginUmfuture,
310    /// Margin (cross) to COINM Futures
311    MarginCmfuture,
312    /// Spot to Isolated Margin
313    MainIsolatedMargin,
314    /// Isolated Margin to Spot
315    IsolatedMarginMain,
316    /// Isolated Margin to Isolated Margin
317    IsolatedMarginIsolatedMargin,
318    /// Spot to Funding
319    MainFunding,
320    /// Funding to Spot
321    FundingMain,
322    /// Funding to USDM Futures
323    FundingUmfuture,
324    /// USDM Futures to Funding
325    UmfutureFunding,
326    /// Margin (cross) to Funding
327    MarginFunding,
328    /// Funding to Margin (cross)
329    FundingMargin,
330    /// Funding to COINM Futures
331    FundingCmfuture,
332    /// COINM Futures to Funding
333    CmfutureFunding,
334}
335
336impl UniversalTransferType {
337    /// Return the API wire value for this transfer type.
338    pub fn as_str(self) -> &'static str {
339        match self {
340            Self::MainUmfuture => "MAIN_UMFUTURE",
341            Self::MainCmfuture => "MAIN_CMFUTURE",
342            Self::MainMargin => "MAIN_MARGIN",
343            Self::UmfutureMain => "UMFUTURE_MAIN",
344            Self::UmfutureMargin => "UMFUTURE_MARGIN",
345            Self::CmfutureMain => "CMFUTURE_MAIN",
346            Self::CmfutureMargin => "CMFUTURE_MARGIN",
347            Self::MarginMain => "MARGIN_MAIN",
348            Self::MarginUmfuture => "MARGIN_UMFUTURE",
349            Self::MarginCmfuture => "MARGIN_CMFUTURE",
350            Self::MainIsolatedMargin => "MAIN_ISOLATED_MARGIN",
351            Self::IsolatedMarginMain => "ISOLATED_MARGIN_MAIN",
352            Self::IsolatedMarginIsolatedMargin => "ISOLATED_MARGIN_ISOLATED_MARGIN",
353            Self::MainFunding => "MAIN_FUNDING",
354            Self::FundingMain => "FUNDING_MAIN",
355            Self::FundingUmfuture => "FUNDING_UMFUTURE",
356            Self::UmfutureFunding => "UMFUTURE_FUNDING",
357            Self::MarginFunding => "MARGIN_FUNDING",
358            Self::FundingMargin => "FUNDING_MARGIN",
359            Self::FundingCmfuture => "FUNDING_CMFUTURE",
360            Self::CmfutureFunding => "CMFUTURE_FUNDING",
361        }
362    }
363}
364
365/// Universal transfer response.
366#[derive(Debug, Clone, Serialize, Deserialize)]
367#[serde(rename_all = "camelCase")]
368pub struct TransferResponse {
369    /// Transaction ID.
370    pub tran_id: u64,
371}
372
373/// Universal transfer record.
374#[derive(Debug, Clone, Serialize, Deserialize)]
375#[serde(rename_all = "camelCase")]
376pub struct TransferRecord {
377    /// Asset.
378    pub asset: String,
379    /// Amount.
380    #[serde(with = "string_or_float")]
381    pub amount: f64,
382    /// Transfer type.
383    #[serde(rename = "type")]
384    pub transfer_type: UniversalTransferType,
385    /// Status.
386    pub status: String,
387    /// Transaction ID.
388    pub tran_id: u64,
389    /// Timestamp.
390    pub timestamp: u64,
391}
392
393/// Transfer history response (paginated).
394#[derive(Debug, Clone, Serialize, Deserialize)]
395#[serde(rename_all = "camelCase")]
396pub struct TransferHistory {
397    /// Total count.
398    pub total: u64,
399    /// Transfer records.
400    pub rows: Vec<TransferRecord>,
401}
402
403/// Wallet balance entry.
404#[derive(Debug, Clone, Serialize, Deserialize)]
405#[serde(rename_all = "camelCase")]
406pub struct WalletBalance {
407    /// Whether balance is active.
408    pub activate: bool,
409    /// Balance amount.
410    #[serde(with = "string_or_float")]
411    pub balance: f64,
412    /// Wallet name.
413    pub wallet_name: String,
414}
415
416/// Funding wallet asset.
417#[derive(Debug, Clone, Serialize, Deserialize)]
418#[serde(rename_all = "camelCase")]
419pub struct FundingAsset {
420    /// Asset.
421    pub asset: String,
422    /// Free balance.
423    #[serde(with = "string_or_float")]
424    pub free: f64,
425    /// Locked balance.
426    #[serde(with = "string_or_float")]
427    pub locked: f64,
428    /// Freeze balance.
429    #[serde(with = "string_or_float")]
430    pub freeze: f64,
431    /// Withdrawing balance.
432    #[serde(with = "string_or_float")]
433    pub withdrawing: f64,
434    /// BTC valuation (optional).
435    #[serde(default, with = "string_or_float_option")]
436    pub btc_valuation: Option<f64>,
437}
438
439/// Account snapshot type.
440#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
441#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
442pub enum AccountSnapshotType {
443    /// Spot account
444    Spot,
445    /// Margin account
446    Margin,
447    /// Futures account
448    Futures,
449}
450
451/// Account snapshot response.
452#[derive(Debug, Clone, Serialize, Deserialize)]
453#[serde(rename_all = "camelCase")]
454pub struct AccountSnapshot {
455    /// Response code.
456    pub code: i32,
457    /// Response message.
458    pub msg: String,
459    /// Snapshot data.
460    pub snapshot_vos: Vec<SnapshotData>,
461}
462
463/// Snapshot data entry.
464#[derive(Debug, Clone, Serialize, Deserialize)]
465#[serde(rename_all = "camelCase")]
466pub struct SnapshotData {
467    /// Snapshot type.
468    #[serde(rename = "type")]
469    pub snapshot_type: String,
470    /// Update time.
471    pub update_time: u64,
472    /// Snapshot data (varies by type).
473    pub data: serde_json::Value,
474}
475
476/// API key permissions.
477#[derive(Debug, Clone, Serialize, Deserialize)]
478#[serde(rename_all = "camelCase")]
479pub struct ApiKeyPermissions {
480    /// Whether IP restricted.
481    pub ip_restrict: bool,
482    /// Creation time.
483    pub create_time: u64,
484    /// Whether spot trading is enabled.
485    pub enable_spot_and_margin_trading: bool,
486    /// Whether withdrawals are enabled.
487    pub enable_withdrawals: bool,
488    /// Whether internal transfers are enabled.
489    pub enable_internal_transfer: bool,
490    /// Permits universal transfer.
491    pub permits_universal_transfer: bool,
492    /// Whether vanilla options are enabled.
493    pub enable_vanilla_options: bool,
494    /// Whether reading is enabled.
495    pub enable_reading: bool,
496    /// Whether futures trading is enabled.
497    pub enable_futures: bool,
498    /// Whether margin loan/borrow/repay is enabled.
499    pub enable_margin: bool,
500    /// Trading authority expiration time.
501    #[serde(default)]
502    pub trading_authority_expiration_time: Option<u64>,
503}
504
505/// Account status.
506#[derive(Debug, Clone, Serialize, Deserialize)]
507#[serde(rename_all = "camelCase")]
508pub struct AccountStatus {
509    /// Account status data.
510    pub data: String,
511}
512
513/// API trading status.
514#[derive(Debug, Clone, Serialize, Deserialize)]
515#[serde(rename_all = "camelCase")]
516pub struct ApiTradingStatus {
517    /// Status data.
518    pub data: ApiTradingStatusData,
519}
520
521/// API trading status data.
522#[derive(Debug, Clone, Serialize, Deserialize)]
523#[serde(rename_all = "camelCase")]
524pub struct ApiTradingStatusData {
525    /// Is locked.
526    pub is_locked: bool,
527    /// Planned recovery time (if locked).
528    #[serde(default)]
529    pub planned_recover_time: Option<u64>,
530    /// Trigger condition.
531    pub trigger_condition: serde_json::Value,
532    /// Update time.
533    pub update_time: u64,
534}
535
536/// Helper for optional f64 fields that may be strings.
537mod string_or_float_option {
538    use serde::{self, Deserialize, Deserializer, Serializer};
539
540    pub fn serialize<S>(value: &Option<f64>, serializer: S) -> Result<S::Ok, S::Error>
541    where
542        S: Serializer,
543    {
544        match value {
545            Some(v) => serializer.serialize_str(&v.to_string()),
546            None => serializer.serialize_none(),
547        }
548    }
549
550    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
551    where
552        D: Deserializer<'de>,
553    {
554        #[derive(Deserialize)]
555        #[serde(untagged)]
556        enum StringOrFloat {
557            String(String),
558            Float(f64),
559        }
560
561        let opt: Option<StringOrFloat> = Option::deserialize(deserializer)?;
562        match opt {
563            Some(StringOrFloat::Float(f)) => Ok(Some(f)),
564            Some(StringOrFloat::String(s)) => {
565                s.parse::<f64>().map(Some).map_err(serde::de::Error::custom)
566            }
567            None => Ok(None),
568        }
569    }
570}