spark_sdk/wallet/internal_handlers/implementations/
swap.rs

1use std::collections::HashMap;
2
3use bitcoin::key::Secp256k1;
4use spark_protos::spark::{LeafSwapRequest, StartSendTransferRequest};
5use tonic::async_trait;
6use uuid::Uuid;
7
8use crate::error::SparkSdkError;
9use crate::signer::traits::SparkSigner;
10use crate::wallet::internal_handlers::traits::swap::{
11    SendSwapSignRefundsResponse, SwapInternalHandlers,
12};
13use crate::wallet::internal_handlers::traits::transfer::{
14    LeafKeyTweak, LeafRefundSigningData, TransferInternalHandlers,
15};
16use crate::wallet::internal_handlers::utils::parsers::parse_secret_key;
17use crate::wallet::internal_handlers::utils::{
18    bitcoin_tx_from_bytes, frost_commitment_to_proto_commitment,
19};
20use crate::SparkSdk;
21
22#[async_trait]
23impl<S: SparkSigner + Send + Sync + Clone + 'static> SwapInternalHandlers<S> for SparkSdk<S> {
24    async fn send_swap_sign_refunds(
25        &self,
26        leaves: &Vec<LeafKeyTweak>,
27        receiver_identity_pubkey: Vec<u8>,
28        expiry_time: u64,
29        adaptor_public_key: &Vec<u8>,
30    ) -> Result<SendSwapSignRefundsResponse, SparkSdkError> {
31        let transfer_id = Uuid::now_v7().to_string();
32        let mut leaf_data_map = HashMap::new();
33
34        for leaf_key in leaves {
35            let node_tx = bitcoin_tx_from_bytes(&leaf_key.leaf.node_tx)?;
36            let commitments = self.signer.new_frost_signing_noncepair()?;
37
38            let secp = Secp256k1::new();
39            let signing_secret_key = parse_secret_key(&leaf_key.old_signing_private_key)?;
40            let signing_public_key = signing_secret_key.public_key(&secp);
41
42            let leaf_refund_signing_data = LeafRefundSigningData {
43                signing_public_key: signing_public_key.serialize().to_vec(),
44                receiving_pubkey: receiver_identity_pubkey.clone(),
45                commitment: frost_commitment_to_proto_commitment(&commitments)?,
46                tx: node_tx,
47                refund_tx: None,
48                vout: leaf_key.leaf.vout,
49            };
50
51            leaf_data_map.insert(leaf_key.leaf.id.clone(), leaf_refund_signing_data);
52        }
53
54        let signing_jobs = self.prepare_refund_so_signing_jobs(leaves, &mut leaf_data_map)?;
55
56        let mut request = tonic::Request::new(LeafSwapRequest {
57            transfer: Some(StartSendTransferRequest {
58                transfer_id: transfer_id.clone(),
59                leaves_to_send: signing_jobs,
60                owner_identity_public_key: self.get_identity_public_key().to_vec(),
61                receiver_identity_public_key: receiver_identity_pubkey,
62                expiry_time: Some(prost_types::Timestamp {
63                    seconds: expiry_time as i64,
64                    nanos: 0,
65                }),
66            }),
67            swap_id: Uuid::now_v7().to_string(),
68            adaptor_public_key: adaptor_public_key.to_vec(),
69        });
70        self.add_authorization_header_to_request(&mut request, None);
71
72        let mut spark_client = self.config.spark_config.get_spark_connection(None).await?;
73        let response = spark_client.leaf_swap(request).await?.into_inner();
74
75        let signatures = self.signer.sign_transfer_refunds(
76            &leaf_data_map,
77            &response.signing_results,
78            adaptor_public_key.to_vec(),
79        )?;
80
81        let mut signature_map = HashMap::new();
82        for leaf_signature in signatures {
83            signature_map.insert(leaf_signature.node_id, leaf_signature.refund_tx_signature);
84        }
85
86        Ok(SendSwapSignRefundsResponse {
87            transfer: response.transfer.unwrap(),
88            refund_signature_map: signature_map,
89            leaf_refund_signing_data: leaf_data_map,
90            leaf_refund_tx_signing_result: response.signing_results,
91        })
92    }
93}