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}