onemoney_protocol/api/
accounts.rs

1//! Account-related API operations.
2
3use crate::client::Client;
4use crate::client::config::api_path;
5use crate::client::config::endpoints::accounts::{NONCE, TOKEN_ACCOUNT};
6use crate::{AccountNonce, AssociatedTokenAccount, Result};
7use alloy_primitives::Address;
8
9impl Client {
10    /// Get the nonce for an account.
11    ///
12    /// # Arguments
13    ///
14    /// * `address` - The account address to query
15    ///
16    /// # Returns
17    ///
18    /// The account nonce information.
19    ///
20    /// # Example
21    ///
22    /// ```rust,no_run
23    /// use onemoney_protocol::Client;
24    /// use alloy_primitives::Address;
25    /// use std::str::FromStr;
26    ///
27    /// #[tokio::main]
28    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
29    ///     let client = Client::mainnet()?;
30    ///     let address = Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0")?;
31    ///
32    ///     let nonce = client.get_account_nonce(address).await?;
33    ///     println!("Account nonce: {}", nonce.nonce);
34    ///
35    ///     Ok(())
36    /// }
37    /// ```
38    pub async fn get_account_nonce(&self, address: Address) -> Result<AccountNonce> {
39        let path = api_path(&format!("{NONCE}?address={address}"));
40        self.get(&path).await
41    }
42
43    /// Get associated token account information for a specific address and token.
44    ///
45    /// This method queries the L1 server's `/v1/accounts/token_account` endpoint
46    /// to retrieve token account details including balance and nonce.
47    ///
48    /// # Arguments
49    ///
50    /// * `address` - The wallet owner address
51    /// * `token` - The token mint address
52    ///
53    /// # Returns
54    ///
55    /// The associated token account information.
56    ///
57    /// # Example
58    ///
59    /// ```rust,no_run
60    /// use onemoney_protocol::Client;
61    /// use alloy_primitives::Address;
62    /// use std::str::FromStr;
63    ///
64    /// #[tokio::main]
65    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
66    ///     let client = Client::mainnet()?;
67    ///     let address = Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0")?;
68    ///     let token = Address::from_str("0x1234567890abcdef1234567890abcdef12345678")?;
69    ///
70    ///     let account = client.get_associated_token_account(address, token).await?;
71    ///     println!("Token balance: {}", account.balance);
72    ///
73    ///     Ok(())
74    /// }
75    /// ```
76    pub async fn get_associated_token_account(
77        &self,
78        address: Address,
79        token: Address,
80    ) -> Result<AssociatedTokenAccount> {
81        let path = api_path(&format!("{TOKEN_ACCOUNT}?address={address}&token={token}"));
82        self.get(&path).await
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89    use crate::client::config::api_path;
90    use alloy_primitives::Address;
91    use std::str::FromStr;
92
93    #[test]
94    fn test_nonce_api_path_construction() {
95        let address = Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0")
96            .expect("Test data should be valid");
97        let expected_path = api_path(&format!("{NONCE}?address={address}"));
98
99        assert!(expected_path.contains("/accounts/nonce"));
100        assert!(expected_path.contains("address=0x742d35Cc6634c0532925a3b8D91D6f4a81B8cbc0"));
101    }
102
103    #[test]
104    fn test_token_account_api_path_construction() {
105        let address = Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0")
106            .expect("Test data should be valid");
107        let token = Address::from_str("0x1234567890abcdef1234567890abcdef12345678")
108            .expect("Test data should be valid");
109        let expected_path = api_path(&format!("{TOKEN_ACCOUNT}?address={address}&token={token}"));
110
111        assert!(expected_path.contains("/accounts/token_account"));
112        assert!(expected_path.contains("address=0x742d35Cc6634c0532925a3b8D91D6f4a81B8cbc0"));
113        assert!(expected_path.contains("token=0x1234567890AbcdEF1234567890aBcdef12345678"));
114    }
115
116    #[test]
117    fn test_account_nonce_display() {
118        let nonce = AccountNonce { nonce: 42 };
119        let display_str = format!("{}", nonce);
120        assert_eq!(display_str, "Account Nonce: 42");
121    }
122
123    #[test]
124    fn test_associated_token_account_display() {
125        let address = Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0")
126            .expect("Test data should be valid");
127        let account = AssociatedTokenAccount {
128            token_account_address: address,
129            balance: "1000000000000000000".to_string(),
130            nonce: 5,
131        };
132
133        let display_str = format!("{}", account);
134        assert!(display_str.contains("Associated Token Account"));
135        assert!(display_str.contains("Address: 0x742d35Cc6634c0532925a3b8D91D6f4a81B8cbc0"));
136        assert!(display_str.contains("Balance: 1000000000000000000"));
137        assert!(display_str.contains("Nonce: 5"));
138    }
139
140    #[test]
141    fn test_associated_token_account_equality() {
142        let address1 = Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0")
143            .expect("Test data should be valid");
144        let address2 = Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0")
145            .expect("Test data should be valid");
146
147        let account1 = AssociatedTokenAccount {
148            token_account_address: address1,
149            balance: "1000000000000000000".to_string(),
150            nonce: 5,
151        };
152
153        let account2 = AssociatedTokenAccount {
154            token_account_address: address2,
155            balance: "1000000000000000000".to_string(),
156            nonce: 5,
157        };
158
159        assert_eq!(account1, account2);
160    }
161
162    #[test]
163    fn test_associated_token_account_clone() {
164        let address = Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0")
165            .expect("Test data should be valid");
166        let account = AssociatedTokenAccount {
167            token_account_address: address,
168            balance: "1000000000000000000".to_string(),
169            nonce: 5,
170        };
171
172        let cloned = account.clone();
173        assert_eq!(account, cloned);
174    }
175
176    #[test]
177    fn test_associated_token_account_default() {
178        let account = AssociatedTokenAccount::default();
179        assert_eq!(account.token_account_address, Address::default());
180        assert_eq!(account.balance, String::default());
181        assert_eq!(account.nonce, 0);
182    }
183}