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}