casper_rust_wasm_sdk/sdk/rpcs/
get_transaction.rs

1use crate::types::hash::transaction_hash::TransactionHash;
2#[cfg(target_arch = "wasm32")]
3use crate::types::transaction::Transaction;
4use crate::{types::verbosity::Verbosity, SDK};
5use casper_client::{
6    get_transaction, rpcs::results::GetTransactionResult as _GetTransactionResult, Error,
7    JsonRpcId, SuccessResponse,
8};
9#[cfg(target_arch = "wasm32")]
10use gloo_utils::format::JsValueSerdeExt;
11use rand::Rng;
12#[cfg(target_arch = "wasm32")]
13use serde::{Deserialize, Serialize};
14use wasm_bindgen::prelude::*;
15
16// Define a struct to wrap the GetTransactionResult
17#[cfg(target_arch = "wasm32")]
18#[derive(Debug, Deserialize, Clone, Serialize)]
19#[wasm_bindgen]
20pub struct GetTransactionResult(_GetTransactionResult);
21
22#[cfg(target_arch = "wasm32")]
23impl From<GetTransactionResult> for _GetTransactionResult {
24    fn from(result: GetTransactionResult) -> Self {
25        result.0
26    }
27}
28#[cfg(target_arch = "wasm32")]
29impl From<_GetTransactionResult> for GetTransactionResult {
30    fn from(result: _GetTransactionResult) -> Self {
31        GetTransactionResult(result)
32    }
33}
34
35#[cfg(target_arch = "wasm32")]
36#[wasm_bindgen]
37impl GetTransactionResult {
38    #[wasm_bindgen(getter)]
39    /// Gets the API version as a JavaScript value.
40    pub fn api_version(&self) -> JsValue {
41        JsValue::from_serde(&self.0.api_version).unwrap()
42    }
43
44    #[wasm_bindgen(getter)]
45    /// Gets the transaction information.
46    pub fn transaction(&self) -> Transaction {
47        self.0.transaction.clone().into()
48    }
49
50    #[wasm_bindgen(getter)]
51    /// Gets the execution info as a JavaScript value.
52    pub fn execution_info(&self) -> JsValue {
53        JsValue::from_serde(&self.0.execution_info).unwrap()
54    }
55
56    #[wasm_bindgen(js_name = "toJson")]
57    /// Converts the result to a JSON JavaScript value.
58    pub fn to_json(&self) -> JsValue {
59        JsValue::from_serde(&self.0).unwrap_or(JsValue::null())
60    }
61}
62
63/// Options for the `get_transaction` method.
64#[derive(Debug, Clone, Default, Deserialize, Serialize)]
65#[cfg(target_arch = "wasm32")]
66#[wasm_bindgen(js_name = "getTransactionOptions", getter_with_clone)]
67pub struct GetTransactionOptions {
68    pub transaction_hash_as_string: Option<String>,
69    pub transaction_hash: Option<TransactionHash>,
70    pub finalized_approvals: Option<bool>,
71    pub rpc_address: Option<String>,
72    pub verbosity: Option<Verbosity>,
73}
74
75#[wasm_bindgen]
76impl SDK {
77    /// Parses transaction options from a JsValue.
78    ///
79    /// # Arguments
80    ///
81    /// * `options` - A JsValue containing transaction options to be parsed.
82    ///
83    /// # Returns
84    ///
85    /// Parsed transaction options as a `GetTransactionOptions` struct.
86    #[cfg(target_arch = "wasm32")]
87    pub fn get_transaction_options(
88        &self,
89        options: JsValue,
90    ) -> Result<GetTransactionOptions, JsError> {
91        let options_result: Result<GetTransactionOptions, _> = options.into_serde();
92        match options_result {
93            Ok(mut options) => {
94                if let Some(finalized_approvals) = options.finalized_approvals {
95                    options.finalized_approvals =
96                        Some(JsValue::from_bool(finalized_approvals) == JsValue::TRUE);
97                }
98                Ok(options)
99            }
100            Err(err) => Err(JsError::new(&format!(
101                "Error deserializing options: {:?}",
102                err
103            ))),
104        }
105    }
106
107    /// Retrieves transaction information using the provided options.
108    ///
109    /// # Arguments
110    ///
111    /// * `options` - An optional `GetTransactionOptions` struct containing retrieval options.
112    ///
113    /// # Returns
114    ///
115    /// A `Result` containing either a `GetTransactionResult` or an error.
116    #[cfg(target_arch = "wasm32")]
117    #[wasm_bindgen(js_name = "get_transaction")]
118    pub async fn get_transaction_js_alias(
119        &self,
120        options: Option<GetTransactionOptions>,
121    ) -> Result<GetTransactionResult, JsError> {
122        let GetTransactionOptions {
123            transaction_hash_as_string,
124            transaction_hash,
125            finalized_approvals,
126            verbosity,
127            rpc_address,
128        } = options.unwrap_or_default();
129
130        let transaction_hash = if let Some(transaction_hash_as_string) = transaction_hash_as_string
131        {
132            TransactionHash::new(&transaction_hash_as_string)?
133        } else {
134            if transaction_hash.is_none() {
135                let err_msg =
136                    "Error: Missing transaction hash as string or transaction hash".to_string();
137                return Err(JsError::new(&err_msg));
138            }
139            transaction_hash.unwrap()
140        };
141
142        let result = self
143            .get_transaction(
144                transaction_hash,
145                finalized_approvals,
146                verbosity,
147                rpc_address,
148            )
149            .await;
150        match result {
151            Ok(data) => Ok(data.result.into()),
152            Err(err) => {
153                let err = &format!("Error occurred with {:?}", err);
154                Err(JsError::new(err))
155            }
156        }
157    }
158
159    /// Retrieves transaction information using the provided options, alias for `get_transaction`.
160    #[cfg(target_arch = "wasm32")]
161    #[deprecated(note = "This function is an alias. Please use `get_transaction` instead.")]
162    #[allow(deprecated)]
163    pub async fn info_get_transaction(
164        &self,
165        options: Option<GetTransactionOptions>,
166    ) -> Result<GetTransactionResult, JsError> {
167        self.get_transaction_js_alias(options).await
168    }
169}
170
171impl SDK {
172    /// Retrieves transaction information based on the provided options.
173    ///
174    /// # Arguments
175    ///
176    /// * `transaction_hash` - The transaction hash.
177    /// * `finalized_approvals` - An optional boolean indicating finalized approvals.
178    /// * `verbosity` - An optional verbosity level.
179    /// * `rpc_address` - An optional rpc address.
180    ///
181    /// # Returns
182    ///
183    /// A `Result` containing either a `_GetTransactionResult` or an error.
184    pub async fn get_transaction(
185        &self,
186        transaction_hash: TransactionHash,
187        finalized_approvals: Option<bool>,
188        verbosity: Option<Verbosity>,
189        rpc_address: Option<String>,
190    ) -> Result<SuccessResponse<_GetTransactionResult>, Error> {
191        //log("get_transaction!");
192        get_transaction(
193            JsonRpcId::from(rand::thread_rng().gen::<u64>().to_string()),
194            &self.get_rpc_address(rpc_address),
195            self.get_verbosity(verbosity).into(),
196            transaction_hash.into(),
197            finalized_approvals.unwrap_or_default(),
198        )
199        .await
200    }
201}
202
203#[cfg(test)]
204mod tests {
205    use super::*;
206    use crate::{
207        helpers::public_key_from_secret_key,
208        types::transaction_params::transaction_str_params::TransactionStrParams,
209    };
210    use sdk_tests::{
211        config::TRANSFER_AMOUNT,
212        tests::helpers::{get_network_constants, get_user_secret_key},
213    };
214
215    #[tokio::test]
216    async fn test_get_transaction_with_none_values() {
217        // Arrange
218        let sdk = SDK::new(None, None, None);
219        let transaction_hash = TransactionHash::from_raw(&[1u8; 32]).unwrap();
220        let error_message = "failed to parse node address as valid URL";
221
222        // Act
223        let result = sdk
224            .get_transaction(transaction_hash, None, None, None)
225            .await;
226
227        // Assert
228        assert!(result.is_err());
229        let err_string = result.err().unwrap().to_string();
230        assert!(err_string.contains(error_message));
231    }
232
233    #[tokio::test]
234    async fn test_get_transaction_with_invalid_transaction_hash() {
235        // Arrange
236        let sdk = SDK::new(None, None, None);
237        let transaction_hash = TransactionHash::from_raw(&[1u8; 32]).unwrap();
238        let verbosity = Some(Verbosity::High);
239        let (rpc_address, _, _, _, _) = get_network_constants();
240
241        // Act
242        let result = sdk
243            .get_transaction(transaction_hash, None, verbosity, Some(rpc_address))
244            .await;
245
246        // Assert
247        assert!(result.is_err());
248    }
249
250    #[tokio::test]
251    async fn test_get_transaction_with_valid_transaction_hash() {
252        // Arrange
253        let sdk = SDK::new(None, None, None);
254        let verbosity = Some(Verbosity::High);
255        let (rpc_address, _, _, _, chain_name) = get_network_constants();
256
257        let secret_key = get_user_secret_key(None).unwrap();
258        let initiator_addr = public_key_from_secret_key(&secret_key).unwrap();
259
260        let transaction_params = TransactionStrParams::default();
261        transaction_params.set_secret_key(&secret_key);
262        transaction_params.set_chain_name(&chain_name);
263        transaction_params.set_payment_amount(TRANSFER_AMOUNT);
264
265        let transfer = sdk
266            .transfer_transaction(
267                None,
268                &initiator_addr, // self transfer
269                TRANSFER_AMOUNT,
270                transaction_params,
271                None,
272                verbosity,
273                Some(rpc_address.clone()),
274            )
275            .await
276            .unwrap();
277        let transaction_hash = transfer.result.transaction_hash;
278        assert!(!transaction_hash.to_string().is_empty());
279
280        // Act
281        let result = sdk
282            .get_transaction(transaction_hash.into(), None, verbosity, Some(rpc_address))
283            .await;
284
285        // Assert
286        // dbg!(result);
287        assert!(result.is_ok());
288    }
289
290    #[tokio::test]
291    async fn test_get_transaction_with_finalized_approvals() {
292        // Arrange
293        let sdk = SDK::new(None, None, None);
294        let verbosity = Some(Verbosity::High);
295        let (rpc_address, _, _, _, chain_name) = get_network_constants();
296
297        let secret_key = get_user_secret_key(None).unwrap();
298        let initiator_addr = public_key_from_secret_key(&secret_key).unwrap();
299
300        let transaction_params = TransactionStrParams::default();
301        transaction_params.set_secret_key(&secret_key);
302        transaction_params.set_chain_name(&chain_name);
303        transaction_params.set_payment_amount(TRANSFER_AMOUNT);
304
305        let transfer = sdk
306            .transfer_transaction(
307                None,
308                &initiator_addr, // self transfer
309                TRANSFER_AMOUNT,
310                transaction_params,
311                None,
312                verbosity,
313                Some(rpc_address.clone()),
314            )
315            .await
316            .unwrap();
317        let transaction_hash = transfer.result.transaction_hash;
318        assert!(!transaction_hash.to_string().is_empty());
319        let finalized_approvals = true;
320
321        // Act
322        let result = sdk
323            .get_transaction(
324                transaction_hash.into(),
325                Some(finalized_approvals),
326                verbosity,
327                Some(rpc_address),
328            )
329            .await;
330
331        // Assert
332        assert!(result.is_ok());
333    }
334
335    #[tokio::test]
336    async fn test_get_transaction_with_error() {
337        // Arrange
338        let sdk = SDK::new(Some("http://localhost".to_string()), None, None);
339        let transaction_hash = TransactionHash::from_raw(&[1u8; 32]).unwrap();
340        let error_message = "error sending request for url (http://localhost/rpc)";
341
342        // Act
343        let result = sdk
344            .get_transaction(transaction_hash, None, None, None)
345            .await;
346
347        // Assert
348        assert!(result.is_err());
349        let err_string = result.err().unwrap().to_string();
350        assert!(err_string.contains(error_message));
351    }
352}