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