1use crate::{
2 Fee,
3 lnurl::LnurlServerError,
4 persist::{self},
5};
6use bitcoin::consensus::encode::FromHexError;
7use breez_sdk_common::error::ServiceConnectivityError;
8use serde::{Deserialize, Serialize};
9use spark_wallet::SparkWalletError;
10use std::{convert::Infallible, num::TryFromIntError};
11use thiserror::Error;
12use tracing_subscriber::util::TryInitError;
13use web_time::SystemTimeError;
14
15#[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 #[error("Invalid input: {0}")]
30 InvalidInput(String),
31
32 #[error("Network error: {0}")]
34 NetworkError(String),
35
36 #[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::Sdk(e) => e,
117 ConversionError::Storage(e) => SdkError::StorageError(e.to_string()),
118 ConversionError::Wallet(e) => SdkError::SparkError(e.to_string()),
119 }
120 }
121}
122
123impl From<persist::StorageError> for SdkError {
124 fn from(e: persist::StorageError) -> Self {
125 SdkError::StorageError(e.to_string())
126 }
127}
128
129impl From<Infallible> for SdkError {
130 fn from(value: Infallible) -> Self {
131 SdkError::Generic(value.to_string())
132 }
133}
134
135impl From<String> for SdkError {
136 fn from(s: String) -> Self {
137 Self::Generic(s)
138 }
139}
140
141impl From<&str> for SdkError {
142 fn from(s: &str) -> Self {
143 Self::Generic(s.to_string())
144 }
145}
146
147impl From<SystemTimeError> for SdkError {
148 fn from(e: SystemTimeError) -> Self {
149 SdkError::Generic(e.to_string())
150 }
151}
152
153impl From<TryFromIntError> for SdkError {
154 fn from(e: TryFromIntError) -> Self {
155 SdkError::Generic(e.to_string())
156 }
157}
158
159impl From<serde_json::Error> for SdkError {
160 fn from(e: serde_json::Error) -> Self {
161 SdkError::Generic(e.to_string())
162 }
163}
164
165impl From<SparkWalletError> for SdkError {
166 fn from(e: SparkWalletError) -> Self {
167 match e {
168 SparkWalletError::InsufficientFunds => SdkError::InsufficientFunds,
169 _ => SdkError::SparkError(e.to_string()),
170 }
171 }
172}
173
174impl From<FromHexError> for SdkError {
175 fn from(e: FromHexError) -> Self {
176 SdkError::Generic(e.to_string())
177 }
178}
179
180impl From<uuid::Error> for SdkError {
181 fn from(e: uuid::Error) -> Self {
182 SdkError::InvalidUuid(e.to_string())
183 }
184}
185
186impl From<ServiceConnectivityError> for SdkError {
187 fn from(value: ServiceConnectivityError) -> Self {
188 SdkError::NetworkError(value.to_string())
189 }
190}
191
192impl From<LnurlServerError> for SdkError {
193 fn from(value: LnurlServerError) -> Self {
194 match value {
195 LnurlServerError::InvalidApiKey => {
196 SdkError::InvalidInput("Invalid api key".to_string())
197 }
198 LnurlServerError::Network {
199 statuscode,
200 message,
201 } => SdkError::NetworkError(format!(
202 "network request failed with status {statuscode}: {}",
203 message.unwrap_or(String::new())
204 )),
205 LnurlServerError::RequestFailure(e) => SdkError::NetworkError(e),
206 LnurlServerError::SigningError(e) => {
207 SdkError::Generic(format!("Failed to sign message: {e}"))
208 }
209 }
210 }
211}
212
213impl From<TryInitError> for SdkError {
214 fn from(_value: TryInitError) -> Self {
215 SdkError::Generic("Logging can only be initialized once".to_string())
216 }
217}
218
219#[derive(Debug, Clone, Serialize, Deserialize, Error, PartialEq)]
220#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
221pub enum DepositClaimError {
222 #[error(
223 "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"
224 )]
225 MaxDepositClaimFeeExceeded {
226 tx: String,
227 vout: u32,
228 max_fee: Option<Fee>,
229 required_fee_sats: u64,
230 required_fee_rate_sat_per_vbyte: u64,
231 },
232
233 #[error("Missing utxo: {tx}:{vout}")]
234 MissingUtxo { tx: String, vout: u32 },
235
236 #[error("Generic error: {message}")]
237 Generic { message: String },
238}
239
240impl From<SdkError> for DepositClaimError {
241 fn from(value: SdkError) -> Self {
242 match value {
243 SdkError::MaxDepositClaimFeeExceeded {
244 tx,
245 vout,
246 max_fee,
247 required_fee_sats,
248 required_fee_rate_sat_per_vbyte,
249 } => DepositClaimError::MaxDepositClaimFeeExceeded {
250 tx,
251 vout,
252 max_fee,
253 required_fee_sats,
254 required_fee_rate_sat_per_vbyte,
255 },
256 SdkError::MissingUtxo { tx, vout } => DepositClaimError::MissingUtxo { tx, vout },
257 SdkError::Generic(e) => DepositClaimError::Generic { message: e },
258 _ => DepositClaimError::Generic {
259 message: value.to_string(),
260 },
261 }
262 }
263}
264
265#[derive(Debug, Error, Clone)]
267#[cfg_attr(feature = "uniffi", derive(uniffi::Error))]
268pub enum SignerError {
269 #[error("Key derivation error: {0}")]
270 KeyDerivation(String),
271
272 #[error("Signing error: {0}")]
273 Signing(String),
274
275 #[error("Encryption error: {0}")]
276 Encryption(String),
277
278 #[error("Decryption error: {0}")]
279 Decryption(String),
280
281 #[error("FROST error: {0}")]
282 Frost(String),
283
284 #[error("Invalid input: {0}")]
285 InvalidInput(String),
286
287 #[error("Generic signer error: {0}")]
288 Generic(String),
289}
290
291impl From<String> for SignerError {
292 fn from(s: String) -> Self {
293 SignerError::Generic(s)
294 }
295}
296
297impl From<&str> for SignerError {
298 fn from(s: &str) -> Self {
299 SignerError::Generic(s.to_string())
300 }
301}