Skip to main content

casper_rust_wasm_sdk/sdk/contract/
query_contract_dict.rs

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