Skip to main content

breez_sdk_spark/signer/
external_spark_adapter.rs

1//! Adapter from a foreign [`ExternalSparkSigner`] to a native
2//! `spark_wallet::SparkSigner`.
3//!
4//! Converts each native request into its FFI mirror, calls the foreign signer,
5//! and converts the FFI response back into the native type.
6
7use std::sync::Arc;
8
9use bitcoin::secp256k1::{PublicKey, ecdsa, schnorr};
10use spark_wallet::{
11    FrostJob, FrostShareResult, PrepareClaimRequest, PrepareLightningReceiveRequest,
12    PrepareStaticDepositClaimRequest, PrepareStaticDepositRequest, PrepareTokenTransactionRequest,
13    PrepareTransferRequest, PreparedClaim, PreparedLightningReceive, PreparedStaticDeposit,
14    PreparedStaticDepositClaim, PreparedTokenTransaction, PreparedTransfer,
15    SignSparkInvoiceRequest, SignStaticDepositRefundRequest, SignWatchtowerExitRecoveryRequest,
16    SignedSparkInvoice, SignerError, StartStaticDepositRefundRequest,
17    StartWatchtowerExitRecoveryRequest, StartedStaticDepositRefund, StartedWatchtowerExitRecovery,
18    TreeNodeId,
19};
20
21use super::ExternalSparkSigner;
22use super::external_spark_types::{
23    ExternalFrostJob, ExternalFrostShareResult, ExternalPrepareClaimRequest,
24    ExternalPrepareLightningReceiveRequest, ExternalPrepareStaticDepositClaimRequest,
25    ExternalPrepareStaticDepositRequest, ExternalPrepareTokenTransactionRequest,
26    ExternalPrepareTransferRequest, ExternalSignSparkInvoiceRequest,
27    ExternalSignStaticDepositRefundRequest, ExternalSignWatchtowerExitRecoveryRequest,
28    ExternalStartStaticDepositRefundRequest, ExternalStartWatchtowerExitRecoveryRequest,
29};
30use super::external_types::ExternalTreeNodeId;
31
32/// Wraps a foreign [`ExternalSparkSigner`] and implements the native
33/// `spark_wallet::SparkSigner` over it.
34pub struct ExternalSparkSignerAdapter {
35    inner: Arc<dyn ExternalSparkSigner>,
36}
37
38impl ExternalSparkSignerAdapter {
39    pub fn new(inner: Arc<dyn ExternalSparkSigner>) -> Self {
40        Self { inner }
41    }
42}
43
44fn to_spark_err<E: std::fmt::Display>(e: E) -> SignerError {
45    SignerError::Generic(e.to_string())
46}
47
48#[macros::async_trait]
49impl spark_wallet::SparkSigner for ExternalSparkSignerAdapter {
50    async fn get_identity_public_key(&self) -> Result<PublicKey, SignerError> {
51        self.inner
52            .get_identity_public_key()
53            .await
54            .map_err(to_spark_err)?
55            .to_public_key()
56            .map_err(to_spark_err)
57    }
58
59    async fn get_public_key_for_leaf(
60        &self,
61        leaf_id: &TreeNodeId,
62    ) -> Result<PublicKey, SignerError> {
63        let ext = ExternalTreeNodeId::from_tree_node_id(leaf_id).map_err(to_spark_err)?;
64        self.inner
65            .get_public_key_for_leaf(ext)
66            .await
67            .map_err(to_spark_err)?
68            .to_public_key()
69            .map_err(to_spark_err)
70    }
71
72    fn is_remote(&self) -> bool {
73        self.inner.is_remote()
74    }
75
76    async fn get_static_deposit_public_key(&self, index: u32) -> Result<PublicKey, SignerError> {
77        self.inner
78            .get_static_deposit_public_key(index)
79            .await
80            .map_err(to_spark_err)?
81            .to_public_key()
82            .map_err(to_spark_err)
83    }
84
85    async fn sign_authentication_challenge(
86        &self,
87        challenge: &[u8],
88    ) -> Result<ecdsa::Signature, SignerError> {
89        self.inner
90            .sign_authentication_challenge(challenge.to_vec())
91            .await
92            .map_err(to_spark_err)?
93            .to_signature()
94            .map_err(to_spark_err)
95    }
96
97    async fn sign_message(&self, message: &[u8]) -> Result<ecdsa::Signature, SignerError> {
98        self.inner
99            .sign_message(message.to_vec())
100            .await
101            .map_err(to_spark_err)?
102            .to_signature()
103            .map_err(to_spark_err)
104    }
105
106    async fn sign_leaf_refund_spend(
107        &self,
108        leaf_id: &TreeNodeId,
109        sighash: &[u8],
110    ) -> Result<schnorr::Signature, SignerError> {
111        let ext = ExternalTreeNodeId::from_tree_node_id(leaf_id).map_err(to_spark_err)?;
112        self.inner
113            .sign_leaf_refund_spend(ext, sighash.to_vec())
114            .await
115            .map_err(to_spark_err)?
116            .to_signature()
117            .map_err(to_spark_err)
118    }
119
120    async fn sign_frost(&self, jobs: Vec<FrostJob>) -> Result<Vec<FrostShareResult>, SignerError> {
121        let ext_jobs = jobs
122            .iter()
123            .map(ExternalFrostJob::from_frost_job)
124            .collect::<Result<Vec<_>, _>>()
125            .map_err(to_spark_err)?;
126        let results = self
127            .inner
128            .sign_frost(ext_jobs)
129            .await
130            .map_err(to_spark_err)?;
131        results
132            .iter()
133            .map(ExternalFrostShareResult::to_frost_share_result)
134            .collect::<Result<Vec<_>, _>>()
135            .map_err(to_spark_err)
136    }
137
138    async fn prepare_transfer(
139        &self,
140        request: PrepareTransferRequest,
141    ) -> Result<PreparedTransfer, SignerError> {
142        let ext = ExternalPrepareTransferRequest::from_prepare_transfer_request(&request)
143            .map_err(to_spark_err)?;
144        self.inner
145            .prepare_transfer(ext)
146            .await
147            .map_err(to_spark_err)?
148            .to_prepared_transfer()
149            .map_err(to_spark_err)
150    }
151
152    async fn prepare_claim(
153        &self,
154        request: PrepareClaimRequest,
155    ) -> Result<PreparedClaim, SignerError> {
156        let ext = ExternalPrepareClaimRequest::from_prepare_claim_request(&request)
157            .map_err(to_spark_err)?;
158        self.inner
159            .prepare_claim(ext)
160            .await
161            .map_err(to_spark_err)?
162            .to_prepared_claim()
163            .map_err(to_spark_err)
164    }
165
166    async fn prepare_lightning_receive(
167        &self,
168        request: PrepareLightningReceiveRequest,
169    ) -> Result<PreparedLightningReceive, SignerError> {
170        let ext = ExternalPrepareLightningReceiveRequest::from_prepare_lightning_receive_request(
171            &request,
172        )
173        .map_err(to_spark_err)?;
174        self.inner
175            .prepare_lightning_receive(ext)
176            .await
177            .map_err(to_spark_err)?
178            .to_prepared_lightning_receive()
179            .map_err(to_spark_err)
180    }
181
182    async fn prepare_static_deposit(
183        &self,
184        request: PrepareStaticDepositRequest,
185    ) -> Result<PreparedStaticDeposit, SignerError> {
186        let ext =
187            ExternalPrepareStaticDepositRequest::from_prepare_static_deposit_request(&request)
188                .map_err(to_spark_err)?;
189        self.inner
190            .prepare_static_deposit(ext)
191            .await
192            .map_err(to_spark_err)?
193            .to_prepared_static_deposit()
194            .map_err(to_spark_err)
195    }
196
197    async fn start_static_deposit_refund(
198        &self,
199        request: StartStaticDepositRefundRequest,
200    ) -> Result<StartedStaticDepositRefund, SignerError> {
201        let ext =
202            ExternalStartStaticDepositRefundRequest::from_start_static_deposit_refund_request(
203                &request,
204            )
205            .map_err(to_spark_err)?;
206        self.inner
207            .start_static_deposit_refund(ext)
208            .await
209            .map_err(to_spark_err)?
210            .to_started_static_deposit_refund()
211            .map_err(to_spark_err)
212    }
213
214    async fn sign_static_deposit_refund(
215        &self,
216        request: SignStaticDepositRefundRequest,
217    ) -> Result<frost_secp256k1_tr::Signature, SignerError> {
218        let ext = ExternalSignStaticDepositRefundRequest::from_sign_static_deposit_refund_request(
219            &request,
220        )
221        .map_err(to_spark_err)?;
222        self.inner
223            .sign_static_deposit_refund(ext)
224            .await
225            .map_err(to_spark_err)?
226            .to_frost_signature()
227            .map_err(to_spark_err)
228    }
229
230    async fn start_watchtower_exit_recovery(
231        &self,
232        request: StartWatchtowerExitRecoveryRequest,
233    ) -> Result<StartedWatchtowerExitRecovery, SignerError> {
234        let ext =
235            ExternalStartWatchtowerExitRecoveryRequest::from_start_watchtower_exit_recovery_request(
236                &request,
237            )
238            .map_err(to_spark_err)?;
239        self.inner
240            .start_watchtower_exit_recovery(ext)
241            .await
242            .map_err(to_spark_err)?
243            .to_started_watchtower_exit_recovery()
244            .map_err(to_spark_err)
245    }
246
247    async fn sign_watchtower_exit_recovery(
248        &self,
249        request: SignWatchtowerExitRecoveryRequest,
250    ) -> Result<frost_secp256k1_tr::Signature, SignerError> {
251        let ext =
252            ExternalSignWatchtowerExitRecoveryRequest::from_sign_watchtower_exit_recovery_request(
253                &request,
254            )
255            .map_err(to_spark_err)?;
256        self.inner
257            .sign_watchtower_exit_recovery(ext)
258            .await
259            .map_err(to_spark_err)?
260            .to_frost_signature()
261            .map_err(to_spark_err)
262    }
263
264    async fn sign_spark_invoice(
265        &self,
266        request: SignSparkInvoiceRequest,
267    ) -> Result<SignedSparkInvoice, SignerError> {
268        let ext = ExternalSignSparkInvoiceRequest::from_sign_spark_invoice_request(&request)
269            .map_err(to_spark_err)?;
270        self.inner
271            .sign_spark_invoice(ext)
272            .await
273            .map_err(to_spark_err)?
274            .to_signed_spark_invoice()
275            .map_err(to_spark_err)
276    }
277
278    async fn prepare_token_transaction(
279        &self,
280        request: PrepareTokenTransactionRequest,
281    ) -> Result<PreparedTokenTransaction, SignerError> {
282        let ext = ExternalPrepareTokenTransactionRequest::from_prepare_token_transaction_request(
283            &request,
284        )
285        .map_err(to_spark_err)?;
286        self.inner
287            .prepare_token_transaction(ext)
288            .await
289            .map_err(to_spark_err)?
290            .to_prepared_token_transaction()
291            .map_err(to_spark_err)
292    }
293
294    async fn prepare_static_deposit_claim(
295        &self,
296        request: PrepareStaticDepositClaimRequest,
297    ) -> Result<PreparedStaticDepositClaim, SignerError> {
298        let ext =
299            ExternalPrepareStaticDepositClaimRequest::from_prepare_static_deposit_claim_request(
300                &request,
301            )
302            .map_err(to_spark_err)?;
303        self.inner
304            .prepare_static_deposit_claim(ext)
305            .await
306            .map_err(to_spark_err)?
307            .to_prepared_static_deposit_claim()
308            .map_err(to_spark_err)
309    }
310}