1use std::fmt::{Display, Formatter};
2
3use secp256k1_musig::musig;
4use secp256k1_musig::scalar;
5use serde_json::Value;
6
7#[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 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 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}