casper_rust_wasm_sdk/sdk/rpcs/
get_account.rs

1#[cfg(target_arch = "wasm32")]
2use crate::types::identifier::block_identifier::BlockIdentifier;
3use crate::{
4    types::{
5        identifier::{
6            account_identifier::AccountIdentifier, block_identifier::BlockIdentifierInput,
7        },
8        sdk_error::SdkError,
9        verbosity::Verbosity,
10    },
11    SDK,
12};
13use casper_client::cli::parse::account_identifier as parse_account_identifier;
14use casper_client::{
15    cli::get_account as get_account_cli, get_account as get_account_lib,
16    rpcs::results::GetAccountResult as _GetAccountResult, JsonRpcId, SuccessResponse,
17};
18#[cfg(target_arch = "wasm32")]
19use gloo_utils::format::JsValueSerdeExt;
20use rand::Rng;
21#[cfg(target_arch = "wasm32")]
22use serde::{Deserialize, Serialize};
23#[cfg(target_arch = "wasm32")]
24use wasm_bindgen::prelude::*;
25
26// Define the GetAccountResult struct to wrap the result from Casper Client RPC call
27#[cfg(target_arch = "wasm32")]
28#[derive(Debug, Deserialize, Clone, Serialize)]
29#[wasm_bindgen]
30pub struct GetAccountResult(_GetAccountResult);
31
32// Implement conversions between GetAccountResult and _GetAccountResult
33#[cfg(target_arch = "wasm32")]
34impl From<GetAccountResult> for _GetAccountResult {
35    fn from(result: GetAccountResult) -> Self {
36        result.0
37    }
38}
39
40#[cfg(target_arch = "wasm32")]
41impl From<_GetAccountResult> for GetAccountResult {
42    fn from(result: _GetAccountResult) -> Self {
43        GetAccountResult(result)
44    }
45}
46
47#[cfg(target_arch = "wasm32")]
48#[wasm_bindgen]
49impl GetAccountResult {
50    // Define getters for various fields of GetAccountResult
51    #[wasm_bindgen(getter)]
52    pub fn api_version(&self) -> JsValue {
53        JsValue::from_serde(&self.0.api_version).unwrap()
54    }
55
56    #[wasm_bindgen(getter)]
57    pub fn account(&self) -> JsValue {
58        JsValue::from_serde(&self.0.account).unwrap()
59    }
60
61    #[wasm_bindgen(getter)]
62    pub fn merkle_proof(&self) -> String {
63        self.0.merkle_proof.clone()
64    }
65
66    #[wasm_bindgen(js_name = "toJson")]
67    pub fn to_json(&self) -> JsValue {
68        JsValue::from_serde(&self.0).unwrap_or(JsValue::null())
69    }
70}
71
72// Define options for the `get_account` function
73#[derive(Debug, Deserialize, Clone, Default, Serialize)]
74#[cfg(target_arch = "wasm32")]
75#[wasm_bindgen(js_name = "getAccountOptions", getter_with_clone)]
76pub struct GetAccountOptions {
77    pub account_identifier: Option<AccountIdentifier>,
78    pub account_identifier_as_string: Option<String>,
79    pub maybe_block_id_as_string: Option<String>,
80    pub maybe_block_identifier: Option<BlockIdentifier>,
81    pub rpc_address: Option<String>,
82    pub verbosity: Option<Verbosity>,
83}
84
85#[cfg(target_arch = "wasm32")]
86#[wasm_bindgen]
87impl SDK {
88    // Deserialize options for `get_account` from a JavaScript object
89    #[deprecated(note = "prefer 'get_entity_options'")]
90    #[allow(deprecated)]
91    pub fn get_account_options(&self, options: JsValue) -> Result<GetAccountOptions, JsError> {
92        options
93            .into_serde::<GetAccountOptions>()
94            .map_err(|err| JsError::new(&format!("Error deserializing options: {:?}", err)))
95    }
96
97    /// Retrieves account information using the provided options.
98    ///
99    /// This function is an asynchronous JavaScript binding for the Rust `get_account` method.
100    ///
101    /// # Arguments
102    ///
103    /// * `options` - An optional `GetAccountOptions` struct containing retrieval options, such as:
104    ///   - `account_identifier`: Identifier for the account.
105    ///   - `account_identifier_as_string`: String representation of the account identifier.
106    ///   - `maybe_block_id_as_string`: Optional string representation of the block ID.
107    ///   - `maybe_block_identifier`: Optional `BlockIdentifierInput` for specifying the block.
108    ///   - `verbosity`: Verbosity level for the output.
109    ///   - `rpc_address`: Address of the node to query.
110    ///
111    /// # Returns
112    ///
113    /// A `Result` containing either a `GetAccountResult` on success or a `JsError` on failure.
114    ///
115    /// # Errors
116    ///
117    /// Returns a `JsError` if there is an error during the retrieval process, such as issues with the provided options or network errors.
118    /// ```
119    #[wasm_bindgen(js_name = "get_account")]
120    #[deprecated(note = "prefer 'get_entity'")]
121    #[allow(deprecated)]
122    pub async fn get_account_js_alias(
123        &self,
124        options: Option<GetAccountOptions>,
125    ) -> Result<GetAccountResult, JsError> {
126        let GetAccountOptions {
127            account_identifier,
128            account_identifier_as_string,
129            maybe_block_id_as_string,
130            maybe_block_identifier,
131            verbosity,
132            rpc_address,
133        } = options.unwrap_or_default();
134
135        let maybe_block_identifier = if let Some(maybe_block_identifier) = maybe_block_identifier {
136            Some(BlockIdentifierInput::BlockIdentifier(
137                maybe_block_identifier,
138            ))
139        } else {
140            maybe_block_id_as_string.map(BlockIdentifierInput::String)
141        };
142
143        let result = self
144            .get_account(
145                account_identifier,
146                account_identifier_as_string,
147                maybe_block_identifier,
148                verbosity,
149                rpc_address,
150            )
151            .await;
152        match result {
153            Ok(data) => Ok(data.result.into()),
154            Err(err) => {
155                let err = &format!("Error occurred with {:?}", err);
156                Err(JsError::new(err))
157            }
158        }
159    }
160
161    // JavaScript alias for `get_account`
162    #[wasm_bindgen(js_name = "state_get_account_info")]
163    #[deprecated(note = "prefer 'get_entity'")]
164    #[allow(deprecated)]
165    pub async fn state_get_account_info(
166        &self,
167        options: Option<GetAccountOptions>,
168    ) -> Result<GetAccountResult, JsError> {
169        self.get_account_js_alias(options).await
170    }
171}
172
173impl SDK {
174    /// Retrieves account information based on the provided options.
175    ///
176    /// # Arguments
177    ///
178    /// * `account_identifier` - An optional `AccountIdentifier` for specifying the account identifier.
179    /// * `account_identifier_as_string` - An optional string representing the account identifier.
180    /// * `maybe_block_identifier` - An optional `BlockIdentifierInput` for specifying a block identifier.
181    /// * `verbosity` - An optional `Verbosity` level for controlling the output verbosity.
182    /// * `rpc_address` - An optional string specifying the rpc address to use for the request.
183    ///
184    /// # Returns
185    ///
186    /// A `Result` containing either a `SuccessResponse<_GetAccountResult>` or a `SdkError` in case of an error.
187    ///
188    /// # Errors
189    ///
190    /// Returns a `SdkError` if there is an error during the retrieval process.
191    #[deprecated(note = "prefer 'get_entity'")]
192    #[allow(deprecated)]
193    pub async fn get_account(
194        &self,
195        account_identifier: Option<AccountIdentifier>,
196        account_identifier_as_string: Option<String>,
197        maybe_block_identifier: Option<BlockIdentifierInput>,
198        verbosity: Option<Verbosity>,
199        rpc_address: Option<String>,
200    ) -> Result<SuccessResponse<_GetAccountResult>, SdkError> {
201        let account_identifier = if let Some(account_identifier) = account_identifier {
202            account_identifier
203        } else if let Some(account_identifier_as_string) = account_identifier_as_string.clone() {
204            match parse_account_identifier(&account_identifier_as_string) {
205                Ok(parsed) => parsed.into(),
206                Err(err) => {
207                    return Err(err.into());
208                }
209            }
210        } else {
211            let err = "Error: Missing account identifier".to_string();
212            return Err(SdkError::InvalidArgument {
213                context: "get_account",
214                error: err,
215            });
216        };
217        if let Some(BlockIdentifierInput::String(maybe_block_id)) = maybe_block_identifier {
218            get_account_cli(
219                &rand::thread_rng().gen::<u64>().to_string(),
220                &self.get_rpc_address(rpc_address),
221                self.get_verbosity(verbosity).into(),
222                &maybe_block_id,
223                &account_identifier.to_string(),
224            )
225            .await
226            .map_err(SdkError::from)
227        } else {
228            let maybe_block_identifier =
229                if let Some(BlockIdentifierInput::BlockIdentifier(maybe_block_identifier)) =
230                    maybe_block_identifier
231                {
232                    Some(maybe_block_identifier)
233                } else {
234                    None
235                };
236            get_account_lib(
237                JsonRpcId::from(rand::thread_rng().gen::<u64>().to_string()),
238                &self.get_rpc_address(rpc_address),
239                self.get_verbosity(verbosity).into(),
240                maybe_block_identifier.map(Into::into),
241                account_identifier.into(),
242            )
243            .await
244            .map_err(SdkError::from)
245        }
246    }
247}
248
249#[cfg(test)]
250mod tests {
251    use super::*;
252    use crate::{
253        helpers::public_key_from_secret_key,
254        types::{identifier::block_identifier::BlockIdentifier, public_key::PublicKey},
255    };
256    use sdk_tests::tests::helpers::{
257        get_enable_addressable_entity, get_network_constants, get_user_secret_key,
258    };
259
260    #[allow(deprecated)]
261    fn get_account_identifier() -> AccountIdentifier {
262        let secret_key = get_user_secret_key(None).unwrap();
263        let account = public_key_from_secret_key(&secret_key).unwrap();
264        let public_key = PublicKey::new(&account).unwrap();
265
266        AccountIdentifier::from_account_under_public_key(public_key)
267    }
268
269    #[tokio::test]
270    #[allow(deprecated)]
271    async fn test_get_account_with_none_values() {
272        // Arrange
273        let sdk = SDK::new(None, None, None);
274        let error_message = "failed to parse node address as valid URL";
275        let account_identifier = get_account_identifier();
276
277        // Act
278        let result = sdk
279            .get_account(Some(account_identifier), None, None, None, None)
280            .await;
281
282        // Assert
283        assert!(result.is_err());
284        let err_string = result.err().unwrap().to_string();
285        assert!(err_string.contains(error_message));
286    }
287
288    #[tokio::test]
289    #[allow(deprecated)]
290    async fn test_get_account_with_missing_account() {
291        // Arrange
292        let sdk = SDK::new(None, None, None);
293        let error_message = "Error: Missing account identifier";
294
295        // Act
296        let result = sdk.get_account(None, None, None, None, None).await;
297
298        // Assert
299        assert!(result.is_err());
300        let err_string = result.err().unwrap().to_string();
301        assert!(err_string.contains(error_message));
302    }
303
304    #[tokio::test]
305    #[allow(deprecated)]
306    async fn _test_get_account_with_account_identifier() {
307        if get_enable_addressable_entity() {
308            return;
309        }
310        // Arrange
311        let sdk = SDK::new(None, None, None);
312        let account_identifier = get_account_identifier();
313        let verbosity = Some(Verbosity::High);
314        let (rpc_address, _, _, _, _) = get_network_constants();
315
316        // Act
317        let result = sdk
318            .get_account(
319                Some(account_identifier),
320                None,
321                None,
322                verbosity,
323                Some(rpc_address),
324            )
325            .await;
326        // Assert
327        assert!(result.is_ok());
328    }
329
330    #[tokio::test]
331    #[allow(deprecated)]
332    async fn _test_get_account_with_account_identifier_as_string() {
333        if get_enable_addressable_entity() {
334            return;
335        }
336        // Arrange
337        let sdk = SDK::new(None, None, None);
338        let account_identifier_as_string = get_account_identifier().to_string();
339        let verbosity = Some(Verbosity::High);
340        let (rpc_address, _, _, _, _) = get_network_constants();
341
342        // Act
343        let result = sdk
344            .get_account(
345                None,
346                Some(account_identifier_as_string),
347                None,
348                verbosity,
349                Some(rpc_address),
350            )
351            .await;
352
353        // Assert
354        assert!(result.is_ok());
355    }
356
357    #[tokio::test]
358    #[allow(deprecated)]
359    async fn _test_get_account_with_block_identifier() {
360        if get_enable_addressable_entity() {
361            return;
362        }
363        // Arrange
364        let sdk = SDK::new(None, None, None);
365        let block_identifier =
366            BlockIdentifierInput::BlockIdentifier(BlockIdentifier::from_height(1));
367        let account_identifier = get_account_identifier();
368        let verbosity = Some(Verbosity::High);
369        let (rpc_address, _, _, _, _) = get_network_constants();
370
371        // Act
372        let result = sdk
373            .get_account(
374                Some(account_identifier),
375                None,
376                Some(block_identifier),
377                verbosity,
378                Some(rpc_address),
379            )
380            .await;
381
382        // Assert
383        assert!(result.is_ok());
384    }
385
386    #[tokio::test]
387    #[allow(deprecated)]
388    async fn test_get_account_with_error() {
389        // Arrange
390        let sdk = SDK::new(Some("http://localhost".to_string()), None, None);
391        let account_identifier = get_account_identifier();
392        let error_message = "error sending request for url (http://localhost/rpc)";
393
394        // Act
395        let result = sdk
396            .get_account(Some(account_identifier), None, None, None, None)
397            .await;
398
399        // Assert
400        assert!(result.is_err());
401        let err_string = result.err().unwrap().to_string();
402        assert!(err_string.contains(error_message));
403    }
404}