Skip to main content

casper_rust_wasm_sdk/sdk/transaction_utils/
make_transfer_transaction.rs

1use crate::{
2    types::{
3        sdk_error::SdkError,
4        transaction::Transaction,
5        transaction_params::transaction_str_params::{
6            transaction_str_params_to_casper_client, TransactionStrParams,
7        },
8        uref::URef,
9    },
10    SDK,
11};
12use casper_client::cli::{
13    make_transaction as client_make_transaction, parse::transfer_target, TransactionBuilderParams,
14};
15use casper_types::U512;
16use rand::RngExt;
17use std::str::FromStr;
18#[cfg(all(feature = "js", target_arch = "wasm32"))]
19use wasm_bindgen::prelude::*;
20
21/// Exposes the `make_transfer_transaction` function to JavaScript with an alias.
22#[cfg(all(feature = "js", target_arch = "wasm32"))]
23#[cfg_attr(feature = "js", wasm_bindgen)]
24impl SDK {
25    /// JS function for `make_transfer_transaction`.
26    ///
27    /// # Arguments
28    ///
29    /// * `maybe_source` - Optional transfer source uref.
30    /// * `amount` - The transfer amount.
31    /// * `target` - The target account.
32    /// * `transaction_params` - The transaction parameters.
33    /// * `maybe_id` - Optional transfer identifier.
34    ///
35    /// # Returns
36    ///
37    /// A `Result` containing the created `Transaction` or a `JsError` in case of an error.
38    #[cfg_attr(feature = "js", wasm_bindgen(js_name = "make_transfer_transaction"))]
39    #[cfg(feature = "js")]
40    pub fn make_transfer_transaction_js_alias(
41        &self,
42        maybe_source: Option<URef>,
43        target: &str,
44        amount: &str,
45        transaction_params: TransactionStrParams,
46        maybe_id: Option<String>,
47    ) -> Result<Transaction, JsError> {
48        // log("make_transfer_transaction");
49        let result = self.make_transfer_transaction(
50            maybe_source,
51            target,
52            amount,
53            transaction_params,
54            maybe_id,
55        );
56        match result {
57            Ok(data) => Ok(data),
58            Err(err) => {
59                let err = &format!("Error occurred with {err:?}");
60                Err(JsError::new(err))
61            }
62        }
63    }
64}
65
66impl SDK {
67    /// Creates a transfer transaction with the provided parameters.
68    ///
69    /// # Arguments
70    ///
71    /// * `maybe_source` - Optional transfer source uref.
72    /// * `amount` - The transfer amount.
73    /// * `target` - The target account.
74    /// * `transaction_params` - The transaction parameters.
75    /// * `maybe_id` - Optional transfer identifier.
76    ///
77    /// # Returns
78    ///
79    /// A `Result` containing the created `Transaction` or a `SdkError` in case of an error.
80    pub fn make_transfer_transaction(
81        &self,
82        maybe_source: Option<URef>,
83        target: &str,
84        amount: &str,
85        transaction_params: TransactionStrParams,
86        maybe_id: Option<String>,
87    ) -> Result<Transaction, Box<SdkError>> {
88        // log("make_transfer_transaction");
89        make_transfer_transaction(maybe_source, target, amount, transaction_params, maybe_id)
90    }
91}
92
93/// Internal function to create a transfer transaction.
94pub(crate) fn make_transfer_transaction(
95    maybe_source: Option<URef>,
96    target: &str,
97    amount: &str,
98    transaction_params: TransactionStrParams,
99    maybe_id: Option<String>,
100) -> Result<Transaction, Box<SdkError>> {
101    let id = if let Some(maybe_id) = maybe_id {
102        u64::from_str(&maybe_id).unwrap_or_else(|_| rand::rng().random::<u64>())
103    } else {
104        rand::rng().random::<u64>()
105    };
106
107    let target = transfer_target(target).map_err(|e| {
108        Box::new(SdkError::FailedToDecodeHex {
109            context: "make_transfer_transaction: transfer_target",
110            error: e.to_string(),
111        })
112    })?;
113
114    let amount = U512::from_dec_str(amount).map_err(|error| {
115        Box::new(SdkError::FailedToDecodeHex {
116            context: "make_transfer_transaction",
117            error: error.to_string(),
118        })
119    })?;
120
121    let builder_params = TransactionBuilderParams::Transfer {
122        maybe_source: maybe_source.map(Into::into),
123        target,
124        amount,
125        maybe_id: Some(id),
126    };
127
128    transaction_params.set_standard_payment(true);
129
130    let transaction = client_make_transaction(
131        builder_params,
132        transaction_str_params_to_casper_client(&transaction_params),
133        false,
134    );
135    transaction
136        .map(Into::into)
137        .map_err(|e| Box::new(SdkError::from(e)))
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143    use crate::helpers::public_key_from_secret_key;
144    use sdk_tests::{
145        config::{PAYMENT_TRANSFER_AMOUNT, TRANSFER_AMOUNT},
146        tests::helpers::{get_network_constants, get_user_secret_key},
147    };
148
149    #[tokio::test]
150    async fn test_make_transfer_transaction_with_valid_transfer_params() {
151        // Arrange
152        let sdk = SDK::new(None, None, None);
153        let (_, _, _, _, chain_name) = get_network_constants();
154        let secret_key = get_user_secret_key(None).unwrap();
155        let initiator_addr = public_key_from_secret_key(&secret_key).unwrap();
156
157        let transaction_params = TransactionStrParams::default();
158        transaction_params.set_secret_key(&secret_key);
159        transaction_params.set_chain_name(&chain_name);
160        transaction_params.set_payment_amount(PAYMENT_TRANSFER_AMOUNT);
161
162        // Act
163        let result = sdk.make_transfer_transaction(
164            None,
165            &initiator_addr,
166            TRANSFER_AMOUNT,
167            transaction_params,
168            None,
169        );
170
171        // Assert
172        assert!(result.is_ok());
173    }
174
175    #[tokio::test]
176    async fn test_make_transfer_transaction_with_valid_transfer_params_without_secret_key() {
177        // Arrange
178        let sdk = SDK::new(None, None, None);
179        let (_, _, _, _, chain_name) = get_network_constants();
180        let secret_key = get_user_secret_key(None).unwrap();
181        let initiator_addr = public_key_from_secret_key(&secret_key).unwrap();
182
183        let transaction_params = TransactionStrParams::default();
184        transaction_params.set_chain_name(&chain_name);
185        transaction_params.set_initiator_addr(&initiator_addr);
186        transaction_params.set_payment_amount(PAYMENT_TRANSFER_AMOUNT);
187
188        // Act
189        let result = sdk.make_transfer_transaction(
190            None,
191            &initiator_addr,
192            TRANSFER_AMOUNT,
193            transaction_params,
194            None,
195        );
196
197        // Assert
198        assert!(result.is_ok());
199    }
200}