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#[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::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#[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}