casper_rust_wasm_sdk/sdk/deploy/
deploy.rs

1#[cfg(target_arch = "wasm32")]
2use crate::types::hash::deploy_hash::DeployHash;
3use crate::{
4    types::{
5        deploy_params::{
6            deploy_str_params::{deploy_str_params_to_casper_client, DeployStrParams},
7            payment_str_params::{payment_str_params_to_casper_client, PaymentStrParams},
8            session_str_params::{session_str_params_to_casper_client, SessionStrParams},
9        },
10        sdk_error::SdkError,
11        verbosity::Verbosity,
12    },
13    SDK,
14};
15use casper_client::{
16    cli::deploy::make_deploy, rpcs::results::PutDeployResult as _PutDeployResult, 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// Define a struct to wrap the result of a deploy.
26#[cfg(target_arch = "wasm32")]
27#[derive(Debug, Deserialize, Clone, Serialize)]
28#[wasm_bindgen]
29pub struct PutDeployResult(_PutDeployResult);
30
31/// Implement conversions between PutDeployResult and _PutDeployResult.
32#[cfg(target_arch = "wasm32")]
33impl From<PutDeployResult> for _PutDeployResult {
34    fn from(result: PutDeployResult) -> Self {
35        result.0
36    }
37}
38#[cfg(target_arch = "wasm32")]
39impl From<_PutDeployResult> for PutDeployResult {
40    fn from(result: _PutDeployResult) -> Self {
41        PutDeployResult(result)
42    }
43}
44
45/// Implement JavaScript bindings for PutDeployResult.
46#[cfg(target_arch = "wasm32")]
47#[wasm_bindgen]
48impl PutDeployResult {
49    /// Gets the API version as a JavaScript value.
50    #[wasm_bindgen(getter)]
51    pub fn api_version(&self) -> JsValue {
52        JsValue::from_serde(&self.0.api_version).unwrap()
53    }
54
55    /// Gets the deploy hash associated with this result.
56    #[wasm_bindgen(getter)]
57    pub fn deploy_hash(&self) -> DeployHash {
58        self.0.deploy_hash.into()
59    }
60
61    /// Converts PutDeployResult to a JavaScript object.
62    #[wasm_bindgen(js_name = "toJson")]
63    pub fn to_json(&self) -> JsValue {
64        JsValue::from_serde(&self.0).unwrap_or(JsValue::null())
65    }
66}
67
68#[cfg(target_arch = "wasm32")]
69#[wasm_bindgen]
70impl SDK {
71    /// JavaScript function for deploying with deserialized parameters.
72    ///
73    /// # Arguments
74    ///
75    /// * `deploy_params` - Deploy parameters.
76    /// * `session_params` - Session parameters.
77    /// * `payment_params` - Payment parameters.
78    /// * `verbosity` - An optional verbosity level.
79    /// * `rpc_address` - An optional rpc address.
80    ///
81    /// # Returns
82    ///
83    /// A result containing PutDeployResult or a JsError.
84    #[wasm_bindgen(js_name = "deploy")]
85    pub async fn deploy_js_alias(
86        &self,
87        deploy_params: DeployStrParams,
88        session_params: SessionStrParams,
89        payment_params: PaymentStrParams,
90        verbosity: Option<Verbosity>,
91        rpc_address: Option<String>,
92    ) -> Result<PutDeployResult, JsError> {
93        let result = self
94            .deploy(
95                deploy_params,
96                session_params,
97                payment_params,
98                verbosity,
99                rpc_address,
100            )
101            .await;
102        match result {
103            Ok(data) => Ok(data.result.into()),
104            Err(err) => {
105                let err = &format!("Error occurred with {:?}", err);
106                Err(JsError::new(err))
107            }
108        }
109    }
110}
111
112impl SDK {
113    /// Perform a deploy operation.
114    ///
115    /// # Arguments
116    ///
117    /// * `deploy_params` - Deploy parameters.
118    /// * `session_params` - Session parameters.
119    /// * `payment_params` - Payment parameters.
120    /// * `verbosity` - An optional verbosity level.
121    /// * `rpc_address` - An optional rpc address.
122    ///
123    /// # Returns
124    ///
125    /// A result containing a `SuccessResponse<_PutDeployResult>` or an SdkError.
126    pub async fn deploy(
127        &self,
128        deploy_params: DeployStrParams,
129        session_params: SessionStrParams,
130        payment_params: PaymentStrParams,
131        verbosity: Option<Verbosity>,
132        rpc_address: Option<String>,
133    ) -> Result<SuccessResponse<_PutDeployResult>, SdkError> {
134        //log("deploy!");
135        let deploy = make_deploy(
136            "",
137            deploy_str_params_to_casper_client(&deploy_params),
138            session_str_params_to_casper_client(&session_params),
139            payment_str_params_to_casper_client(&payment_params),
140            false,
141        );
142
143        if let Err(err) = deploy {
144            return Err(SdkError::from(err));
145        }
146
147        // Send the deploy to the network and handle any errors.
148        self.put_deploy(deploy.unwrap().into(), verbosity, rpc_address)
149            .await
150            .map_err(SdkError::from)
151    }
152}
153
154#[cfg(test)]
155mod tests {
156    use super::*;
157    use crate::helpers::public_key_from_secret_key;
158    use once_cell::sync::Lazy;
159    use sdk_tests::{
160        config::{ARGS_SIMPLE, HELLO_CONTRACT, PAYMENT_AMOUNT, WASM_PATH},
161        tests::helpers::{get_network_constants, get_user_secret_key, read_wasm_file},
162    };
163    use std::sync::Mutex;
164
165    static SESSION_PARAMS: Lazy<Mutex<Option<SessionStrParams>>> = Lazy::new(|| Mutex::new(None));
166
167    fn get_session_params() -> SessionStrParams {
168        let mut session_params = SESSION_PARAMS.lock().unwrap();
169
170        if session_params.is_none() {
171            let mut new_session_params = SessionStrParams::default();
172            let file_path = &format!("{WASM_PATH}{HELLO_CONTRACT}");
173            let module_bytes = match read_wasm_file(file_path) {
174                Ok(module_bytes) => module_bytes,
175                Err(err) => {
176                    eprintln!("Error reading file: {:?}", err);
177                    unimplemented!()
178                }
179            };
180            new_session_params.set_session_bytes(module_bytes.into());
181            let args_simple: Vec<String> = ARGS_SIMPLE.iter().map(|s| s.to_string()).collect();
182            new_session_params.set_session_args(args_simple);
183            *session_params = Some(new_session_params);
184        }
185
186        session_params.clone().unwrap()
187    }
188
189    #[tokio::test]
190    async fn test_deploy_with_valid_deploy_params() {
191        // Arrange
192        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        let account = public_key_from_secret_key(&secret_key).unwrap();
197
198        let deploy_params =
199            DeployStrParams::new(&chain_name, &account, Some(secret_key), None, None, None);
200
201        let payment_params = PaymentStrParams::default();
202        payment_params.set_payment_amount(PAYMENT_AMOUNT);
203
204        // Act
205        let result = sdk
206            .deploy(
207                deploy_params,
208                get_session_params().clone(),
209                payment_params,
210                verbosity,
211                Some(rpc_address),
212            )
213            .await;
214
215        // Assert
216        assert!(result.is_ok());
217    }
218
219    #[tokio::test]
220    async fn test_deploy_with_valid_deploy_params_without_secret_key() {
221        // Arrange
222        let sdk = SDK::new(None, None, None);
223        let verbosity = Some(Verbosity::High);
224        let (rpc_address, _, _, _, chain_name) = get_network_constants();
225
226        let error_message = "Invalid Deploy";
227
228        let secret_key = get_user_secret_key(None).unwrap();
229        let account = public_key_from_secret_key(&secret_key).unwrap();
230
231        let deploy_params = DeployStrParams::new(&chain_name, &account, None, None, None, None);
232        let payment_params = PaymentStrParams::default();
233        payment_params.set_payment_amount(PAYMENT_AMOUNT);
234
235        // Act
236        let result = sdk
237            .deploy(
238                deploy_params,
239                get_session_params().clone(),
240                payment_params,
241                verbosity,
242                Some(rpc_address),
243            )
244            .await;
245
246        // Assert
247        assert!(result.is_err());
248        let err_string = result.err().unwrap().to_string();
249        assert!(err_string.contains(error_message));
250    }
251
252    #[tokio::test]
253    async fn test_deploy_with_invalid_deploy_params() {
254        // Arrange
255        let sdk = SDK::new(None, None, None);
256        let verbosity = Some(Verbosity::High);
257        let (rpc_address, _, _, _, chain_name) = get_network_constants();
258
259        let error_message = "Missing a required arg - exactly one of the following must be provided: [\"payment_amount\", \"payment_hash\", \"payment_name\", \"payment_package_hash\", \"payment_package_name\", \"payment_path\", \"has_payment_bytes\"]";
260        let secret_key = get_user_secret_key(None).unwrap();
261        let account = public_key_from_secret_key(&secret_key).unwrap();
262
263        let deploy_params =
264            DeployStrParams::new(&chain_name, &account, Some(secret_key), None, None, None);
265        let payment_params = PaymentStrParams::default();
266        payment_params.set_payment_amount(""); // This is not valid payment amount
267
268        // Act
269        let result = sdk
270            .deploy(
271                deploy_params,
272                get_session_params().clone(),
273                payment_params,
274                verbosity,
275                Some(rpc_address),
276            )
277            .await;
278        // Assert
279        assert!(result.is_err());
280
281        let err_string = result.err().unwrap().to_string();
282        assert!(err_string.contains(error_message));
283    }
284}