breez_sdk_spark/
error.rs

1use crate::{
2    Fee,
3    lnurl::LnurlServerError,
4    persist::{self},
5};
6use bitcoin::consensus::encode::FromHexError;
7use breez_sdk_common::error::ServiceConnectivityError;
8use platform_utils::time::SystemTimeError;
9use serde::{Deserialize, Serialize};
10use spark_wallet::SparkWalletError;
11use std::{convert::Infallible, num::TryFromIntError};
12use thiserror::Error;
13use tracing_subscriber::util::TryInitError;
14
15/// Error type for the `BreezSdk`
16#[derive(Debug, Error, Clone)]
17#[cfg_attr(feature = "uniffi", derive(uniffi::Error))]
18pub enum SdkError {
19    #[error("SparkSdkError: {0}")]
20    SparkError(String),
21
22    #[error("Insufficient funds")]
23    InsufficientFunds,
24
25    #[error("Invalid UUID: {0}")]
26    InvalidUuid(String),
27
28    /// Invalid input error
29    #[error("Invalid input: {0}")]
30    InvalidInput(String),
31
32    /// Network error
33    #[error("Network error: {0}")]
34    NetworkError(String),
35
36    /// Storage error
37    #[error("Storage error: {0}")]
38    StorageError(String),
39
40    #[error("Chain service error: {0}")]
41    ChainServiceError(String),
42
43    #[error(
44        "Max deposit claim fee exceeded for utxo: {tx}:{vout} with max fee: {max_fee:?} and required fee: {required_fee_sats} sats or {required_fee_rate_sat_per_vbyte} sats/vbyte"
45    )]
46    MaxDepositClaimFeeExceeded {
47        tx: String,
48        vout: u32,
49        max_fee: Option<Fee>,
50        required_fee_sats: u64,
51        required_fee_rate_sat_per_vbyte: u64,
52    },
53
54    #[error("Missing utxo: {tx}:{vout}")]
55    MissingUtxo { tx: String, vout: u32 },
56
57    #[error("Lnurl error: {0}")]
58    LnurlError(String),
59
60    #[error("Signer error: {0}")]
61    Signer(String),
62
63    #[error("Error: {0}")]
64    Generic(String),
65}
66
67impl From<crate::chain::ChainServiceError> for SdkError {
68    fn from(e: crate::chain::ChainServiceError) -> Self {
69        SdkError::ChainServiceError(e.to_string())
70    }
71}
72
73impl From<breez_sdk_common::lnurl::error::LnurlError> for SdkError {
74    fn from(e: breez_sdk_common::lnurl::error::LnurlError) -> Self {
75        SdkError::LnurlError(e.to_string())
76    }
77}
78
79impl From<breez_sdk_common::input::ParseError> for SdkError {
80    fn from(e: breez_sdk_common::input::ParseError) -> Self {
81        SdkError::InvalidInput(e.to_string())
82    }
83}
84
85impl From<bitcoin::address::ParseError> for SdkError {
86    fn from(e: bitcoin::address::ParseError) -> Self {
87        SdkError::InvalidInput(e.to_string())
88    }
89}
90
91impl From<flashnet::FlashnetError> for SdkError {
92    fn from(e: flashnet::FlashnetError) -> Self {
93        match e {
94            flashnet::FlashnetError::Network { reason, code } => {
95                let code = match code {
96                    Some(c) => format!(" (code: {c})"),
97                    None => String::new(),
98                };
99                SdkError::NetworkError(format!("{reason}{code}"))
100            }
101            _ => SdkError::Generic(e.to_string()),
102        }
103    }
104}
105
106impl From<crate::token_conversion::ConversionError> for SdkError {
107    fn from(e: crate::token_conversion::ConversionError) -> Self {
108        use crate::token_conversion::ConversionError;
109        match e {
110            ConversionError::NoPoolsAvailable => {
111                SdkError::Generic("No conversion pools available".to_string())
112            }
113            ConversionError::ConversionFailed(msg)
114            | ConversionError::ValidationFailed(msg)
115            | ConversionError::RefundFailed(msg) => SdkError::Generic(msg),
116            ConversionError::DuplicateTransfer => {
117                SdkError::Generic("Duplicate transfer: conversion already handled".to_string())
118            }
119            ConversionError::Sdk(e) => e,
120            ConversionError::Storage(e) => SdkError::StorageError(e.to_string()),
121            ConversionError::Wallet(e) => SdkError::SparkError(e.to_string()),
122        }
123    }
124}
125
126impl From<persist::StorageError> for SdkError {
127    fn from(e: persist::StorageError) -> Self {
128        match e {
129            persist::StorageError::NotFound => SdkError::InvalidInput("Not found".to_string()),
130            _ => SdkError::StorageError(e.to_string()),
131        }
132    }
133}
134
135impl From<Infallible> for SdkError {
136    fn from(value: Infallible) -> Self {
137        SdkError::Generic(value.to_string())
138    }
139}
140
141impl From<String> for SdkError {
142    fn from(s: String) -> Self {
143        Self::Generic(s)
144    }
145}
146
147impl From<&str> for SdkError {
148    fn from(s: &str) -> Self {
149        Self::Generic(s.to_string())
150    }
151}
152
153impl From<SystemTimeError> for SdkError {
154    fn from(e: SystemTimeError) -> Self {
155        SdkError::Generic(e.to_string())
156    }
157}
158
159impl From<TryFromIntError> for SdkError {
160    fn from(e: TryFromIntError) -> Self {
161        SdkError::Generic(e.to_string())
162    }
163}
164
165impl From<serde_json::Error> for SdkError {
166    fn from(e: serde_json::Error) -> Self {
167        SdkError::Generic(e.to_string())
168    }
169}
170
171impl From<SparkWalletError> for SdkError {
172    fn from(e: SparkWalletError) -> Self {
173        match e {
174            SparkWalletError::InsufficientFunds => SdkError::InsufficientFunds,
175            SparkWalletError::ServiceError(spark_wallet::ServiceError::InvalidInput(msg)) => {
176                SdkError::InvalidInput(msg)
177            }
178            _ => SdkError::SparkError(e.to_string()),
179        }
180    }
181}
182
183impl From<FromHexError> for SdkError {
184    fn from(e: FromHexError) -> Self {
185        SdkError::Generic(e.to_string())
186    }
187}
188
189impl From<uuid::Error> for SdkError {
190    fn from(e: uuid::Error) -> Self {
191        SdkError::InvalidUuid(e.to_string())
192    }
193}
194
195impl From<ServiceConnectivityError> for SdkError {
196    fn from(value: ServiceConnectivityError) -> Self {
197        SdkError::NetworkError(value.to_string())
198    }
199}
200
201impl From<LnurlServerError> for SdkError {
202    fn from(value: LnurlServerError) -> Self {
203        match value {
204            LnurlServerError::InvalidApiKey => {
205                SdkError::InvalidInput("Invalid api key".to_string())
206            }
207            LnurlServerError::Network {
208                statuscode,
209                message,
210            } => SdkError::NetworkError(format!(
211                "network request failed with status {statuscode}: {}",
212                message.unwrap_or(String::new())
213            )),
214            LnurlServerError::RequestFailure(e) => SdkError::NetworkError(e),
215            LnurlServerError::SigningError(e) => {
216                SdkError::Generic(format!("Failed to sign message: {e}"))
217            }
218        }
219    }
220}
221
222impl From<TryInitError> for SdkError {
223    fn from(_value: TryInitError) -> Self {
224        SdkError::Generic("Logging can only be initialized once".to_string())
225    }
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize, Error, PartialEq)]
229#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
230pub enum DepositClaimError {
231    #[error(
232        "Max deposit claim fee exceeded for utxo: {tx}:{vout} with max fee: {max_fee:?} and required fee: {required_fee_sats} sats or {required_fee_rate_sat_per_vbyte} sats/vbyte"
233    )]
234    MaxDepositClaimFeeExceeded {
235        tx: String,
236        vout: u32,
237        max_fee: Option<Fee>,
238        required_fee_sats: u64,
239        required_fee_rate_sat_per_vbyte: u64,
240    },
241
242    #[error("Missing utxo: {tx}:{vout}")]
243    MissingUtxo { tx: String, vout: u32 },
244
245    #[error("Generic error: {message}")]
246    Generic { message: String },
247}
248
249impl From<SdkError> for DepositClaimError {
250    fn from(value: SdkError) -> Self {
251        match value {
252            SdkError::MaxDepositClaimFeeExceeded {
253                tx,
254                vout,
255                max_fee,
256                required_fee_sats,
257                required_fee_rate_sat_per_vbyte,
258            } => DepositClaimError::MaxDepositClaimFeeExceeded {
259                tx,
260                vout,
261                max_fee,
262                required_fee_sats,
263                required_fee_rate_sat_per_vbyte,
264            },
265            SdkError::MissingUtxo { tx, vout } => DepositClaimError::MissingUtxo { tx, vout },
266            SdkError::Generic(e) => DepositClaimError::Generic { message: e },
267            _ => DepositClaimError::Generic {
268                message: value.to_string(),
269            },
270        }
271    }
272}
273
274/// Error type for signer operations
275#[derive(Debug, Error, Clone)]
276#[cfg_attr(feature = "uniffi", derive(uniffi::Error))]
277pub enum SignerError {
278    #[error("Key derivation error: {0}")]
279    KeyDerivation(String),
280
281    #[error("Signing error: {0}")]
282    Signing(String),
283
284    #[error("Encryption error: {0}")]
285    Encryption(String),
286
287    #[error("Decryption error: {0}")]
288    Decryption(String),
289
290    #[error("FROST error: {0}")]
291    Frost(String),
292
293    #[error("Invalid input: {0}")]
294    InvalidInput(String),
295
296    #[error("Generic signer error: {0}")]
297    Generic(String),
298}
299
300impl From<String> for SignerError {
301    fn from(s: String) -> Self {
302        SignerError::Generic(s)
303    }
304}
305
306impl From<&str> for SignerError {
307    fn from(s: &str) -> Self {
308        SignerError::Generic(s.to_string())
309    }
310}