spark_sdk/wallet/handlers/
swap.rs

1use crate::constants::spark::DEFAULT_TRANSFER_EXPIRY;
2use crate::error::SparkSdkError;
3use crate::signer::traits::secp256k1::KeygenMethod;
4use crate::signer::traits::SparkSigner;
5use crate::wallet::internal_handlers::traits::ssp::SspInternalHandlers;
6use crate::wallet::internal_handlers::traits::ssp::SwapLeaf;
7use crate::wallet::internal_handlers::traits::transfer::LeafKeyTweak;
8use crate::wallet::internal_handlers::traits::transfer::TransferInternalHandlers;
9use crate::wallet::internal_handlers::utils::bitcoin_tx_from_bytes;
10use crate::wallet::internal_handlers::utils::parsers::parse_public_key;
11use crate::wallet::internal_handlers::utils::parsers::parse_secret_key;
12use crate::wallet::utils::bitcoin::sighash_from_tx;
13use crate::SparkSdk;
14use bitcoin::key::Secp256k1;
15use spark_cryptography::adaptor_signature::apply_adaptor_to_signature;
16use spark_cryptography::adaptor_signature::generate_adaptor_from_signature;
17use spark_cryptography::adaptor_signature::generate_signature_from_existing_adaptor;
18use spark_protos::spark::query_nodes_request::Source;
19use spark_protos::spark::QueryNodesRequest;
20use spark_protos::spark::TreeNodeIds;
21use std::collections::HashMap;
22
23impl<S: SparkSigner + Send + Sync + Clone + 'static> SparkSdk<S> {
24    pub async fn request_leaves_swap(
25        &self,
26        target_amount: u64,
27        leaf_ids: Vec<String>,
28    ) -> Result<(), SparkSdkError> {
29        // leaf selection for atomic swap
30        let mut leaf_key_tweaks = Vec::with_capacity(leaf_ids.len());
31        let mut nodes_to_remove = HashMap::new();
32
33        println!("here 1");
34
35        for leaf_id in leaf_ids.iter() {
36            let node = self.leaf_manager.get_node(leaf_id)?;
37
38            let tree_leaf =
39                node.marshal_to_tree_node(self.get_identity_public_key(), &self.get_network());
40
41            let old_pubkey = node.signing_public_key.clone();
42            let old_secret_key = self
43                .signer
44                .sensitive_expose_secret_key_from_pubkey(old_pubkey, false)?;
45
46            // Generate new private key for the leaf
47            let new_signing_public_key = self.signer.new_secp256k1_keypair(KeygenMethod::Random)?;
48
49            leaf_key_tweaks.push(LeafKeyTweak {
50                leaf: tree_leaf,
51                old_signing_private_key: old_secret_key,
52                new_signing_public_key,
53            });
54
55            nodes_to_remove.insert(leaf_id.clone(), true);
56
57            println!("here for n");
58        }
59
60        println!("here 2");
61
62        let expiry_time = chrono::Utc::now().timestamp() as u64 + DEFAULT_TRANSFER_EXPIRY;
63
64        let ssp_public_key = &self.config.spark_config.ssp_identity_public_key;
65        let (transfer, refund_signature_map) = self
66            .send_transfer_sign_refunds(&leaf_key_tweaks, ssp_public_key.to_vec(), expiry_time)
67            .await?;
68
69        println!("here 3");
70
71        // TODO: map
72        let leaf = transfer.leaves[0].leaf.as_ref().unwrap();
73        let leaf_refund_signature = refund_signature_map[&leaf.id].clone();
74
75        let adaptor_signature =
76            generate_adaptor_from_signature(leaf_refund_signature.as_slice().try_into().unwrap())
77                .unwrap();
78
79        println!("here 4");
80
81        let mut user_leaves = Vec::new();
82        user_leaves.push(SwapLeaf {
83            leaf_id: transfer.leaves[0].leaf.as_ref().unwrap().id.clone(),
84            raw_unsigned_refund_transaction: hex::encode(
85                &transfer.leaves[0].intermediate_refund_tx,
86            ),
87            adaptor_added_signature: hex::encode(&adaptor_signature.signature),
88        });
89
90        println!("here 5");
91
92        for leaf in transfer.leaves.iter().skip(1) {
93            let leaf_id = leaf.leaf.as_ref().unwrap().id.clone();
94            let leaf_refund_signature = refund_signature_map[&leaf_id].clone();
95
96            let signature = generate_signature_from_existing_adaptor(
97                &leaf_refund_signature,
98                adaptor_signature.adaptor_private_key.as_slice(),
99            )
100            .unwrap();
101
102            user_leaves.push(SwapLeaf {
103                leaf_id,
104                raw_unsigned_refund_transaction: hex::encode(&leaf.intermediate_refund_tx),
105                adaptor_added_signature: hex::encode(&signature),
106            });
107
108            println!("here for n leaf");
109        }
110
111        println!("here 6");
112
113        // total leaf value
114        let total_amount = leaf_key_tweaks
115            .iter()
116            .map(|leaf| leaf.leaf.value)
117            .sum::<u64>();
118
119        let secp = Secp256k1::new();
120        let adaptor_private_key =
121            parse_secret_key(&adaptor_signature.adaptor_private_key.to_vec())?;
122        let adaptor_public_key = adaptor_private_key.public_key(&secp);
123
124        println!("here 7");
125
126        let (request_id, leaves) = self
127            .request_swap_leaves_with_ssp(
128                hex::encode(adaptor_public_key.serialize()),
129                total_amount,
130                target_amount,
131                0,
132                self.config.spark_config.network.clone(),
133                user_leaves,
134            )
135            .await?;
136
137        println!("here 8");
138
139        let mut spark_client = self.config.spark_config.get_spark_connection(None).await?;
140
141        for leaf in &leaves {
142            let leaf_id = leaf.leaf_id.clone();
143            let response = spark_client
144                .query_nodes(QueryNodesRequest {
145                    source: Some(Source::NodeIds(TreeNodeIds {
146                        node_ids: vec![leaf_id.clone()],
147                    })),
148                    include_parents: Default::default(),
149                })
150                .await?
151                .into_inner();
152
153            let node = response
154                .nodes
155                .get(&leaf_id)
156                .ok_or(SparkSdkError::InvalidResponse("Missing node".into()))?;
157
158            let node_tx = bitcoin_tx_from_bytes(&node.node_tx)?;
159            let refund_tx_bytes = hex::decode(&leaf.raw_unsigned_refund_transaction)?;
160            let refund_tx = bitcoin_tx_from_bytes(&refund_tx_bytes)?;
161
162            let sighash = sighash_from_tx(&refund_tx, 0, &node_tx.output[0])?;
163            let verifying_public_key = parse_public_key(&node.verifying_public_key)?;
164            let taproot_key = bitcoin::Address::p2tr(
165                &secp,
166                verifying_public_key.x_only_public_key().0,
167                None,
168                self.config.spark_config.network.to_bitcoin_network(),
169            )
170            .script_pubkey();
171
172            let adaptor_signature_bytes = hex::decode(&leaf.adaptor_added_signature)?;
173
174            let _ = apply_adaptor_to_signature(
175                &taproot_key.to_bytes(),
176                &sighash,
177                &adaptor_signature_bytes,
178                &adaptor_private_key.secret_bytes(),
179            )
180            .unwrap();
181        }
182
183        let transfer_id = transfer.id.clone();
184        self.send_transfer_tweak_key(transfer.clone(), &leaf_key_tweaks, &refund_signature_map)
185            .await?;
186
187        self.complete_leaves_swap_with_ssp(
188            hex::encode(adaptor_private_key.secret_bytes()),
189            transfer_id,
190            request_id.clone(),
191        )
192        .await?;
193
194        println!("here");
195        println!("Logging data below...");
196        println!("transfer: {:?}", transfer);
197        println!("leaves: {:?}", leaves);
198        println!("leaf_key_tweaks: {:?}", leaf_key_tweaks);
199        println!("refund_signature_map: {:?}", refund_signature_map);
200        println!("request_id: {:?}", request_id);
201
202        Ok(())
203    }
204}