boltz_client/
error.rs

1use std::fmt::{Display, Formatter};
2
3use secp256k1_musig::musig;
4use secp256k1_musig::scalar;
5use serde_json::Value;
6
7/// The Global Error enum. Encodes all possible internal library errors
8#[derive(Debug)]
9pub enum Error {
10    #[cfg(feature = "electrum")]
11    #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
12    Electrum(electrum_client::Error),
13    #[cfg(feature = "esplora")]
14    Esplora(String),
15    Hex(String),
16    Protocol(String),
17    Key(bitcoin::key::ParsePublicKeyError),
18    Address(String),
19    Sighash(bitcoin::sighash::TaprootError),
20    ElSighash(elements::sighash::Error),
21    Secp(bitcoin::secp256k1::Error),
22    HTTP(String),
23    JSON(serde_json::Error),
24    IO(std::io::Error),
25    Bolt11(lightning_invoice::ParseOrSemanticError),
26    LiquidEncode(elements::encode::Error),
27    BitcoinEncode(bitcoin::consensus::encode::Error),
28    Blind(String),
29    ConfidentialTx(elements::ConfidentialTxOutError),
30    BIP32(bitcoin::bip32::Error),
31    BIP39(bip39::Error),
32    BIP85(bip85_extended::Error),
33    Hash(bitcoin::hashes::FromSliceError),
34    Locktime(String),
35    Url(url::ParseError),
36    #[cfg(feature = "ws")]
37    WebSocket(Box<tokio_tungstenite_wasm::Error>),
38    Taproot(String),
39    Musig2(String),
40    Generic(String),
41    HTTPStatusNotSuccess(reqwest::StatusCode, Value),
42}
43
44#[cfg(feature = "electrum")]
45#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
46impl From<electrum_client::Error> for Error {
47    fn from(value: electrum_client::Error) -> Self {
48        Self::Electrum(value)
49    }
50}
51
52impl From<bitcoin::hex::HexToBytesError> for Error {
53    fn from(value: bitcoin::hex::HexToBytesError) -> Self {
54        Self::Hex(value.to_string())
55    }
56}
57
58impl From<bitcoin::key::ParsePublicKeyError> for Error {
59    fn from(value: bitcoin::key::ParsePublicKeyError) -> Self {
60        Self::Key(value)
61    }
62}
63
64impl From<bitcoin::hex::HexToArrayError> for Error {
65    fn from(value: bitcoin::hex::HexToArrayError) -> Self {
66        Self::Hex(value.to_string())
67    }
68}
69
70impl From<hex::FromHexError> for Error {
71    fn from(value: hex::FromHexError) -> Self {
72        Self::Hex(value.to_string())
73    }
74}
75
76impl From<bitcoin::address::ParseError> for Error {
77    fn from(value: bitcoin::address::ParseError) -> Self {
78        Self::Address(value.to_string())
79    }
80}
81
82impl From<elements::address::AddressError> for Error {
83    fn from(value: elements::address::AddressError) -> Self {
84        Self::Address(value.to_string())
85    }
86}
87
88impl From<elements::sighash::Error> for Error {
89    fn from(value: elements::sighash::Error) -> Self {
90        Self::ElSighash(value)
91    }
92}
93
94impl From<bitcoin::sighash::TaprootError> for Error {
95    fn from(value: bitcoin::sighash::TaprootError) -> Self {
96        Self::Sighash(value)
97    }
98}
99
100impl From<bitcoin::secp256k1::Error> for Error {
101    fn from(value: bitcoin::secp256k1::Error) -> Self {
102        Self::Secp(value)
103    }
104}
105
106impl From<reqwest::Error> for Error {
107    fn from(value: reqwest::Error) -> Self {
108        Self::HTTP(value.to_string())
109    }
110}
111
112impl From<serde_json::Error> for Error {
113    fn from(value: serde_json::Error) -> Self {
114        Self::JSON(value)
115    }
116}
117
118impl From<std::io::Error> for Error {
119    fn from(value: std::io::Error) -> Self {
120        Self::IO(value)
121    }
122}
123
124impl From<lightning_invoice::ParseOrSemanticError> for Error {
125    fn from(value: lightning_invoice::ParseOrSemanticError) -> Self {
126        Self::Bolt11(value)
127    }
128}
129
130impl From<elements::hex::Error> for Error {
131    fn from(value: elements::hex::Error) -> Self {
132        Self::Hex(value.to_string())
133    }
134}
135
136impl From<elements::encode::Error> for Error {
137    fn from(value: elements::encode::Error) -> Self {
138        Self::LiquidEncode(value)
139    }
140}
141
142impl From<elements::BlindError> for Error {
143    fn from(value: elements::BlindError) -> Self {
144        Self::Blind(value.to_string())
145    }
146}
147
148impl From<elements::UnblindError> for Error {
149    fn from(value: elements::UnblindError) -> Self {
150        Self::Blind(value.to_string())
151    }
152}
153
154impl From<elements::ConfidentialTxOutError> for Error {
155    fn from(value: elements::ConfidentialTxOutError) -> Self {
156        Self::ConfidentialTx(value)
157    }
158}
159
160impl From<bitcoin::bip32::Error> for Error {
161    fn from(value: bitcoin::bip32::Error) -> Self {
162        Self::BIP32(value)
163    }
164}
165
166impl From<bitcoin::hashes::FromSliceError> for Error {
167    fn from(value: bitcoin::hashes::FromSliceError) -> Self {
168        Self::Hash(value)
169    }
170}
171
172impl From<bip39::Error> for Error {
173    fn from(value: bip39::Error) -> Self {
174        Self::BIP39(value)
175    }
176}
177
178impl From<bip85_extended::Error> for Error {
179    fn from(value: bip85_extended::Error) -> Self {
180        Self::BIP85(value)
181    }
182}
183
184impl From<bitcoin::absolute::ConversionError> for Error {
185    fn from(value: bitcoin::absolute::ConversionError) -> Self {
186        Self::Locktime(value.to_string())
187    }
188}
189
190impl From<elements::locktime::Error> for Error {
191    fn from(value: elements::locktime::Error) -> Self {
192        Self::Locktime(value.to_string())
193    }
194}
195
196impl From<url::ParseError> for Error {
197    fn from(value: url::ParseError) -> Self {
198        Self::Url(value)
199    }
200}
201
202#[cfg(feature = "ws")]
203impl From<tokio_tungstenite_wasm::Error> for Error {
204    fn from(value: tokio_tungstenite_wasm::Error) -> Self {
205        Self::WebSocket(value.into())
206    }
207}
208
209impl From<bitcoin::taproot::TaprootError> for Error {
210    fn from(value: bitcoin::taproot::TaprootError) -> Self {
211        Self::Taproot(value.to_string())
212    }
213}
214
215impl From<elements::taproot::TaprootError> for Error {
216    fn from(value: elements::taproot::TaprootError) -> Self {
217        Self::Taproot(value.to_string())
218    }
219}
220
221impl From<elements::taproot::TaprootBuilderError> for Error {
222    fn from(value: elements::taproot::TaprootBuilderError) -> Self {
223        Self::Taproot(value.to_string())
224    }
225}
226
227impl From<bitcoin::taproot::TaprootBuilderError> for Error {
228    fn from(value: bitcoin::taproot::TaprootBuilderError) -> Self {
229        Self::Taproot(value.to_string())
230    }
231}
232
233impl From<bitcoin::consensus::encode::Error> for Error {
234    fn from(value: bitcoin::consensus::encode::Error) -> Self {
235        Self::BitcoinEncode(value)
236    }
237}
238
239impl From<musig::InvalidTweakErr> for Error {
240    fn from(value: musig::InvalidTweakErr) -> Self {
241        Self::Musig2(value.to_string())
242    }
243}
244
245impl From<scalar::OutOfRangeError> for Error {
246    fn from(value: scalar::OutOfRangeError) -> Self {
247        Self::Musig2(value.to_string())
248    }
249}
250
251impl From<musig::ParseError> for Error {
252    fn from(value: musig::ParseError) -> Self {
253        Self::Musig2(value.to_string())
254    }
255}
256
257impl Error {
258    // Returns the name of the enum variant as a string
259    pub fn name(&self) -> String {
260        match self {
261            #[cfg(feature = "electrum")]
262            #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
263            Error::Electrum(_) => "Electrum",
264            #[cfg(feature = "esplora")]
265            Error::Esplora(_) => "Esplora",
266            Error::Hex(_) => "Hex",
267            Error::Protocol(_) => "Protocol",
268            Error::Key(_) => "Key",
269            Error::Address(_) => "Address",
270            Error::Sighash(_) => "Sighash",
271            Error::ElSighash(_) => "Elements-Sighash",
272            Error::Secp(_) => "Secp",
273            Error::HTTP(_) => "HTTP",
274            Error::JSON(_) => "JSON",
275            Error::IO(_) => "IO",
276            Error::Bolt11(_) => "Bolt11",
277            Error::LiquidEncode(_) => "LiquidEncode",
278            Error::BitcoinEncode(_) => "BitcoinEncode",
279            Error::Blind(_) => "Blind",
280            Error::ConfidentialTx(_) => "ConfidentialTx",
281            Error::BIP32(_) => "BIP32",
282            Error::BIP39(_) => "BIP39",
283            Error::BIP85(_) => "BIP85",
284            Error::Hash(_) => "Hash",
285            Error::Locktime(_) => "Locktime",
286            Error::Url(_) => "Url",
287            #[cfg(feature = "ws")]
288            Error::WebSocket(_) => "WebSocket",
289            Error::Taproot(_) => "Taproot",
290            Error::Musig2(_) => "Musig2",
291            Error::Generic(_) => "Generic",
292            Error::HTTPStatusNotSuccess(_, _) => "HTTPStatusNotSuccess",
293        }
294        .to_string()
295    }
296
297    // Returns the error message as a string
298    pub fn message(&self) -> String {
299        match self {
300            #[cfg(feature = "electrum")]
301            #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
302            Error::Electrum(e) => e.to_string(),
303            #[cfg(feature = "esplora")]
304            Error::Esplora(e) => e.clone(),
305            Error::Hex(e) => e.clone(),
306            Error::Protocol(e) => e.clone(),
307            Error::Key(e) => e.to_string(),
308            Error::Address(e) => e.clone(),
309            Error::Sighash(e) => e.to_string(),
310            Error::ElSighash(e) => e.to_string(),
311            Error::Secp(e) => e.to_string(),
312            Error::HTTP(e) => e.to_string(),
313            Error::JSON(e) => e.to_string(),
314            Error::IO(e) => e.to_string(),
315            Error::Bolt11(e) => e.to_string(),
316            Error::LiquidEncode(e) => e.to_string(),
317            Error::BitcoinEncode(e) => e.to_string(),
318            Error::Blind(e) => e.clone(),
319            Error::ConfidentialTx(e) => e.to_string(),
320            Error::BIP32(e) => e.to_string(),
321            Error::BIP39(e) => e.to_string(),
322            Error::BIP85(e) => e.to_string(),
323            Error::Hash(e) => e.to_string(),
324            Error::Locktime(e) => e.clone(),
325            Error::Url(e) => e.to_string(),
326            #[cfg(feature = "ws")]
327            Error::WebSocket(e) => e.to_string(),
328            Error::Taproot(e) => e.clone(),
329            Error::Musig2(e) => e.clone(),
330            Error::Generic(e) => e.clone(),
331            Error::HTTPStatusNotSuccess(status, body) => {
332                format!("HTTP Status Not Success: {status}, {body}")
333            }
334        }
335    }
336}
337
338impl Display for Error {
339    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
340        f.write_str(&self.message())?;
341        Ok(())
342    }
343}