casper_rust_wasm_sdk/sdk/transaction/
transaction.rs1#[cfg(target_arch = "wasm32")]
2use crate::types::hash::transaction_hash::TransactionHash;
3use crate::{
4 types::{
5 sdk_error::SdkError,
6 transaction_params::{
7 transaction_builder_params::{
8 transaction_builder_params_to_casper_client, TransactionBuilderParams,
9 },
10 transaction_str_params::{
11 transaction_str_params_to_casper_client, TransactionStrParams,
12 },
13 },
14 verbosity::Verbosity,
15 },
16 SDK,
17};
18
19use casper_client::{
20 cli::make_transaction, rpcs::results::PutTransactionResult as _PutTransactionResult,
21 SuccessResponse,
22};
23#[cfg(target_arch = "wasm32")]
24use gloo_utils::format::JsValueSerdeExt;
25#[cfg(target_arch = "wasm32")]
26use serde::{Deserialize, Serialize};
27#[cfg(target_arch = "wasm32")]
28use wasm_bindgen::prelude::*;
29
30#[cfg(target_arch = "wasm32")]
32#[derive(Debug, Deserialize, Clone, Serialize)]
33#[wasm_bindgen]
34pub struct PutTransactionResult(_PutTransactionResult);
35
36#[cfg(target_arch = "wasm32")]
38impl From<PutTransactionResult> for _PutTransactionResult {
39 fn from(result: PutTransactionResult) -> Self {
40 result.0
41 }
42}
43#[cfg(target_arch = "wasm32")]
44impl From<_PutTransactionResult> for PutTransactionResult {
45 fn from(result: _PutTransactionResult) -> Self {
46 PutTransactionResult(result)
47 }
48}
49
50#[cfg(target_arch = "wasm32")]
52#[wasm_bindgen]
53impl PutTransactionResult {
54 #[wasm_bindgen(getter)]
56 pub fn api_version(&self) -> JsValue {
57 JsValue::from_serde(&self.0.api_version).unwrap()
58 }
59
60 #[wasm_bindgen(getter)]
62 pub fn transaction_hash(&self) -> TransactionHash {
63 self.0.transaction_hash.into()
64 }
65
66 #[wasm_bindgen(js_name = "toJson")]
68 pub fn to_json(&self) -> JsValue {
69 JsValue::from_serde(&self.0).unwrap_or(JsValue::null())
70 }
71}
72
73#[cfg(target_arch = "wasm32")]
74#[wasm_bindgen]
75impl SDK {
76 #[wasm_bindgen(js_name = "transaction")]
89 pub async fn transaction_js_alias(
90 &self,
91 builder_params: TransactionBuilderParams,
92 transaction_params: TransactionStrParams,
93 verbosity: Option<Verbosity>,
94 rpc_address: Option<String>,
95 ) -> Result<PutTransactionResult, JsError> {
96 let result = self
97 .transaction(builder_params, transaction_params, verbosity, rpc_address)
98 .await;
99 match result {
100 Ok(data) => Ok(data.result.into()),
101 Err(err) => {
102 let err = &format!("Error occurred with {:?}", err);
103 Err(JsError::new(err))
104 }
105 }
106 }
107}
108
109impl SDK {
110 pub async fn transaction(
123 &self,
124 builder_params: TransactionBuilderParams,
125 transaction_params: TransactionStrParams,
126 verbosity: Option<Verbosity>,
127 rpc_address: Option<String>,
128 ) -> Result<SuccessResponse<_PutTransactionResult>, SdkError> {
129 let transaction = match make_transaction(
131 transaction_builder_params_to_casper_client(&builder_params),
132 transaction_str_params_to_casper_client(&transaction_params),
133 false,
134 ) {
135 Ok(transaction) => transaction,
136 Err(err) => {
137 return Err(SdkError::from(err));
138 }
139 };
140 self.put_transaction(transaction.into(), verbosity, rpc_address)
141 .await
142 .map_err(SdkError::from)
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use std::sync::Mutex;
149
150 use super::*;
151 use crate::helpers::public_key_from_secret_key;
152 use once_cell::sync::Lazy;
153 use sdk_tests::{
154 config::{ARGS_SIMPLE, HELLO_CONTRACT, PAYMENT_AMOUNT, WASM_PATH},
155 tests::helpers::{get_network_constants, get_user_secret_key, read_wasm_file},
156 };
157
158 static ARGS: Lazy<Vec<String>> =
159 Lazy::new(|| ARGS_SIMPLE.iter().map(|s| s.to_string()).collect());
160
161 static BUILDER_PARAMS: Lazy<Mutex<Option<TransactionBuilderParams>>> =
162 Lazy::new(|| Mutex::new(None));
163
164 fn get_builder_params() -> TransactionBuilderParams {
165 let mut builder_params = BUILDER_PARAMS.lock().unwrap();
166
167 if builder_params.is_none() {
168 let file_path = &format!("{WASM_PATH}{HELLO_CONTRACT}");
169 let transaction_bytes = match read_wasm_file(file_path) {
170 Ok(transaction_bytes) => transaction_bytes,
171 Err(err) => {
172 eprintln!("Error reading file: {:?}", err);
173 unimplemented!()
174 }
175 };
176
177 let is_install_upgrade = Some(true);
178
179 let new_builder_params = TransactionBuilderParams::new_session(
180 Some(transaction_bytes.into()),
181 is_install_upgrade,
182 );
183 *builder_params = Some(new_builder_params);
184 }
185
186 builder_params.clone().unwrap()
187 }
188
189 #[tokio::test]
190 async fn test_transaction_with_valid_transaction_params() {
191 let sdk = SDK::new(None, None, None);
193 let verbosity = Some(Verbosity::High);
194 let (rpc_address, _, _, _, chain_name) = get_network_constants();
195 let secret_key = get_user_secret_key(None).unwrap();
196
197 let mut transaction_params = TransactionStrParams::default();
198 transaction_params.set_secret_key(&secret_key);
199 transaction_params.set_chain_name(&chain_name);
200 transaction_params.set_payment_amount(PAYMENT_AMOUNT);
201 transaction_params.set_session_args_simple(ARGS.to_vec());
202
203 let result = sdk
205 .transaction(
206 get_builder_params().clone(),
207 transaction_params,
208 verbosity,
209 Some(rpc_address),
210 )
211 .await;
212
213 assert!(result.is_ok());
215 }
216
217 #[tokio::test]
218 async fn test_transaction_with_valid_transaction_params_without_secret_key() {
219 let sdk = SDK::new(None, None, None);
221 let verbosity = Some(Verbosity::High);
222 let (rpc_address, _, _, _, chain_name) = get_network_constants();
223 let secret_key = get_user_secret_key(None).unwrap();
224 let initiator_addr = public_key_from_secret_key(&secret_key).unwrap();
225 let error_message = "the transaction was invalid: invalid associated keys";
226
227 let mut transaction_params = TransactionStrParams::default();
228 transaction_params.set_chain_name(&chain_name);
229 transaction_params.set_initiator_addr(&initiator_addr);
230 transaction_params.set_payment_amount(PAYMENT_AMOUNT);
231 transaction_params.set_session_args_simple(ARGS.to_vec());
232
233 let result = sdk
235 .transaction(
236 get_builder_params().clone(),
237 transaction_params,
238 verbosity,
239 Some(rpc_address),
240 )
241 .await;
242
243 assert!(result.is_err());
245 let err_string = result.err().unwrap().to_string();
246 assert!(err_string.contains(error_message));
247 }
248
249 #[tokio::test]
250 async fn test_transaction_with_invalid_transaction_params() {
251 let sdk = SDK::new(None, None, None);
253 let verbosity = Some(Verbosity::High);
254 let (rpc_address, _, _, _, _) = get_network_constants();
255
256 let error_message = "The transaction sent to the network had an invalid chain name";
257 let secret_key = get_user_secret_key(None).unwrap();
258
259 let transaction_params = TransactionStrParams::default();
260 transaction_params.set_payment_amount(PAYMENT_AMOUNT);
261 transaction_params.set_secret_key(&secret_key);
262 transaction_params.set_chain_name("");
263
264 let result = sdk
266 .transaction(
267 get_builder_params().clone(),
268 transaction_params,
269 verbosity,
270 Some(rpc_address),
271 )
272 .await;
273 assert!(result.is_err());
275
276 let err_string = result.err().unwrap().to_string();
277 assert!(err_string.contains(error_message));
278 }
279}