spark_sdk/wallet/handlers/
swap.rs1use 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 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 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 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 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}