casper_rust_wasm_sdk/sdk/contract/
query_contract_dict.rs

1#[cfg(target_arch = "wasm32")]
2use crate::rpcs::get_dictionary_item::GetDictionaryItemResult;
3#[cfg(target_arch = "wasm32")]
4use crate::types::digest::Digest;
5#[cfg(target_arch = "wasm32")]
6use crate::types::{
7    deploy_params::dictionary_item_str_params::DictionaryItemStrParams,
8    identifier::dictionary_item_identifier::DictionaryItemIdentifier,
9};
10use crate::{
11    rpcs::get_dictionary_item::DictionaryItemInput,
12    types::{digest::ToDigest, verbosity::Verbosity},
13};
14use crate::{types::sdk_error::SdkError, SDK};
15use casper_client::{
16    rpcs::results::GetDictionaryItemResult as _GetDictionaryItemResult, SuccessResponse,
17};
18#[cfg(target_arch = "wasm32")]
19use gloo_utils::format::JsValueSerdeExt;
20#[cfg(target_arch = "wasm32")]
21use serde::{Deserialize, Serialize};
22#[cfg(target_arch = "wasm32")]
23use wasm_bindgen::prelude::*;
24
25#[derive(Default, Debug, Deserialize, Clone, Serialize)]
26#[cfg(target_arch = "wasm32")]
27#[wasm_bindgen(js_name = "queryContractDictOptions", getter_with_clone)]
28pub struct QueryContractDictOptions {
29    // Not supported by get_dictionary_item
30    // pub global_state_identifier: Option<GlobalStateIdentifier>,
31    pub state_root_hash_as_string: Option<String>,
32    pub state_root_hash: Option<Digest>,
33    pub dictionary_item_params: Option<DictionaryItemStrParams>,
34    pub dictionary_item_identifier: Option<DictionaryItemIdentifier>,
35    pub rpc_address: Option<String>,
36    pub verbosity: Option<Verbosity>,
37}
38
39#[cfg(target_arch = "wasm32")]
40#[wasm_bindgen]
41impl SDK {
42    /// Deserialize query_contract_dict_options from a JavaScript object.
43    #[wasm_bindgen(js_name = "query_contract_dict_options")]
44    pub fn query_contract_dict_state_options(
45        &self,
46        options: JsValue,
47    ) -> Result<QueryContractDictOptions, JsError> {
48        options
49            .into_serde::<QueryContractDictOptions>()
50            .map_err(|err| JsError::new(&format!("Error deserializing options: {:?}", err)))
51    }
52
53    /// JavaScript function for query_contract_dict with deserialized options.
54    #[wasm_bindgen(js_name = "query_contract_dict")]
55    pub async fn query_contract_dict_js_alias(
56        &self,
57        options: Option<QueryContractDictOptions>,
58    ) -> Result<GetDictionaryItemResult, JsError> {
59        let js_value_options =
60            JsValue::from_serde::<QueryContractDictOptions>(&options.unwrap_or_default());
61        if let Err(err) = js_value_options {
62            let err = &format!("Error serializing options: {:?}", err);
63            return Err(JsError::new(err));
64        }
65        let options = self.get_dictionary_item_options(js_value_options.unwrap())?;
66        self.get_dictionary_item_js_alias(Some(options)).await
67    }
68}
69
70/// Alias of sdk.get_dictionary_item
71impl SDK {
72    /// Query a contract dictionary item.
73    ///
74    /// # Arguments
75    ///
76    /// * `state_root_hash` - State root hash.
77    /// * `dictionary_item` - Dictionary item input.
78    /// * `verbosity` - Optional verbosity level.
79    /// * `rpc_address` - Optional rpc address.
80    ///
81    /// # Returns
82    ///
83    /// A `Result` containing either a `SuccessResponse<_GetDictionaryItemResult>` or a `SdkError` in case of an error.
84    pub async fn query_contract_dict(
85        &self,
86        dictionary_item: DictionaryItemInput,
87        state_root_hash: Option<impl ToDigest>,
88        verbosity: Option<Verbosity>,
89        rpc_address: Option<String>,
90    ) -> Result<SuccessResponse<_GetDictionaryItemResult>, SdkError> {
91        // log("query_contract_dict!");
92        self.get_dictionary_item(dictionary_item, state_root_hash, verbosity, rpc_address)
93            .await
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100    use crate::{
101        get_dictionary_item,
102        types::{
103            deploy_params::dictionary_item_str_params::DictionaryItemStrParams, digest::Digest,
104        },
105    };
106    use sdk_tests::tests::helpers::get_network_constants;
107    use tokio;
108
109    #[tokio::test]
110    async fn test_query_contract_dict_with_none_values() {
111        // Arrange
112        let sdk = SDK::new(None, None, None);
113        let error_message = "failed to parse node address as valid URL";
114
115        // Act
116        let result = sdk
117            .query_contract_dict(
118                get_dictionary_item(false).await,
119                Some("7d3dc9c74fe93e83fe6cc7a9830ba223035ad4fd4fd464489640742069ca31ed"), // query_contract_dict does not support empty string as state_root_hash
120                None,
121                None,
122            )
123            .await;
124
125        // Assert
126        assert!(result.is_err());
127        let err_string = result.err().unwrap().to_string();
128        assert!(err_string.contains(error_message));
129    }
130
131    #[tokio::test]
132    async fn test_query_contract_dict_with_state_root_hash() {
133        // Arrange
134        let sdk = SDK::new(None, None, None);
135        let verbosity = Some(Verbosity::High);
136        let (rpc_address, _, _, _, _) = get_network_constants();
137
138        let dictionary_item = get_dictionary_item(false).await;
139
140        let state_root_hash: Digest = sdk
141            .get_state_root_hash(None, verbosity, Some(rpc_address.clone()))
142            .await
143            .unwrap()
144            .result
145            .state_root_hash
146            .unwrap()
147            .into();
148
149        // Act
150        let result = sdk
151            .query_contract_dict(
152                dictionary_item,
153                Some(state_root_hash),
154                verbosity,
155                Some(rpc_address),
156            )
157            .await;
158
159        // Assert
160        assert!(result.is_ok());
161    }
162
163    #[tokio::test]
164    async fn test_query_contract_dict_with_empty_state_root_hash() {
165        // Arrange
166        let sdk = SDK::new(None, None, None);
167        let verbosity = Some(Verbosity::High);
168        let (rpc_address, _, _, _, _) = get_network_constants();
169        let state_root_hash = "";
170
171        // Act
172        let result = sdk
173            .query_contract_dict(
174                get_dictionary_item(false).await,
175                Some(state_root_hash),
176                verbosity,
177                Some(rpc_address),
178            )
179            .await;
180        // Assert
181        assert!(result.is_ok());
182    }
183
184    #[tokio::test]
185    async fn test_query_contract_dict_with_valid_identifier_input() {
186        // Arrange
187        let sdk = SDK::new(None, None, None);
188        let verbosity = Some(Verbosity::High);
189        let (rpc_address, _, _, _, _) = get_network_constants();
190        let state_root_hash = "";
191
192        // Act
193        let result = sdk
194            .query_contract_dict(
195                get_dictionary_item(false).await,
196                Some(state_root_hash),
197                verbosity,
198                Some(rpc_address),
199            )
200            .await;
201
202        // Assert
203        assert!(result.is_ok());
204    }
205
206    #[tokio::test]
207    async fn test_query_contract_dict_with_valid_params_input() {
208        // Arrange
209        let sdk = SDK::new(None, None, None);
210        let verbosity = Some(Verbosity::High);
211        let (rpc_address, _, _, _, _) = get_network_constants();
212        let state_root_hash = "";
213
214        // Act
215        let result = sdk
216            .query_contract_dict(
217                get_dictionary_item(true).await,
218                Some(state_root_hash),
219                verbosity,
220                Some(rpc_address),
221            )
222            .await;
223
224        // Assert
225        assert!(result.is_ok());
226    }
227
228    #[tokio::test]
229    async fn test_query_contract_dict_with_invalid_params_input() {
230        // Arrange
231        let sdk = SDK::new(None, None, None);
232        let verbosity = Some(Verbosity::High);
233        let (rpc_address, _, _, _, _) = get_network_constants();
234
235        let error_message =
236            "Failed to parse dictionary item address as a key: unknown prefix for key";
237
238        let state_root_hash = "";
239        let params = DictionaryItemStrParams::new();
240
241        // Act
242        let result = sdk
243            .query_contract_dict(
244                DictionaryItemInput::Params(params),
245                Some(state_root_hash),
246                verbosity,
247                Some(rpc_address),
248            )
249            .await;
250
251        // Assert
252        assert!(result.is_err());
253        let err_string = result.err().unwrap().to_string();
254        assert!(err_string.contains(error_message));
255    }
256
257    #[tokio::test]
258    async fn test_query_contract_dict_with_error() {
259        // Arrange
260        let sdk = SDK::new(Some("http://localhost".to_string()), None, None);
261        let error_message = "error sending request for url (http://localhost/rpc)";
262
263        // Act
264        let result = sdk
265            .query_contract_dict(
266                get_dictionary_item(false).await,
267                Some("7d3dc9c74fe93e83fe6cc7a9830ba223035ad4fd4fd464489640742069ca31ed"), // query_contract_dict does not support empty string as state_root_hash
268                None,
269                None,
270            )
271            .await;
272
273        // Assert
274        assert!(result.is_err());
275        let err_string = result.err().unwrap().to_string();
276        assert!(err_string.contains(error_message));
277    }
278}