spark_rust/wallet/internal_handlers/implementations/
swap.rs

1use std::collections::HashMap;
2
3use bitcoin::key::Secp256k1;
4use bitcoin::secp256k1::PublicKey;
5use spark_protos::spark::{CounterLeafSwapRequest, StartSendTransferRequest};
6use tonic::async_trait;
7use uuid::Uuid;
8
9use crate::error::SparkSdkError;
10use crate::signer::traits::SparkSigner;
11use crate::wallet::internal_handlers::traits::swap::{
12    SendSwapSignRefundsResponse, SwapInternalHandlers,
13};
14use crate::wallet::internal_handlers::traits::transfer::{
15    LeafKeyTweak, LeafRefundSigningData, TransferInternalHandlers,
16};
17use crate::wallet::utils::bitcoin::bitcoin_tx_from_bytes;
18use crate::wallet::utils::frost::frost_commitment_to_proto_commitment;
19use crate::SparkSdk;
20
21#[async_trait]
22impl<S: SparkSigner + Send + Sync + Clone + 'static> SwapInternalHandlers<S> for SparkSdk<S> {
23    #[cfg_attr(feature = "telemetry", tracing::instrument(skip_all))]
24    async fn send_swap_sign_refunds(
25        &self,
26        leaves: &Vec<LeafKeyTweak>,
27        receiver_identity_pubkey: &PublicKey,
28        expiry_time: u64,
29        adaptor_public_key: &PublicKey,
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.generate_frost_signing_commitments()?;
37
38            let secp = Secp256k1::new();
39            let signing_public_key = leaf_key.old_signing_private_key.public_key(&secp);
40
41            let leaf_refund_signing_data = LeafRefundSigningData {
42                signing_public_key,
43                receiving_pubkey: *receiver_identity_pubkey,
44                commitment: frost_commitment_to_proto_commitment(&commitments)?,
45                tx: node_tx,
46                refund_tx: None,
47                vout: leaf_key.leaf.vout,
48            };
49
50            leaf_data_map.insert(leaf_key.leaf.id.clone(), leaf_refund_signing_data);
51        }
52
53        let signing_jobs =
54            self.prepare_refund_so_signing_jobs(&leaves.to_vec(), &mut leaf_data_map)?;
55
56        let request = CounterLeafSwapRequest {
57            transfer: Some(StartSendTransferRequest {
58                transfer_id: transfer_id.clone(),
59                leaves_to_send: signing_jobs,
60                owner_identity_public_key: self.get_spark_address()?.serialize().to_vec(),
61                receiver_identity_public_key: receiver_identity_pubkey.serialize().to_vec(),
62                expiry_time: Some(prost_types::Timestamp {
63                    seconds: expiry_time as i64,
64                    nanos: 0,
65                }),
66                key_tweak_proofs: Default::default(),
67            }),
68            swap_id: Uuid::now_v7().to_string(),
69            adaptor_public_key: adaptor_public_key.serialize().to_vec(),
70        };
71
72        let response = self
73            .config
74            .spark_config
75            .call_with_retry(
76                request,
77                |mut client, req| Box::pin(async move { client.leaf_swap(req).await }),
78                None,
79            )
80            .await?;
81
82        let signatures = self.signer.sign_transfer_refunds(
83            &leaf_data_map,
84            &response.signing_results,
85            adaptor_public_key.serialize().to_vec(),
86        )?;
87
88        let mut signature_map = HashMap::new();
89        for leaf_signature in signatures {
90            signature_map.insert(leaf_signature.node_id, leaf_signature.refund_tx_signature);
91        }
92
93        Ok(SendSwapSignRefundsResponse {
94            transfer: response.transfer.unwrap(),
95            refund_signature_map: signature_map,
96            leaf_refund_signing_data: leaf_data_map,
97            leaf_refund_tx_signing_result: response.signing_results,
98        })
99    }
100}