breez_sdk_liquid/
error.rs

1use anyhow::Error;
2use lwk_wollet::secp256k1;
3use sdk_common::{
4    lightning_with_bolt12::offers::parse::Bolt12SemanticError,
5    prelude::{LnUrlAuthError, LnUrlPayError, LnUrlWithdrawError},
6};
7
8use crate::payjoin::error::PayjoinError;
9
10pub type SdkResult<T, E = SdkError> = Result<T, E>;
11
12#[macro_export]
13macro_rules! ensure_sdk {
14    ($cond:expr, $err:expr) => {
15        if !$cond {
16            return Err($err);
17        }
18    };
19}
20
21// TODO Unify error enum
22#[derive(Debug, thiserror::Error)]
23pub enum SdkError {
24    #[error("Liquid SDK instance is already running")]
25    AlreadyStarted,
26
27    #[error("Error: {err}")]
28    Generic { err: String },
29
30    #[error("Liquid SDK instance is not running")]
31    NotStarted,
32
33    #[error("Service connectivity: {err}")]
34    ServiceConnectivity { err: String },
35}
36impl SdkError {
37    pub fn generic<T: AsRef<str>>(err: T) -> Self {
38        Self::Generic {
39            err: err.as_ref().to_string(),
40        }
41    }
42}
43
44impl From<anyhow::Error> for SdkError {
45    fn from(e: Error) -> Self {
46        SdkError::generic(e.to_string())
47    }
48}
49
50impl From<boltz_client::error::Error> for SdkError {
51    fn from(err: boltz_client::error::Error) -> Self {
52        match err {
53            boltz_client::error::Error::HTTP(e) => {
54                SdkError::generic(format!("Could not contact servers: {e:?}"))
55            }
56            _ => SdkError::generic(format!("{err:?}")),
57        }
58    }
59}
60
61impl From<secp256k1::Error> for SdkError {
62    fn from(err: secp256k1::Error) -> Self {
63        SdkError::generic(format!("{err:?}"))
64    }
65}
66
67#[derive(thiserror::Error, Debug)]
68pub enum PaymentError {
69    #[error("The specified funds have already been claimed")]
70    AlreadyClaimed,
71
72    #[error("The specified funds have already been sent")]
73    AlreadyPaid,
74
75    #[error("The payment is already in progress")]
76    PaymentInProgress,
77
78    #[error("Amount must be between {min} and {max}")]
79    AmountOutOfRange { min: u64, max: u64 },
80
81    #[error("Amount is missing: {err}")]
82    AmountMissing { err: String },
83
84    #[error("Asset error: {err}")]
85    AssetError { err: String },
86
87    #[error("Invalid network: {err}")]
88    InvalidNetwork { err: String },
89
90    #[error("Generic error: {err}")]
91    Generic { err: String },
92
93    #[error("The provided fees have expired")]
94    InvalidOrExpiredFees,
95
96    #[error("Cannot pay: not enough funds")]
97    InsufficientFunds,
98
99    #[error("Invalid description: {err}")]
100    InvalidDescription { err: String },
101
102    #[error("The specified invoice is not valid: {err}")]
103    InvalidInvoice { err: String },
104
105    #[error("The generated preimage is not valid")]
106    InvalidPreimage,
107
108    #[error("Boltz did not return any pairs from the request")]
109    PairsNotFound,
110
111    #[error("The payment timed out")]
112    PaymentTimeout,
113
114    #[error("Could not store the swap details locally")]
115    PersistError,
116
117    #[error("Could not process the Receive Payment: {err}")]
118    ReceiveError { err: String },
119
120    #[error("The payment has been refunded. Reason for failure: {err}")]
121    Refunded { err: String, refund_tx_id: String },
122
123    #[error("The payment is a self-transfer, which is not supported")]
124    SelfTransferNotSupported,
125
126    #[error("Could not process the Send Payment: {err}")]
127    SendError { err: String },
128
129    #[error("Could not sign the transaction: {err}")]
130    SignerError { err: String },
131}
132impl PaymentError {
133    pub(crate) fn asset_error<S: AsRef<str>>(err: S) -> Self {
134        Self::AssetError {
135            err: err.as_ref().to_string(),
136        }
137    }
138
139    pub(crate) fn generic<S: AsRef<str>>(err: S) -> Self {
140        Self::Generic {
141            err: err.as_ref().to_string(),
142        }
143    }
144
145    pub(crate) fn invalid_invoice<S: AsRef<str>>(err: S) -> Self {
146        Self::InvalidInvoice {
147            err: err.as_ref().to_string(),
148        }
149    }
150
151    pub(crate) fn invalid_network<S: AsRef<str>>(err: S) -> Self {
152        Self::InvalidNetwork {
153            err: err.as_ref().to_string(),
154        }
155    }
156
157    pub(crate) fn receive_error<S: AsRef<str>>(err: S) -> Self {
158        Self::ReceiveError {
159            err: err.as_ref().to_string(),
160        }
161    }
162
163    pub(crate) fn amount_missing<S: AsRef<str>>(err: S) -> Self {
164        Self::AmountMissing {
165            err: err.as_ref().to_string(),
166        }
167    }
168}
169
170impl From<Bolt12SemanticError> for PaymentError {
171    fn from(err: Bolt12SemanticError) -> Self {
172        PaymentError::Generic {
173            err: format!("Failed to create BOLT12 invoice: {err:?}"),
174        }
175    }
176}
177
178impl From<boltz_client::error::Error> for PaymentError {
179    fn from(err: boltz_client::error::Error) -> Self {
180        match err {
181            boltz_client::error::Error::HTTP(e) => PaymentError::Generic {
182                err: format!("Could not contact servers: {e:?}"),
183            },
184            _ => PaymentError::Generic {
185                err: format!("{err:?}"),
186            },
187        }
188    }
189}
190
191impl From<boltz_client::bitcoin::hex::HexToArrayError> for PaymentError {
192    fn from(err: boltz_client::bitcoin::hex::HexToArrayError) -> Self {
193        PaymentError::Generic {
194            err: format!("{err:?}"),
195        }
196    }
197}
198
199impl From<lwk_wollet::Error> for PaymentError {
200    fn from(err: lwk_wollet::Error) -> Self {
201        match err {
202            lwk_wollet::Error::InsufficientFunds => PaymentError::InsufficientFunds,
203            _ => PaymentError::Generic {
204                err: format!("{err:?}"),
205            },
206        }
207    }
208}
209
210#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
211impl From<lwk_wollet::UrlError> for PaymentError {
212    fn from(err: lwk_wollet::UrlError) -> Self {
213        PaymentError::Generic {
214            err: format!("{err:?}"),
215        }
216    }
217}
218
219impl From<lwk_signer::SignerError> for PaymentError {
220    fn from(err: lwk_signer::SignerError) -> Self {
221        PaymentError::SignerError {
222            err: format!("{err:?}"),
223        }
224    }
225}
226
227impl From<anyhow::Error> for PaymentError {
228    fn from(err: anyhow::Error) -> Self {
229        Self::Generic {
230            err: err.to_string(),
231        }
232    }
233}
234
235impl From<PayjoinError> for PaymentError {
236    fn from(err: PayjoinError) -> Self {
237        match err {
238            PayjoinError::InsufficientFunds => PaymentError::InsufficientFunds,
239            _ => PaymentError::Generic {
240                err: format!("{err:?}"),
241            },
242        }
243    }
244}
245
246impl From<rusqlite::Error> for PaymentError {
247    fn from(_: rusqlite::Error) -> Self {
248        Self::PersistError
249    }
250}
251
252impl From<SdkError> for PaymentError {
253    fn from(err: SdkError) -> Self {
254        Self::Generic {
255            err: err.to_string(),
256        }
257    }
258}
259
260impl From<sdk_common::bitcoin::util::bip32::Error> for PaymentError {
261    fn from(err: sdk_common::bitcoin::util::bip32::Error) -> Self {
262        Self::SignerError {
263            err: err.to_string(),
264        }
265    }
266}
267
268impl From<secp256k1::Error> for PaymentError {
269    fn from(err: secp256k1::Error) -> Self {
270        Self::Generic {
271            err: err.to_string(),
272        }
273    }
274}
275
276impl From<PaymentError> for LnUrlAuthError {
277    fn from(err: PaymentError) -> Self {
278        Self::Generic {
279            err: err.to_string(),
280        }
281    }
282}
283
284impl From<PaymentError> for LnUrlPayError {
285    fn from(err: PaymentError) -> Self {
286        Self::Generic {
287            err: err.to_string(),
288        }
289    }
290}
291
292impl From<PaymentError> for LnUrlWithdrawError {
293    fn from(err: PaymentError) -> Self {
294        Self::Generic {
295            err: err.to_string(),
296        }
297    }
298}