Skip to main content

casper_rust_wasm_sdk/sdk/deploy/
deploy.rs

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