1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
//! Binance exchange account information and balances.

#![allow(dead_code)]

use std::convert::TryFrom;

use hashbrown::HashMap;

use cxmr_api_clients_errors::Error;
use cxmr_balances::{points, Balance};
use cxmr_exchanges::AccountInfo;

#[derive(Deserialize)]
pub struct BncAccount {
    #[serde(rename = "makerCommission")]
    maker_commission: u64,
    #[serde(rename = "takerCommission")]
    taker_commission: u64,
    #[serde(rename = "buyerCommission")]
    buyer_commission: u64,
    #[serde(rename = "sellerCommission")]
    seller_commission: u64,
    #[serde(rename = "canTrade")]
    can_trade: bool,
    #[serde(rename = "canWithdraw")]
    can_withdraw: bool,
    #[serde(rename = "canDeposit")]
    can_deposit: bool,
    #[serde(rename = "updateTime")]
    update_time: u64,
    balances: Vec<BncBalance>,
}

impl ::std::convert::TryFrom<BncAccount> for AccountInfo {
    type Error = Error;
    #[inline]
    fn try_from(acc: BncAccount) -> Result<AccountInfo, Error> {
        let mut balances = HashMap::new();
        acc.balances.into_iter().for_each(|b| {
            let bnc = Balance::try_from(&b).unwrap();
            balances.insert(b.asset.as_str().into(), bnc);
        });
        Ok(AccountInfo {
            account: "".to_owned(),
            maker_fee_rate: acc.maker_commission,
            taker_fee_rate: acc.taker_commission,
            can_trade: acc.can_trade,
            balances: balances,
            updated_at: acc.update_time,
        })
    }
}

#[derive(Deserialize)]
pub struct BncBalance {
    asset: String,
    free: String,
    locked: String,
}

impl TryFrom<&BncBalance> for Balance {
    type Error = Error;
    #[inline]
    fn try_from(b: &BncBalance) -> Result<Balance, Error> {
        let unused = points(b.free.parse()?);
        let in_use = points(b.locked.parse()?);
        Ok(Balance {
            total: unused + in_use,
            unused: unused,
            in_use: in_use,
            total_btc: None,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;

    use cxmr_currency::Currency;

    #[bench]
    fn find_balance_map(b: &mut Bencher) {
        let account: BncAccount =
            ::serde_json::from_str(include_str!("../../../testdata/account.v3.json")).unwrap();
        let account = AccountInfo::try_from(account).unwrap();
        b.iter(|| {
            let _balance = account.balances.get(&Currency::Usdc).unwrap();
            let _balance = account.balances.get(&Currency::Btc).unwrap();
        });
    }

    #[test]
    fn get_balance() {
        let account: BncAccount =
            ::serde_json::from_str(include_str!("../../../testdata/account.v3.json")).unwrap();
        let account = AccountInfo::try_from(account).unwrap();
        let balance = account.balances.get(&Currency::Btc).unwrap();
        assert_eq!(1, balance.in_use);
        assert_eq!(2452, balance.unused);
        let balance = account.balances.get(&Currency::Eth).unwrap();
        assert_eq!(0, balance.in_use);
        assert_eq!(805792263, balance.unused);
        let balance = account.balances.get(&Currency::Bnb).unwrap();
        assert_eq!(0, balance.in_use);
        assert_eq!(362829719, balance.unused);
        let balance = account.balances.get(&Currency::Bchabc).unwrap();
        assert_eq!(0, balance.in_use);
        assert_eq!(192000000, balance.unused);
    }
}