1use crate::{Error, GoldRushClient};
2use crate::models::balances::BalancesResponse;
3use reqwest::Method;
4
5#[derive(Debug, Clone, Default)]
7pub struct BalancesOptions {
8 pub quote_currency: Option<String>,
10
11 pub nft: Option<bool>,
13
14 pub no_spam: Option<bool>,
16
17 pub page_number: Option<u32>,
19
20 pub page_size: Option<u32>,
22}
23
24impl BalancesOptions {
25 pub fn new() -> Self {
27 Self::default()
28 }
29
30 pub fn quote_currency<S: Into<String>>(mut self, currency: S) -> Self {
32 self.quote_currency = Some(currency.into());
33 self
34 }
35
36 pub fn nft(mut self, include_nft: bool) -> Self {
38 self.nft = Some(include_nft);
39 self
40 }
41
42 pub fn no_spam(mut self, exclude_spam: bool) -> Self {
44 self.no_spam = Some(exclude_spam);
45 self
46 }
47
48 pub fn page_number(mut self, page: u32) -> Self {
50 self.page_number = Some(page);
51 self
52 }
53
54 pub fn page_size(mut self, size: u32) -> Self {
56 self.page_size = Some(size);
57 self
58 }
59}
60
61impl GoldRushClient {
62 pub async fn get_token_balances_for_wallet_address(
91 &self,
92 chain_name: &str,
93 address: &str,
94 options: Option<BalancesOptions>,
95 ) -> Result<BalancesResponse, Error> {
96 let path = format!("/v1/{}/address/{}/balances_v2/", chain_name, address);
98
99 let mut builder = self.build_request(Method::GET, &path);
100
101 if let Some(opts) = options {
103 if let Some(currency) = opts.quote_currency {
104 builder = builder.query(&[("quote-currency", currency)]);
105 }
106 if let Some(include_nft) = opts.nft {
107 builder = builder.query(&[("nft", include_nft.to_string())]);
108 }
109 if let Some(no_spam) = opts.no_spam {
110 builder = builder.query(&[("no-spam", no_spam.to_string())]);
111 }
112 if let Some(page_num) = opts.page_number {
113 builder = builder.query(&[("page-number", page_num.to_string())]);
114 }
115 if let Some(page_sz) = opts.page_size {
116 builder = builder.query(&[("page-size", page_sz.to_string())]);
117 }
118 }
119
120 self.send_with_retry(builder).await
121 }
122
123 pub async fn get_historical_portfolio_for_wallet_address(
148 &self,
149 chain_name: &str,
150 address: &str,
151 options: Option<BalancesOptions>,
152 ) -> Result<BalancesResponse, Error> {
153 let path = format!("/v1/{}/address/{}/portfolio_v2/", chain_name, address);
155
156 let mut builder = self.build_request(Method::GET, &path);
157
158 if let Some(opts) = options {
159 if let Some(currency) = opts.quote_currency {
160 builder = builder.query(&[("quote-currency", currency)]);
161 }
162 if let Some(page_num) = opts.page_number {
163 builder = builder.query(&[("page-number", page_num.to_string())]);
164 }
165 if let Some(page_sz) = opts.page_size {
166 builder = builder.query(&[("page-size", page_sz.to_string())]);
167 }
168 }
169
170 self.send_with_retry(builder).await
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177 use serde_json::json;
178
179 #[test]
180 fn test_balances_options_builder() {
181 let options = BalancesOptions::new()
182 .quote_currency("USD")
183 .nft(true)
184 .no_spam(true)
185 .page_size(50);
186
187 assert_eq!(options.quote_currency, Some("USD".to_string()));
188 assert_eq!(options.nft, Some(true));
189 assert_eq!(options.no_spam, Some(true));
190 assert_eq!(options.page_size, Some(50));
191 }
192
193 #[test]
194 fn test_deserialize_balances_response() {
195 let json_data = json!({
196 "data": {
197 "address": "0x123",
198 "chain_id": 1,
199 "items": [{
200 "contract_address": "0xA0b86a33E6441e6b32f6aDaa51a3FC6F1b6a3B9a",
201 "contract_ticker_symbol": "COVALENT",
202 "contract_name": "Covalent Query Token",
203 "balance": "1000000000000000000",
204 "quote_rate": 1.23,
205 "quote": 1.23,
206 "token_type": "cryptocurrency",
207 "is_spam": false,
208 "contract_decimals": 18
209 }]
210 },
211 "error": null,
212 "pagination": {
213 "has_more": false,
214 "page_number": 0,
215 "page_size": 100,
216 "total_count": 1
217 }
218 });
219
220 let response: BalancesResponse = serde_json::from_value(json_data).unwrap();
221 assert!(response.data.is_some());
222
223 let data = response.data.unwrap();
224 assert_eq!(data.items.len(), 1);
225 assert_eq!(data.items[0].contract_ticker_symbol, Some("COVALENT".to_string()));
226 assert_eq!(data.items[0].balance, "1000000000000000000");
227 }
228}