crypto_pay_api/api/
balance.rs

1use async_trait::async_trait;
2
3use crate::{
4    client::CryptoBot,
5    error::CryptoBotError,
6    models::{APIEndpoint, APIMethod, Balance, Method},
7};
8
9use super::BalanceAPI;
10
11#[async_trait]
12impl BalanceAPI for CryptoBot {
13    /// Gets current balance for all supported cryptocurrencies in your CryptoBot wallet
14    ///
15    /// This method returns the current balance for all cryptocurrencies that are
16    /// available in your CryptoBot wallet, including both crypto and test currencies.
17    ///
18    /// # Returns
19    /// * `Ok(Vec<Balance>)` - A vector of balances for each currency
20    /// * `Err(CryptoBotError)` - If the request fails
21    ///
22    /// # Errors
23    /// This method will return an error if:
24    /// * The API request fails
25    /// * The response cannot be parsed
26    /// * The API token is invalid
27    ///
28    /// # Example
29    /// ```no_run
30    /// use crypto_pay_api::prelude::*;
31    ///
32    /// #[tokio::main]
33    /// async fn main() -> Result<(), CryptoBotError> {
34    ///     let client = CryptoBot::builder().api_token("YOUR_API_TOKEN").build().unwrap();
35    ///     
36    ///     let balances = client.get_balance().await?;
37    ///     
38    ///     for balance in balances {
39    ///         println!("Available: {}", balance.available);
40    ///     }
41    ///     
42    ///     Ok(())
43    /// }
44    /// ```
45    ///
46    /// # See Also
47    /// * [Balance](struct.Balance.html) - The structure representing a currency balance
48    /// * [CryptoBot API Documentation](https://help.crypt.bot/crypto-pay-api#getBalance)
49    async fn get_balance(&self) -> Result<Vec<Balance>, CryptoBotError> {
50        self.make_request(
51            &APIMethod {
52                endpoint: APIEndpoint::GetBalance,
53                method: Method::GET,
54            },
55            None::<()>.as_ref(),
56        )
57        .await
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use mockito::Mock;
64    use rust_decimal_macros::dec;
65    use serde_json::json;
66
67    use crate::{models::CryptoCurrencyCode, utils::test_utils::TestContext};
68
69    use super::*;
70
71    impl TestContext {
72        pub fn mock_balance_response(&mut self) -> Mock {
73            self.server
74                .mock("GET", "/getBalance")
75                .with_header("content-type", "application/json")
76                .with_header("Crypto-Pay-API-Token", "test_token")
77                .with_body(
78                    json!({
79                        "ok": true,
80                        "result": [
81                        {
82                            "currency_code": "TON",
83                            "available": "100.5",
84                            "onhold": "0.0"
85                        },
86                        {
87                            "currency_code": "SEND",
88                            "available": "10.5",
89                            "onhold": "0.0"
90                        }
91                        ]
92                    })
93                    .to_string(),
94                )
95                .create()
96        }
97    }
98
99    #[test]
100    fn test_get_balance() {
101        let mut ctx = TestContext::new();
102        let _m = ctx.mock_balance_response();
103
104        let client = CryptoBot::builder()
105            .api_token("api_token")
106            .base_url(ctx.server.url())
107            .build()
108            .unwrap();
109
110        let result = ctx.run(async { client.get_balance().await });
111
112        assert!(result.is_ok());
113        let balances = result.unwrap();
114        assert_eq!(balances.len(), 2);
115        assert_eq!(balances[0].currency_code, CryptoCurrencyCode::Ton);
116        assert_eq!(balances[0].available, dec!(100.5));
117        assert_eq!(balances[1].currency_code, CryptoCurrencyCode::Send);
118        assert_eq!(balances[1].available, dec!(10.5));
119    }
120}