Skip to main content

casper_rust_wasm_sdk/sdk/transaction/
transfer_transaction.rs

1#[cfg(all(feature = "js", target_arch = "wasm32"))]
2use crate::transaction::transaction::PutTransactionResult;
3use crate::{
4    make_transfer_transaction,
5    types::{
6        sdk_error::SdkError, transaction_params::transaction_str_params::TransactionStrParams,
7        uref::URef, verbosity::Verbosity,
8    },
9    SDK,
10};
11use casper_client::{
12    rpcs::results::PutTransactionResult as _PutTransactionResult, SuccessResponse,
13};
14#[cfg(all(feature = "js", target_arch = "wasm32"))]
15use wasm_bindgen::prelude::*;
16
17#[cfg(all(feature = "js", target_arch = "wasm32"))]
18#[cfg_attr(feature = "js", wasm_bindgen)]
19impl SDK {
20    /// JS function for transaction transferring funds.
21    ///
22    /// # Arguments
23    ///
24    /// * `maybe_source` - Optional transfer source uref.
25    /// * `target_account` - The target account.
26    /// * `amount` - The amount to transfer.
27    /// * `transaction_params` - The transaction parameters.
28    /// * `maybe_id` - An optional transfer ID (defaults to a random number).
29    /// * `verbosity` - The verbosity level for logging (optional).
30    /// * `rpc_address` - The address of the node to connect to (optional).
31    ///
32    /// # Returns
33    ///
34    /// A `Result` containing the result of the transfer or a `JsError` in case of an error.
35    #[cfg_attr(feature = "js", wasm_bindgen(js_name = "transfer_transaction"))]
36    #[allow(clippy::too_many_arguments)]
37    #[cfg(feature = "js")]
38    pub async fn transfer_transactionjs_alias(
39        &self,
40        maybe_source: Option<URef>,
41        target_account: &str,
42        amount: &str,
43        transaction_params: TransactionStrParams,
44        maybe_id: Option<String>,
45        verbosity: Option<Verbosity>,
46        rpc_address: Option<String>,
47    ) -> Result<PutTransactionResult, JsError> {
48        let result = self
49            .transfer_transaction(
50                maybe_source,
51                target_account,
52                amount,
53                transaction_params,
54                maybe_id,
55                verbosity,
56                rpc_address,
57            )
58            .await;
59        match result {
60            Ok(data) => Ok(data.result.into()),
61            Err(err) => {
62                let err = &format!("Error occurred with {err:?}");
63                Err(JsError::new(err))
64            }
65        }
66    }
67}
68
69impl SDK {
70    /// Perform a transfer transaction of funds.
71    ///
72    /// # Arguments
73    ///
74    /// * `maybe_source` - Optional transfer source uref.
75    /// * `target_account` - The target account.
76    /// * `amount` - The amount to transfer.
77    /// * `transaction_params` - The transaction parameters.
78    /// * `maybe_id` - An optional transfer ID (defaults to a random number).
79    /// * `verbosity` - The verbosity level for logging (optional).
80    /// * `rpc_address` - The address of the node to connect to (optional).
81    ///
82    /// # Returns
83    ///
84    /// A `Result` containing the result a `SuccessResponse<_PutTransactionResult>` of the transfer or a `SdkError` in case of an error.
85    #[allow(clippy::too_many_arguments)]
86    pub async fn transfer_transaction(
87        &self,
88        maybe_source: Option<URef>,
89        target_account: &str,
90        amount: &str,
91        transaction_params: TransactionStrParams,
92        maybe_id: Option<String>,
93        verbosity: Option<Verbosity>,
94        rpc_address: Option<String>,
95    ) -> Result<SuccessResponse<_PutTransactionResult>, SdkError> {
96        //log("transfer!");
97        let transaction = make_transfer_transaction(
98            maybe_source,
99            target_account,
100            amount,
101            transaction_params,
102            maybe_id,
103        )
104        .map_err(|e| *e)?;
105
106        self.put_transaction(transaction, verbosity, rpc_address)
107            .await
108    }
109}
110
111#[cfg(test)]
112mod tests {
113
114    use super::*;
115    use crate::helpers::public_key_from_secret_key;
116    use sdk_tests::{
117        config::TRANSFER_AMOUNT,
118        tests::helpers::{get_network_constants, get_user_secret_key},
119    };
120
121    #[tokio::test]
122    async fn test_transfer_with_valid_transfer_params() {
123        // Arrange
124        let sdk = SDK::new(None, None, None);
125        let verbosity = Some(Verbosity::High);
126        let (rpc_address, _, _, _, chain_name) = get_network_constants();
127
128        let secret_key = get_user_secret_key(None).unwrap();
129        let initiator_addr = public_key_from_secret_key(&secret_key).unwrap();
130
131        let transaction_params = TransactionStrParams::default();
132        transaction_params.set_secret_key(&secret_key);
133        transaction_params.set_chain_name(&chain_name);
134        transaction_params.set_payment_amount(TRANSFER_AMOUNT);
135
136        // Act
137        let result = sdk
138            .transfer_transaction(
139                None,
140                &initiator_addr,
141                TRANSFER_AMOUNT,
142                transaction_params,
143                None,
144                verbosity,
145                Some(rpc_address),
146            )
147            .await;
148
149        // Assert
150        assert!(result.is_ok());
151    }
152
153    #[tokio::test]
154    async fn test_transfer_with_valid_transfer_params_without_secret_key() {
155        // Arrange
156        let sdk = SDK::new(None, None, None);
157        let verbosity = Some(Verbosity::High);
158        let (rpc_address, _, _, _, chain_name) = get_network_constants();
159
160        let error_message = "the transaction was invalid: invalid associated keys";
161
162        let secret_key = get_user_secret_key(None).unwrap();
163        let initiator_addr = public_key_from_secret_key(&secret_key).unwrap();
164
165        let transaction_params = TransactionStrParams::default();
166        transaction_params.set_chain_name(&chain_name);
167        transaction_params.set_initiator_addr(&initiator_addr);
168        transaction_params.set_payment_amount(TRANSFER_AMOUNT);
169
170        // Act
171        let result = sdk
172            .transfer_transaction(
173                None,
174                &initiator_addr,
175                TRANSFER_AMOUNT,
176                transaction_params,
177                None,
178                verbosity,
179                Some(rpc_address),
180            )
181            .await;
182
183        // Assert
184        assert!(result.is_err());
185        let err_string = result.err().unwrap().to_string();
186        assert!(err_string.contains(error_message));
187    }
188
189    #[tokio::test]
190    async fn test_transfer_with_invalid_transfer_params() {
191        // Arrange
192        let sdk = SDK::new(None, None, None);
193        let verbosity = Some(Verbosity::High);
194        let (rpc_address, _, _, _, _) = get_network_constants();
195
196        let error_message = "The transaction sent to the network had an invalid chain name";
197        let secret_key = get_user_secret_key(None).unwrap();
198        let initiator_addr = public_key_from_secret_key(&secret_key).unwrap();
199
200        let transaction_params = TransactionStrParams::default();
201        transaction_params.set_secret_key(&secret_key);
202        transaction_params.set_payment_amount(TRANSFER_AMOUNT);
203        transaction_params.set_chain_name("");
204
205        // Act
206        let result = sdk
207            .transfer_transaction(
208                None,
209                &initiator_addr,
210                TRANSFER_AMOUNT,
211                transaction_params,
212                None,
213                verbosity,
214                Some(rpc_address),
215            )
216            .await;
217        // Assert
218        assert!(result.is_err());
219
220        let err_string = result.err().unwrap().to_string();
221        assert!(err_string.contains(error_message));
222    }
223}