spark_sdk/wallet/handlers/split.rs
1use std::sync::Arc;
2
3use parking_lot::lock_api::RwLock;
4
5use crate::{
6 constants::spark::DUST_AMOUNT, error::SparkSdkError, signer::traits::SparkSigner,
7 wallet::internal_handlers::traits::ssp::SspInternalHandlers, SparkSdk,
8};
9
10impl<S: SparkSigner + Send + Sync + Clone + 'static> SparkSdk<S> {
11 /// Splits a leaf node into two nodes of specified target value.
12 ///
13 /// This function allows splitting a leaf node into two nodes when the SSP (Spark Service Provider) is down.
14 /// The split operation is only permitted during SSP downtime as a fallback mechanism.
15 ///
16 /// # Arguments
17 ///
18 /// * `target_value` - The target value in satoshis for one of the split nodes. Must be greater than the dust amount.
19 ///
20 /// # Returns
21 ///
22 /// * `Ok(())` if the split operation succeeds
23 /// * `Err(SparkSdkError)` if:
24 /// - The SSP is online (splits not allowed)
25 /// - Target value is below dust amount
26 /// - No suitable leaf node available for splitting
27 /// - Other errors during the split process
28 ///
29 /// # Example
30 ///
31 /// ```no_run
32 /// # use spark_wallet_sdk::{SparkSdk, error::SparkSdkError};
33 /// # async fn example(mut sdk: SparkSdk) -> Result<(), SparkSdkError> {
34 /// // Split a leaf node into two nodes, one with 10000 sats
35 /// sdk.split(10000).await?;
36 /// # Ok(())
37 /// # }
38 /// ```
39 pub async fn split(&self, target_value: u64) -> Result<(), SparkSdkError> {
40 // ping the SSP to check if it is up.
41 // user splits are only allowed if the SSP is down.
42 let ssp_status = self.ping_ssp().await?;
43 if ssp_status {
44 return Err(SparkSdkError::InvalidArgument(
45 "Cannot split: SSP is up. No user splits are allowed at this tme.".to_string(),
46 ));
47 }
48
49 // target value must be greater than the dust amount
50 if target_value < DUST_AMOUNT {
51 return Err(SparkSdkError::InvalidArgument(
52 "Target value is less than the dust amount".to_string(),
53 ));
54 }
55
56 // find the parent node applicable for the split
57 let split_root = self.leaf_manager.select_leaf_to_split(target_value)?;
58
59 // create the tree.
60 let identity_public_key = self.get_identity_public_key();
61 let network = self.get_network();
62 let signing_public_key = split_root.signing_public_key.clone();
63 self.create_tree(
64 None,
65 Some(Arc::new(RwLock::new(
66 split_root.marshal_to_tree_node(identity_public_key, &network),
67 ))),
68 0,
69 1,
70 signing_public_key,
71 )
72 .await?;
73
74 // TODO: release the statuses in the leaf manager.
75 // TODO: update the leaf manager to reflect the split. create_tree only handles incomplete and not accurate at all parts.
76
77 Ok(())
78 }
79}