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        let random_id = rand::thread_rng().gen::<u64>().to_string();
218        if let Some(BlockIdentifierInput::String(maybe_block_id)) = maybe_block_identifier {
219            get_account_cli(
220                &random_id,
221                &self.get_rpc_address(rpc_address),
222                self.get_verbosity(verbosity).into(),
223                &maybe_block_id,
224                &account_identifier.to_string(),
225            )
226            .await
227            .map_err(SdkError::from)
228        } else {
229            let maybe_block_identifier =
230                if let Some(BlockIdentifierInput::BlockIdentifier(maybe_block_identifier)) =
231                    maybe_block_identifier
232                {
233                    Some(maybe_block_identifier)
234                } else {
235                    None
236                };
237            get_account_lib(
238                JsonRpcId::from(random_id),
239                &self.get_rpc_address(rpc_address),
240                self.get_verbosity(verbosity).into(),
241                maybe_block_identifier.map(Into::into),
242                account_identifier.into(),
243            )
244            .await
245            .map_err(SdkError::from)
246        }
247    }
248}
249
250#[cfg(test)]
251mod tests {
252    use super::*;
253    use crate::{
254        helpers::public_key_from_secret_key,
255        types::{identifier::block_identifier::BlockIdentifier, public_key::PublicKey},
256    };
257    use sdk_tests::tests::helpers::{
258        get_enable_addressable_entity, get_network_constants, get_user_secret_key,
259    };
260
261    #[allow(deprecated)]
262    fn get_account_identifier() -> AccountIdentifier {
263        let secret_key = get_user_secret_key(None).unwrap();
264        let account = public_key_from_secret_key(&secret_key).unwrap();
265        let public_key = PublicKey::new(&account).unwrap();
266
267        AccountIdentifier::from_account_under_public_key(public_key)
268    }
269
270    #[tokio::test]
271    #[allow(deprecated)]
272    async fn test_get_account_with_none_values() {
273        // Arrange
274        let sdk = SDK::new(None, None, None);
275        let error_message = "failed to parse node address as valid URL";
276        let account_identifier = get_account_identifier();
277
278        // Act
279        let result = sdk
280            .get_account(Some(account_identifier), None, None, None, None)
281            .await;
282
283        // Assert
284        assert!(result.is_err());
285        let err_string = result.err().unwrap().to_string();
286        assert!(err_string.contains(error_message));
287    }
288
289    #[tokio::test]
290    #[allow(deprecated)]
291    async fn test_get_account_with_missing_account() {
292        // Arrange
293        let sdk = SDK::new(None, None, None);
294        let error_message = "Error: Missing account identifier";
295
296        // Act
297        let result = sdk.get_account(None, None, None, None, None).await;
298
299        // Assert
300        assert!(result.is_err());
301        let err_string = result.err().unwrap().to_string();
302        assert!(err_string.contains(error_message));
303    }
304
305    #[tokio::test]
306    #[allow(deprecated)]
307    async fn _test_get_account_with_account_identifier() {
308        if get_enable_addressable_entity() {
309            return;
310        }
311        // Arrange
312        let sdk = SDK::new(None, None, None);
313        let account_identifier = get_account_identifier();
314        let verbosity = Some(Verbosity::High);
315        let (rpc_address, _, _, _, _) = get_network_constants();
316
317        // Act
318        let result = sdk
319            .get_account(
320                Some(account_identifier),
321                None,
322                None,
323                verbosity,
324                Some(rpc_address),
325            )
326            .await;
327        // Assert
328        assert!(result.is_ok());
329    }
330
331    #[tokio::test]
332    #[allow(deprecated)]
333    async fn _test_get_account_with_account_identifier_as_string() {
334        if get_enable_addressable_entity() {
335            return;
336        }
337        // Arrange
338        let sdk = SDK::new(None, None, None);
339        let account_identifier_as_string = get_account_identifier().to_string();
340        let verbosity = Some(Verbosity::High);
341        let (rpc_address, _, _, _, _) = get_network_constants();
342
343        // Act
344        let result = sdk
345            .get_account(
346                None,
347                Some(account_identifier_as_string),
348                None,
349                verbosity,
350                Some(rpc_address),
351            )
352            .await;
353
354        // Assert
355        assert!(result.is_ok());
356    }
357
358    #[tokio::test]
359    #[allow(deprecated)]
360    async fn _test_get_account_with_block_identifier() {
361        if get_enable_addressable_entity() {
362            return;
363        }
364        // Arrange
365        let sdk = SDK::new(None, None, None);
366        let block_identifier =
367            BlockIdentifierInput::BlockIdentifier(BlockIdentifier::from_height(1));
368        let account_identifier = get_account_identifier();
369        let verbosity = Some(Verbosity::High);
370        let (rpc_address, _, _, _, _) = get_network_constants();
371
372        // Act
373        let result = sdk
374            .get_account(
375                Some(account_identifier),
376                None,
377                Some(block_identifier),
378                verbosity,
379                Some(rpc_address),
380            )
381            .await;
382
383        // Assert
384        assert!(result.is_ok());
385    }
386
387    #[tokio::test]
388    #[allow(deprecated)]
389    async fn test_get_account_with_error() {
390        // Arrange
391        let sdk = SDK::new(Some("http://localhost".to_string()), None, None);
392        let account_identifier = get_account_identifier();
393        let error_message = "error sending request";
394
395        // Act
396        let result = sdk
397            .get_account(Some(account_identifier), None, None, None, None)
398            .await;
399
400        // Assert
401        assert!(result.is_err());
402        let err_string = result.err().unwrap().to_string();
403        assert!(err_string.contains(error_message));
404    }
405}