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