bdkffi/
error.rs

1use crate::OutPoint;
2
3use bdk_electrum::electrum_client::Error as BdkElectrumError;
4use bdk_esplora::esplora_client::Error as BdkEsploraError;
5use bdk_wallet::bitcoin::address::ParseError as BdkParseError;
6use bdk_wallet::bitcoin::address::{FromScriptError as BdkFromScriptError, ParseError};
7use bdk_wallet::bitcoin::amount::ParseAmountError as BdkParseAmountError;
8use bdk_wallet::bitcoin::bip32::Error as BdkBip32Error;
9use bdk_wallet::bitcoin::consensus::encode::Error as BdkEncodeError;
10use bdk_wallet::bitcoin::hashes::hex::HexToArrayError as BdkHexToArrayError;
11use bdk_wallet::bitcoin::hex::DisplayHex;
12use bdk_wallet::bitcoin::psbt::Error as BdkPsbtError;
13use bdk_wallet::bitcoin::psbt::ExtractTxError as BdkExtractTxError;
14use bdk_wallet::bitcoin::psbt::PsbtParseError as BdkPsbtParseError;
15use bdk_wallet::bitcoin::script::PushBytesError;
16use bdk_wallet::chain::local_chain::CannotConnectError as BdkCannotConnectError;
17use bdk_wallet::chain::rusqlite::Error as BdkSqliteError;
18use bdk_wallet::chain::tx_graph::CalculateFeeError as BdkCalculateFeeError;
19use bdk_wallet::descriptor::DescriptorError as BdkDescriptorError;
20use bdk_wallet::error::BuildFeeBumpError;
21use bdk_wallet::error::CreateTxError as BdkCreateTxError;
22use bdk_wallet::keys::bip39::Error as BdkBip39Error;
23use bdk_wallet::migration::PreV1MigrationError as BdkPreV1MigrationError;
24use bdk_wallet::miniscript::descriptor::DescriptorKeyParseError as BdkDescriptorKeyParseError;
25use bdk_wallet::miniscript::psbt::Error as BdkPsbtFinalizeError;
26use bdk_wallet::signer::SignerError as BdkSignerError;
27use bdk_wallet::tx_builder::AddForeignUtxoError as BdkAddForeignUtxoError;
28use bdk_wallet::tx_builder::AddUtxoError;
29use bdk_wallet::LoadWithPersistError as BdkLoadWithPersistError;
30use bdk_wallet::{chain, CreateWithPersistError as BdkCreateWithPersistError};
31
32use std::convert::TryInto;
33
34// ------------------------------------------------------------------------
35// error definitions
36// ------------------------------------------------------------------------
37
38#[derive(Debug, thiserror::Error, uniffi::Error)]
39#[uniffi::export(Debug, Display)]
40pub enum AddForeignUtxoError {
41    #[error("foreign utxo outpoint txid does not match PSBT input txid")]
42    InvalidTxid,
43
44    #[error("requested outpoint doesn't exist in the tx: {outpoint}")]
45    InvalidOutpoint { outpoint: String },
46
47    #[error("foreign utxo missing witness_utxo or non_witness_utxo")]
48    MissingUtxo,
49
50    #[error("failed to convert Input to BdkInput: {error_message}")]
51    InputConversionError { error_message: String },
52}
53
54#[derive(Debug, thiserror::Error, uniffi::Error)]
55#[uniffi::export(Debug, Display)]
56pub enum AddressParseError {
57    #[error("base58 address encoding error")]
58    Base58,
59
60    #[error("bech32 address encoding error")]
61    Bech32,
62
63    #[error("witness version conversion/parsing error: {error_message}")]
64    WitnessVersion { error_message: String },
65
66    #[error("witness program error: {error_message}")]
67    WitnessProgram { error_message: String },
68
69    #[error("tried to parse an unknown hrp")]
70    UnknownHrp,
71
72    #[error("legacy address base58 string")]
73    LegacyAddressTooLong,
74
75    #[error("legacy address base58 data")]
76    InvalidBase58PayloadLength,
77
78    #[error("segwit address bech32 string")]
79    InvalidLegacyPrefix,
80
81    #[error("validation error")]
82    NetworkValidation,
83
84    // This error is required because the bdk::bitcoin::address::ParseError is non-exhaustive
85    #[error("other address parse error")]
86    OtherAddressParseErr,
87}
88
89#[derive(Debug, thiserror::Error, uniffi::Error)]
90#[uniffi::export(Debug, Display)]
91pub enum Bip32Error {
92    #[error("cannot derive from a hardened key")]
93    CannotDeriveFromHardenedKey,
94
95    #[error("secp256k1 error: {error_message}")]
96    Secp256k1 { error_message: String },
97
98    #[error("invalid child number: {child_number}")]
99    InvalidChildNumber { child_number: u32 },
100
101    #[error("invalid format for child number")]
102    InvalidChildNumberFormat,
103
104    #[error("invalid derivation path format")]
105    InvalidDerivationPathFormat,
106
107    #[error("unknown version: {version}")]
108    UnknownVersion { version: String },
109
110    #[error("wrong extended key length: {length}")]
111    WrongExtendedKeyLength { length: u32 },
112
113    #[error("base58 error: {error_message}")]
114    Base58 { error_message: String },
115
116    #[error("hexadecimal conversion error: {error_message}")]
117    Hex { error_message: String },
118
119    #[error("invalid public key hex length: {length}")]
120    InvalidPublicKeyHexLength { length: u32 },
121
122    #[error("unknown error: {error_message}")]
123    UnknownError { error_message: String },
124}
125
126#[derive(Debug, thiserror::Error, uniffi::Error)]
127#[uniffi::export(Debug, Display)]
128pub enum Bip39Error {
129    #[error("the word count {word_count} is not supported")]
130    BadWordCount { word_count: u64 },
131
132    #[error("unknown word at index {index}")]
133    UnknownWord { index: u64 },
134
135    #[error("entropy bit count {bit_count} is invalid")]
136    BadEntropyBitCount { bit_count: u64 },
137
138    #[error("checksum is invalid")]
139    InvalidChecksum,
140
141    #[error("ambiguous languages detected: {languages}")]
142    AmbiguousLanguages { languages: String },
143}
144
145#[derive(Debug, thiserror::Error, uniffi::Error)]
146#[uniffi::export(Debug, Display)]
147pub enum CalculateFeeError {
148    #[error("missing transaction output: {out_points:?}")]
149    MissingTxOut { out_points: Vec<OutPoint> },
150
151    #[error("negative fee value: {amount}")]
152    NegativeFee { amount: String },
153}
154
155#[derive(Debug, thiserror::Error, uniffi::Error)]
156#[uniffi::export(Debug, Display)]
157pub enum CannotConnectError {
158    #[error("cannot include height: {height}")]
159    Include { height: u32 },
160}
161
162#[derive(Debug, thiserror::Error, uniffi::Error)]
163#[uniffi::export(Debug, Display)]
164pub enum CbfError {
165    #[error("the node is no longer running")]
166    NodeStopped,
167}
168
169#[derive(Debug, thiserror::Error, uniffi::Error)]
170#[uniffi::export(Debug, Display)]
171pub enum CreateTxError {
172    #[error("descriptor error: {error_message}")]
173    Descriptor { error_message: String },
174
175    #[error("policy error: {error_message}")]
176    Policy { error_message: String },
177
178    #[error("spending policy required for {kind}")]
179    SpendingPolicyRequired { kind: String },
180
181    #[error("unsupported version 0")]
182    Version0,
183
184    #[error("unsupported version 1 with csv")]
185    Version1Csv,
186
187    #[error("lock time conflict: requested {requested}, but required {required}")]
188    LockTime { requested: String, required: String },
189
190    #[error("rbf sequence: {sequence}, csv sequence: {csv}")]
191    RbfSequenceCsv { sequence: String, csv: String },
192
193    #[error("fee too low: required {required}")]
194    FeeTooLow { required: String },
195
196    #[error("fee rate too low: {required}")]
197    FeeRateTooLow { required: String },
198
199    #[error("no utxos selected for the transaction")]
200    NoUtxosSelected,
201
202    #[error("output value below dust limit at index {index}")]
203    OutputBelowDustLimit { index: u64 },
204
205    #[error("change policy descriptor error")]
206    ChangePolicyDescriptor,
207
208    #[error("coin selection failed: {error_message}")]
209    CoinSelection { error_message: String },
210
211    #[error("insufficient funds: needed {needed} sat, available {available} sat")]
212    InsufficientFunds { needed: u64, available: u64 },
213
214    #[error("transaction has no recipients")]
215    NoRecipients,
216
217    #[error("psbt creation error: {error_message}")]
218    Psbt { error_message: String },
219
220    #[error("missing key origin for: {key}")]
221    MissingKeyOrigin { key: String },
222
223    #[error("reference to an unknown utxo: {outpoint}")]
224    UnknownUtxo { outpoint: String },
225
226    #[error("missing non-witness utxo for outpoint: {outpoint}")]
227    MissingNonWitnessUtxo { outpoint: String },
228
229    #[error("miniscript psbt error: {error_message}")]
230    MiniscriptPsbt { error_message: String },
231
232    #[error("attempt to prepare too many bytes to be pushed into script")]
233    PushBytesError,
234
235    #[error("invalid lock time value")]
236    LockTimeConversionError,
237}
238
239#[derive(Debug, thiserror::Error, uniffi::Error)]
240#[uniffi::export(Debug, Display)]
241pub enum CreateWithPersistError {
242    #[error("sqlite persistence error: {error_message}")]
243    Persist { error_message: String },
244
245    #[error("the wallet has already been created")]
246    DataAlreadyExists,
247
248    #[error("the loaded changeset cannot construct wallet: {error_message}")]
249    Descriptor { error_message: String },
250}
251
252#[derive(Debug, thiserror::Error, uniffi::Error)]
253#[uniffi::export(Debug, Display)]
254pub enum DescriptorError {
255    #[error("invalid hd key path")]
256    InvalidHdKeyPath,
257
258    #[error("the provided descriptor doesn't match its checksum")]
259    InvalidDescriptorChecksum,
260
261    #[error("the descriptor contains hardened derivation steps on public extended keys")]
262    HardenedDerivationXpub,
263
264    #[error("the descriptor contains multipath keys, which are not supported yet")]
265    MultiPath,
266
267    #[error("key error: {error_message}")]
268    Key { error_message: String },
269
270    #[error("policy error: {error_message}")]
271    Policy { error_message: String },
272
273    #[error("invalid descriptor character: {char}")]
274    InvalidDescriptorCharacter { char: String },
275
276    #[error("bip32 error: {error_message}")]
277    Bip32 { error_message: String },
278
279    #[error("base58 error: {error_message}")]
280    Base58 { error_message: String },
281
282    #[error("key-related error: {error_message}")]
283    Pk { error_message: String },
284
285    #[error("miniscript error: {error_message}")]
286    Miniscript { error_message: String },
287
288    #[error("hex decoding error: {error_message}")]
289    Hex { error_message: String },
290
291    #[error("external and internal descriptors are the same")]
292    ExternalAndInternalAreTheSame,
293}
294
295#[derive(Debug, thiserror::Error, uniffi::Error)]
296#[uniffi::export(Debug, Display)]
297pub enum DescriptorKeyError {
298    #[error("error parsing descriptor key: {error_message}")]
299    Parse { error_message: String },
300
301    #[error("error invalid key type")]
302    InvalidKeyType,
303
304    #[error("error bip 32 related: {error_message}")]
305    Bip32 { error_message: String },
306
307    #[error("you cannot change a wildcard from hardened to unhardened or the opposite")]
308    CannotChangeWildcardType,
309}
310
311#[derive(Debug, thiserror::Error, uniffi::Error)]
312#[uniffi::export(Debug, Display)]
313pub enum ElectrumError {
314    #[error("{error_message}")]
315    IOError { error_message: String },
316
317    #[error("{error_message}")]
318    Json { error_message: String },
319
320    #[error("{error_message}")]
321    Hex { error_message: String },
322
323    #[error("electrum server error: {error_message}")]
324    Protocol { error_message: String },
325
326    #[error("{error_message}")]
327    Bitcoin { error_message: String },
328
329    #[error("already subscribed to the notifications of an address")]
330    AlreadySubscribed,
331
332    #[error("not subscribed to the notifications of an address")]
333    NotSubscribed,
334
335    #[error("error during the deserialization of a response from the server: {error_message}")]
336    InvalidResponse { error_message: String },
337
338    #[error("{error_message}")]
339    Message { error_message: String },
340
341    #[error("invalid domain name {domain} not matching SSL certificate")]
342    InvalidDNSNameError { domain: String },
343
344    #[error("missing domain while it was explicitly asked to validate it")]
345    MissingDomain,
346
347    #[error("made one or multiple attempts, all errored")]
348    AllAttemptsErrored,
349
350    #[error("{error_message}")]
351    SharedIOError { error_message: String },
352
353    #[error("couldn't take a lock on the reader mutex. This means that there's already another reader thread is running")]
354    CouldntLockReader,
355
356    #[error("broken IPC communication channel: the other thread probably has exited")]
357    Mpsc,
358
359    #[error("{error_message}")]
360    CouldNotCreateConnection { error_message: String },
361
362    #[error("the request has already been consumed")]
363    RequestAlreadyConsumed,
364}
365
366#[derive(Debug, thiserror::Error, uniffi::Error)]
367#[uniffi::export(Debug, Display)]
368pub enum EsploraError {
369    #[error("minreq error: {error_message}")]
370    Minreq { error_message: String },
371
372    #[error("http error with status code {status} and message {error_message}")]
373    HttpResponse { status: u16, error_message: String },
374
375    #[error("parsing error: {error_message}")]
376    Parsing { error_message: String },
377
378    #[error("invalid status code, unable to convert to u16: {error_message}")]
379    StatusCode { error_message: String },
380
381    #[error("bitcoin encoding error: {error_message}")]
382    BitcoinEncoding { error_message: String },
383
384    #[error("invalid hex data returned: {error_message}")]
385    HexToArray { error_message: String },
386
387    #[error("invalid hex data returned: {error_message}")]
388    HexToBytes { error_message: String },
389
390    #[error("transaction not found")]
391    TransactionNotFound,
392
393    #[error("header height {height} not found")]
394    HeaderHeightNotFound { height: u32 },
395
396    #[error("header hash not found")]
397    HeaderHashNotFound,
398
399    #[error("invalid http header name: {name}")]
400    InvalidHttpHeaderName { name: String },
401
402    #[error("invalid http header value: {value}")]
403    InvalidHttpHeaderValue { value: String },
404
405    #[error("the request has already been consumed")]
406    RequestAlreadyConsumed,
407
408    #[error("the server sent an invalid response")]
409    InvalidResponse,
410}
411
412#[derive(Debug, thiserror::Error, uniffi::Error)]
413#[uniffi::export(Debug, Display)]
414pub enum ExtractTxError {
415    #[error("an absurdly high fee rate of {fee_rate} sat/vbyte")]
416    AbsurdFeeRate { fee_rate: u64 },
417
418    #[error("one of the inputs lacked value information (witness_utxo or non_witness_utxo)")]
419    MissingInputValue,
420
421    #[error("transaction would be invalid due to output value being greater than input value")]
422    SendingTooMuch,
423
424    #[error(
425        "this error is required because the bdk::bitcoin::psbt::ExtractTxError is non-exhaustive"
426    )]
427    OtherExtractTxErr,
428}
429
430#[derive(Debug, thiserror::Error, uniffi::Error)]
431#[uniffi::export(Debug, Display)]
432pub enum FeeRateError {
433    #[error("arithmetic overflow")]
434    ArithmeticOverflow,
435}
436
437#[derive(Debug, thiserror::Error, uniffi::Error)]
438#[uniffi::export(Debug, Display)]
439pub enum FromScriptError {
440    #[error("script is not a p2pkh, p2sh or witness program")]
441    UnrecognizedScript,
442
443    #[error("witness program error: {error_message}")]
444    WitnessProgram { error_message: String },
445
446    #[error("witness version construction error: {error_message}")]
447    WitnessVersion { error_message: String },
448
449    // This error is required because the bdk::bitcoin::address::FromScriptError is non-exhaustive
450    #[error("other from script error")]
451    OtherFromScriptErr,
452}
453
454#[derive(Debug, thiserror::Error, uniffi::Error)]
455#[uniffi::export(Debug, Display)]
456pub enum HashParseError {
457    #[error("invalid hash: expected length 32 bytes, got {len} bytes")]
458    InvalidHash { len: u32 },
459
460    #[error("invalid hex string: {hex}")]
461    InvalidHexString { hex: String },
462}
463
464#[derive(Debug, thiserror::Error, uniffi::Error)]
465#[uniffi::export(Debug, Display)]
466pub enum LoadWithPersistError {
467    #[error("sqlite persistence error: {error_message}")]
468    Persist { error_message: String },
469
470    #[error("the loaded changeset cannot construct wallet: {error_message}")]
471    InvalidChangeSet { error_message: String },
472
473    #[error("could not load")]
474    CouldNotLoad,
475}
476
477#[derive(Debug, thiserror::Error, uniffi::Error)]
478#[uniffi::export(Debug, Display)]
479pub enum MiniscriptError {
480    #[error("absolute locktime error")]
481    AbsoluteLockTime,
482
483    #[error("address error: {error_message}")]
484    AddrError { error_message: String },
485
486    #[error("p2sh address error: {error_message}")]
487    AddrP2shError { error_message: String },
488
489    #[error("analysis error: {error_message}")]
490    AnalysisError { error_message: String },
491
492    #[error("@ found outside of OR")]
493    AtOutsideOr,
494
495    #[error("bad descriptor: {error_message}")]
496    BadDescriptor { error_message: String },
497
498    #[error("bare descriptor address")]
499    BareDescriptorAddr,
500
501    #[error("too many keys in checkmultisig: {keys}")]
502    CmsTooManyKeys { keys: u32 },
503
504    #[error("context error: {error_message}")]
505    ContextError { error_message: String },
506
507    #[error("could not satisfy")]
508    CouldNotSatisfy,
509
510    #[error("expected character: {char}")]
511    ExpectedChar { char: String },
512
513    #[error("impossible satisfaction")]
514    ImpossibleSatisfaction,
515
516    #[error("invalid opcode")]
517    InvalidOpcode,
518
519    #[error("invalid push")]
520    InvalidPush,
521
522    #[error("lift error: {error_message}")]
523    LiftError { error_message: String },
524
525    #[error("maximum recursive depth exceeded")]
526    MaxRecursiveDepthExceeded,
527
528    #[error("missing signature")]
529    MissingSig,
530
531    #[error("too many keys in multi-a: {keys}")]
532    MultiATooManyKeys { keys: u64 },
533
534    #[error("multiple colons in fragment name")]
535    MultiColon,
536
537    #[error("multipath descriptor length mismatch")]
538    MultipathDescLenMismatch,
539
540    #[error("non-minimal verify: {error_message}")]
541    NonMinimalVerify { error_message: String },
542
543    #[error("non-standard bare script")]
544    NonStandardBareScript,
545
546    #[error("non top-level: {error_message}")]
547    NonTopLevel { error_message: String },
548
549    #[error("parse threshold error")]
550    ParseThreshold,
551
552    #[error("policy error: {error_message}")]
553    PolicyError { error_message: String },
554
555    #[error("pubkey context error")]
556    PubKeyCtxError,
557
558    #[error("relative locktime error")]
559    RelativeLockTime,
560
561    #[error("script error: {error_message}")]
562    Script { error_message: String },
563
564    #[error("secp256k1 error: {error_message}")]
565    Secp { error_message: String },
566
567    #[error("threshold error")]
568    Threshold,
569
570    #[error("no script code for taproot")]
571    TrNoScriptCode,
572
573    #[error("trailing data: {error_message}")]
574    Trailing { error_message: String },
575
576    #[error("type check error: {error_message}")]
577    TypeCheck { error_message: String },
578
579    #[error("unexpected: {error_message}")]
580    Unexpected { error_message: String },
581
582    #[error("unexpected start")]
583    UnexpectedStart,
584
585    #[error("unknown wrapper: {char}")]
586    UnknownWrapper { char: String },
587
588    #[error("unprintable character: {byte}")]
589    Unprintable { byte: u8 },
590}
591
592#[derive(Debug, thiserror::Error, uniffi::Error)]
593#[uniffi::export(Debug, Display)]
594pub enum ParseAmountError {
595    #[error("amount out of range")]
596    OutOfRange,
597
598    #[error("amount has a too high precision")]
599    TooPrecise,
600
601    #[error("the input has too few digits")]
602    MissingDigits,
603
604    #[error("the input is too large")]
605    InputTooLarge,
606
607    #[error("invalid character: {error_message}")]
608    InvalidCharacter { error_message: String },
609
610    // Has to handle non-exhaustive
611    #[error("unknown parse amount error")]
612    OtherParseAmountErr,
613}
614
615#[derive(Debug, thiserror::Error, uniffi::Error)]
616#[uniffi::export(Debug, Display)]
617pub enum PersistenceError {
618    #[error("persistence error: {error_message}")]
619    Reason { error_message: String },
620}
621
622#[derive(Debug, thiserror::Error, uniffi::Error)]
623#[uniffi::export(Debug, Display)]
624pub enum PreV1MigrationError {
625    #[error("migration helper is only available for sqlite-backed persisters")]
626    SqliteOnly,
627
628    #[error("sqlite migration error: {error_message}")]
629    Sqlite { error_message: String },
630
631    #[error("invalid keychain: {keychain}")]
632    InvalidKeychain { keychain: String },
633
634    #[error("invalid checksum: {error_message}")]
635    InvalidChecksum { error_message: String },
636}
637
638#[derive(Debug, thiserror::Error, uniffi::Error)]
639#[uniffi::export(Debug, Display)]
640pub enum PsbtError {
641    #[error("invalid magic")]
642    InvalidMagic,
643
644    #[error("UTXO information is not present in PSBT")]
645    MissingUtxo,
646
647    #[error("invalid separator")]
648    InvalidSeparator,
649
650    #[error("output index is out of bounds of non witness script output array")]
651    PsbtUtxoOutOfBounds,
652
653    #[error("invalid key: {key}")]
654    InvalidKey { key: String },
655
656    #[error("non-proprietary key type found when proprietary key was expected")]
657    InvalidProprietaryKey,
658
659    #[error("duplicate key: {key}")]
660    DuplicateKey { key: String },
661
662    #[error("the unsigned transaction has script sigs")]
663    UnsignedTxHasScriptSigs,
664
665    #[error("the unsigned transaction has script witnesses")]
666    UnsignedTxHasScriptWitnesses,
667
668    #[error("partially signed transactions must have an unsigned transaction")]
669    MustHaveUnsignedTx,
670
671    #[error("no more key-value pairs for this psbt map")]
672    NoMorePairs,
673
674    // Note: this error would be nice to unpack and provide the two transactions
675    #[error("different unsigned transaction")]
676    UnexpectedUnsignedTx,
677
678    #[error("non-standard sighash type: {sighash}")]
679    NonStandardSighashType { sighash: u32 },
680
681    #[error("invalid hash when parsing slice: {hash}")]
682    InvalidHash { hash: String },
683
684    // Note: to provide the data returned in Rust, we need to dereference the fields
685    #[error("preimage does not match")]
686    InvalidPreimageHashPair,
687
688    #[error("combine conflict: {xpub}")]
689    CombineInconsistentKeySources { xpub: String },
690
691    #[error("bitcoin consensus encoding error: {encoding_error}")]
692    ConsensusEncoding { encoding_error: String },
693
694    #[error("PSBT has a negative fee which is not allowed")]
695    NegativeFee,
696
697    #[error("integer overflow in fee calculation")]
698    FeeOverflow,
699
700    #[error("invalid public key {error_message}")]
701    InvalidPublicKey { error_message: String },
702
703    #[error("invalid secp256k1 public key: {secp256k1_error}")]
704    InvalidSecp256k1PublicKey { secp256k1_error: String },
705
706    #[error("invalid xonly public key")]
707    InvalidXOnlyPublicKey,
708
709    #[error("invalid ECDSA signature: {error_message}")]
710    InvalidEcdsaSignature { error_message: String },
711
712    #[error("invalid taproot signature: {error_message}")]
713    InvalidTaprootSignature { error_message: String },
714
715    #[error("invalid control block")]
716    InvalidControlBlock,
717
718    #[error("invalid leaf version")]
719    InvalidLeafVersion,
720
721    #[error("taproot error")]
722    Taproot,
723
724    #[error("taproot tree error: {error_message}")]
725    TapTree { error_message: String },
726
727    #[error("xpub key error")]
728    XPubKey,
729
730    #[error("version error: {error_message}")]
731    Version { error_message: String },
732
733    #[error("data not consumed entirely when explicitly deserializing")]
734    PartialDataConsumption,
735
736    #[error("I/O error: {error_message}")]
737    Io { error_message: String },
738
739    #[error("other PSBT error")]
740    OtherPsbtErr,
741}
742
743#[derive(Debug, thiserror::Error, uniffi::Error)]
744#[uniffi::export(Debug, Display)]
745pub enum PsbtFinalizeError {
746    #[error("an input at index {index} is invalid: {reason}")]
747    InputError { reason: String, index: u32 },
748    #[error("wrong input count; expected: {in_tx}, got: {in_map}")]
749    WrongInputCount { in_tx: u32, in_map: u32 },
750    #[error("input index out of bounds; inputs: {psbt_inp}, requested: {requested}")]
751    InputIdxOutofBounds { psbt_inp: u32, requested: u32 },
752}
753
754#[derive(Debug, thiserror::Error, uniffi::Error)]
755#[uniffi::export(Debug, Display)]
756pub enum PsbtParseError {
757    #[error("error in internal psbt data structure: {error_message}")]
758    PsbtEncoding { error_message: String },
759
760    #[error("error in psbt base64 encoding: {error_message}")]
761    Base64Encoding { error_message: String },
762}
763
764#[derive(Debug, thiserror::Error, uniffi::Error)]
765#[uniffi::export(Debug, Display)]
766pub enum RequestBuilderError {
767    #[error("the request has already been consumed")]
768    RequestAlreadyConsumed,
769}
770
771#[derive(Debug, thiserror::Error, uniffi::Error)]
772#[uniffi::export(Debug, Display)]
773pub enum SighashParseError {
774    #[error("invalid sighash type: {error_message}")]
775    Invalid { error_message: String },
776}
777
778#[derive(Debug, thiserror::Error, uniffi::Error)]
779#[uniffi::export(Debug, Display)]
780pub enum SignerError {
781    #[error("missing key for signing")]
782    MissingKey,
783
784    #[error("invalid key provided")]
785    InvalidKey,
786
787    #[error("user canceled operation")]
788    UserCanceled,
789
790    #[error("input index out of range")]
791    InputIndexOutOfRange,
792
793    #[error("missing non-witness utxo information")]
794    MissingNonWitnessUtxo,
795
796    #[error("invalid non-witness utxo information provided")]
797    InvalidNonWitnessUtxo,
798
799    #[error("missing witness utxo")]
800    MissingWitnessUtxo,
801
802    #[error("missing witness script")]
803    MissingWitnessScript,
804
805    #[error("missing hd keypath")]
806    MissingHdKeypath,
807
808    #[error("non-standard sighash type used")]
809    NonStandardSighash,
810
811    #[error("invalid sighash type provided")]
812    InvalidSighash,
813
814    #[error("error while computing the hash to sign a P2WPKH input: {error_message}")]
815    SighashP2wpkh { error_message: String },
816
817    #[error("error while computing the hash to sign a taproot input: {error_message}")]
818    SighashTaproot { error_message: String },
819
820    #[error("Error while computing the hash, out of bounds access on the transaction inputs: {error_message}")]
821    TxInputsIndexError { error_message: String },
822
823    #[error("miniscript psbt error: {error_message}")]
824    MiniscriptPsbt { error_message: String },
825
826    #[error("external error: {error_message}")]
827    External { error_message: String },
828
829    #[error("Psbt error: {error_message}")]
830    Psbt { error_message: String },
831}
832
833#[derive(Debug, thiserror::Error, uniffi::Error)]
834#[uniffi::export(Debug, Display)]
835pub enum TransactionError {
836    #[error("io error")]
837    Io,
838
839    #[error("allocation of oversized vector")]
840    OversizedVectorAllocation,
841
842    #[error("invalid checksum: expected={expected} actual={actual}")]
843    InvalidChecksum { expected: String, actual: String },
844
845    #[error("non-minimal var int")]
846    NonMinimalVarInt,
847
848    #[error("parse failed")]
849    ParseFailed,
850
851    #[error("unsupported segwit version: {flag}")]
852    UnsupportedSegwitFlag { flag: u8 },
853
854    // This is required because the bdk::bitcoin::consensus::encode::Error is non-exhaustive
855    #[error("other transaction error")]
856    OtherTransactionErr,
857}
858
859#[derive(Debug, thiserror::Error, uniffi::Error)]
860#[uniffi::export(Debug, Display)]
861pub enum TxidParseError {
862    #[error("invalid txid: {txid}")]
863    InvalidTxid { txid: String },
864}
865
866// ------------------------------------------------------------------------
867// error conversions
868// ------------------------------------------------------------------------
869
870impl From<AddForeignUtxoError> for CreateTxError {
871    fn from(error: AddForeignUtxoError) -> Self {
872        match error {
873            AddForeignUtxoError::InvalidTxid => CreateTxError::Descriptor {
874                error_message: "foreign utxo outpoint txid does not match PSBT input txid"
875                    .to_string(),
876            },
877            AddForeignUtxoError::InvalidOutpoint { outpoint } => {
878                CreateTxError::UnknownUtxo { outpoint }
879            }
880            AddForeignUtxoError::MissingUtxo => CreateTxError::Descriptor {
881                error_message: "foreign utxo missing witness_utxo or non_witness_utxo".to_string(),
882            },
883            AddForeignUtxoError::InputConversionError { error_message } => {
884                CreateTxError::Descriptor { error_message }
885            }
886        }
887    }
888}
889
890impl From<BdkAddForeignUtxoError> for AddForeignUtxoError {
891    fn from(error: BdkAddForeignUtxoError) -> Self {
892        match error {
893            BdkAddForeignUtxoError::InvalidTxid { .. } => AddForeignUtxoError::InvalidTxid,
894            BdkAddForeignUtxoError::InvalidOutpoint(outpoint) => {
895                AddForeignUtxoError::InvalidOutpoint {
896                    outpoint: outpoint.to_string(),
897                }
898            }
899            BdkAddForeignUtxoError::MissingUtxo => AddForeignUtxoError::MissingUtxo,
900        }
901    }
902}
903
904impl From<BdkElectrumError> for ElectrumError {
905    fn from(error: BdkElectrumError) -> Self {
906        match error {
907            BdkElectrumError::IOError(e) => ElectrumError::IOError {
908                error_message: e.to_string(),
909            },
910            BdkElectrumError::JSON(e) => ElectrumError::Json {
911                error_message: e.to_string(),
912            },
913            BdkElectrumError::Hex(e) => ElectrumError::Hex {
914                error_message: e.to_string(),
915            },
916            BdkElectrumError::Protocol(e) => ElectrumError::Protocol {
917                error_message: e.to_string(),
918            },
919            BdkElectrumError::Bitcoin(e) => ElectrumError::Bitcoin {
920                error_message: e.to_string(),
921            },
922            BdkElectrumError::AlreadySubscribed(_) => ElectrumError::AlreadySubscribed,
923            BdkElectrumError::NotSubscribed(_) => ElectrumError::NotSubscribed,
924            BdkElectrumError::InvalidResponse(e) => ElectrumError::InvalidResponse {
925                error_message: e.to_string(),
926            },
927            BdkElectrumError::Message(e) => ElectrumError::Message {
928                error_message: e.to_string(),
929            },
930            BdkElectrumError::InvalidDNSNameError(domain) => {
931                ElectrumError::InvalidDNSNameError { domain }
932            }
933            BdkElectrumError::MissingDomain => ElectrumError::MissingDomain,
934            BdkElectrumError::AllAttemptsErrored(_) => ElectrumError::AllAttemptsErrored,
935            BdkElectrumError::SharedIOError(e) => ElectrumError::SharedIOError {
936                error_message: e.to_string(),
937            },
938            BdkElectrumError::CouldntLockReader => ElectrumError::CouldntLockReader,
939            BdkElectrumError::Mpsc => ElectrumError::Mpsc,
940            BdkElectrumError::CouldNotCreateConnection(error_message) => {
941                ElectrumError::CouldNotCreateConnection {
942                    error_message: error_message.to_string(),
943                }
944            }
945        }
946    }
947}
948
949impl From<BdkParseError> for AddressParseError {
950    fn from(error: BdkParseError) -> Self {
951        match error {
952            BdkParseError::Base58(_) => AddressParseError::Base58,
953            BdkParseError::Bech32(_) => AddressParseError::Bech32,
954            BdkParseError::WitnessVersion(e) => AddressParseError::WitnessVersion {
955                error_message: e.to_string(),
956            },
957            BdkParseError::WitnessProgram(e) => AddressParseError::WitnessProgram {
958                error_message: e.to_string(),
959            },
960            ParseError::UnknownHrp(_) => AddressParseError::UnknownHrp,
961            ParseError::LegacyAddressTooLong(_) => AddressParseError::LegacyAddressTooLong,
962            ParseError::InvalidBase58PayloadLength(_) => {
963                AddressParseError::InvalidBase58PayloadLength
964            }
965            ParseError::InvalidLegacyPrefix(_) => AddressParseError::InvalidLegacyPrefix,
966            ParseError::NetworkValidation(_) => AddressParseError::NetworkValidation,
967            _ => AddressParseError::OtherAddressParseErr,
968        }
969    }
970}
971
972impl From<BdkBip32Error> for Bip32Error {
973    fn from(error: BdkBip32Error) -> Self {
974        match error {
975            BdkBip32Error::CannotDeriveFromHardenedKey => Bip32Error::CannotDeriveFromHardenedKey,
976            BdkBip32Error::Secp256k1(e) => Bip32Error::Secp256k1 {
977                error_message: e.to_string(),
978            },
979            BdkBip32Error::InvalidChildNumber(num) => {
980                Bip32Error::InvalidChildNumber { child_number: num }
981            }
982            BdkBip32Error::InvalidChildNumberFormat => Bip32Error::InvalidChildNumberFormat,
983            BdkBip32Error::InvalidDerivationPathFormat => Bip32Error::InvalidDerivationPathFormat,
984            BdkBip32Error::UnknownVersion(bytes) => Bip32Error::UnknownVersion {
985                version: bytes.to_lower_hex_string(),
986            },
987            BdkBip32Error::WrongExtendedKeyLength(len) => {
988                Bip32Error::WrongExtendedKeyLength { length: len as u32 }
989            }
990            BdkBip32Error::Base58(e) => Bip32Error::Base58 {
991                error_message: e.to_string(),
992            },
993            BdkBip32Error::Hex(e) => Bip32Error::Hex {
994                error_message: e.to_string(),
995            },
996            BdkBip32Error::InvalidPublicKeyHexLength(len) => {
997                Bip32Error::InvalidPublicKeyHexLength { length: len as u32 }
998            }
999            _ => Bip32Error::UnknownError {
1000                error_message: format!("Unhandled error: {error:?}"),
1001            },
1002        }
1003    }
1004}
1005
1006impl From<BdkBip39Error> for Bip39Error {
1007    fn from(error: BdkBip39Error) -> Self {
1008        match error {
1009            BdkBip39Error::BadWordCount(word_count) => Bip39Error::BadWordCount {
1010                word_count: word_count.try_into().expect("word count exceeds u64"),
1011            },
1012            BdkBip39Error::UnknownWord(index) => Bip39Error::UnknownWord {
1013                index: index.try_into().expect("index exceeds u64"),
1014            },
1015            BdkBip39Error::BadEntropyBitCount(bit_count) => Bip39Error::BadEntropyBitCount {
1016                bit_count: bit_count.try_into().expect("bit count exceeds u64"),
1017            },
1018            BdkBip39Error::InvalidChecksum => Bip39Error::InvalidChecksum,
1019            BdkBip39Error::AmbiguousLanguages(info) => Bip39Error::AmbiguousLanguages {
1020                languages: format!("{info:?}"),
1021            },
1022        }
1023    }
1024}
1025
1026impl From<BdkCalculateFeeError> for CalculateFeeError {
1027    fn from(error: BdkCalculateFeeError) -> Self {
1028        match error {
1029            BdkCalculateFeeError::MissingTxOut(out_points) => {
1030                let out_points = out_points.iter().map(OutPoint::from).collect();
1031                CalculateFeeError::MissingTxOut { out_points }
1032            }
1033            BdkCalculateFeeError::NegativeFee(signed_amount) => CalculateFeeError::NegativeFee {
1034                amount: signed_amount.to_string(),
1035            },
1036        }
1037    }
1038}
1039
1040impl From<BdkCannotConnectError> for CannotConnectError {
1041    fn from(error: BdkCannotConnectError) -> Self {
1042        CannotConnectError::Include {
1043            height: error.try_include_height,
1044        }
1045    }
1046}
1047
1048impl From<BdkCreateTxError> for CreateTxError {
1049    fn from(error: BdkCreateTxError) -> Self {
1050        match error {
1051            BdkCreateTxError::Descriptor(e) => CreateTxError::Descriptor {
1052                error_message: e.to_string(),
1053            },
1054            BdkCreateTxError::Policy(e) => CreateTxError::Policy {
1055                error_message: e.to_string(),
1056            },
1057            BdkCreateTxError::SpendingPolicyRequired(kind) => {
1058                CreateTxError::SpendingPolicyRequired {
1059                    kind: format!("{kind:?}"),
1060                }
1061            }
1062            BdkCreateTxError::Version0 => CreateTxError::Version0,
1063            BdkCreateTxError::Version1Csv => CreateTxError::Version1Csv,
1064            BdkCreateTxError::LockTime {
1065                requested,
1066                required,
1067            } => CreateTxError::LockTime {
1068                requested: requested.to_string(),
1069                required: required.to_string(),
1070            },
1071            BdkCreateTxError::RbfSequenceCsv { sequence, csv } => CreateTxError::RbfSequenceCsv {
1072                sequence: sequence.to_string(),
1073                csv: csv.to_string(),
1074            },
1075            BdkCreateTxError::FeeTooLow { required } => CreateTxError::FeeTooLow {
1076                required: required.to_string(),
1077            },
1078            BdkCreateTxError::FeeRateTooLow { required } => CreateTxError::FeeRateTooLow {
1079                required: required.to_string(),
1080            },
1081            BdkCreateTxError::NoUtxosSelected => CreateTxError::NoUtxosSelected,
1082            BdkCreateTxError::OutputBelowDustLimit(index) => CreateTxError::OutputBelowDustLimit {
1083                index: index as u64,
1084            },
1085            BdkCreateTxError::CoinSelection(e) => CreateTxError::CoinSelection {
1086                error_message: e.to_string(),
1087            },
1088            BdkCreateTxError::NoRecipients => CreateTxError::NoRecipients,
1089            BdkCreateTxError::Psbt(e) => CreateTxError::Psbt {
1090                error_message: e.to_string(),
1091            },
1092            BdkCreateTxError::MissingKeyOrigin(key) => CreateTxError::MissingKeyOrigin { key },
1093            BdkCreateTxError::UnknownUtxo => CreateTxError::UnknownUtxo {
1094                outpoint: "Unknown".to_string(),
1095            },
1096            BdkCreateTxError::MissingNonWitnessUtxo(outpoint) => {
1097                CreateTxError::MissingNonWitnessUtxo {
1098                    outpoint: outpoint.to_string(),
1099                }
1100            }
1101            BdkCreateTxError::MiniscriptPsbt(e) => CreateTxError::MiniscriptPsbt {
1102                error_message: e.to_string(),
1103            },
1104        }
1105    }
1106}
1107
1108impl From<PushBytesError> for CreateTxError {
1109    fn from(_: PushBytesError) -> Self {
1110        CreateTxError::PushBytesError
1111    }
1112}
1113
1114impl From<BdkCreateWithPersistError<chain::rusqlite::Error>> for CreateWithPersistError {
1115    fn from(error: BdkCreateWithPersistError<chain::rusqlite::Error>) -> Self {
1116        match error {
1117            BdkCreateWithPersistError::Persist(e) => CreateWithPersistError::Persist {
1118                error_message: e.to_string(),
1119            },
1120            BdkCreateWithPersistError::Descriptor(e) => CreateWithPersistError::Descriptor {
1121                error_message: e.to_string(),
1122            },
1123            // Objects cannot currently be used in enumerations
1124            BdkCreateWithPersistError::DataAlreadyExists(_e) => {
1125                CreateWithPersistError::DataAlreadyExists
1126            }
1127        }
1128    }
1129}
1130
1131impl From<BdkCreateWithPersistError<PersistenceError>> for CreateWithPersistError {
1132    fn from(error: BdkCreateWithPersistError<PersistenceError>) -> Self {
1133        match error {
1134            BdkCreateWithPersistError::Persist(e) => CreateWithPersistError::Persist {
1135                error_message: e.to_string(),
1136            },
1137            BdkCreateWithPersistError::Descriptor(e) => CreateWithPersistError::Descriptor {
1138                error_message: e.to_string(),
1139            },
1140            // Objects cannot currently be used in enumerations
1141            BdkCreateWithPersistError::DataAlreadyExists(_e) => {
1142                CreateWithPersistError::DataAlreadyExists
1143            }
1144        }
1145    }
1146}
1147
1148impl From<AddUtxoError> for CreateTxError {
1149    fn from(error: AddUtxoError) -> Self {
1150        match error {
1151            AddUtxoError::UnknownUtxo(outpoint) => CreateTxError::UnknownUtxo {
1152                outpoint: outpoint.to_string(),
1153            },
1154        }
1155    }
1156}
1157
1158impl From<BuildFeeBumpError> for CreateTxError {
1159    fn from(error: BuildFeeBumpError) -> Self {
1160        match error {
1161            BuildFeeBumpError::UnknownUtxo(outpoint) => CreateTxError::UnknownUtxo {
1162                outpoint: outpoint.to_string(),
1163            },
1164            BuildFeeBumpError::TransactionNotFound(txid) => CreateTxError::UnknownUtxo {
1165                outpoint: txid.to_string(),
1166            },
1167            BuildFeeBumpError::TransactionConfirmed(txid) => CreateTxError::UnknownUtxo {
1168                outpoint: txid.to_string(),
1169            },
1170            BuildFeeBumpError::IrreplaceableTransaction(txid) => CreateTxError::UnknownUtxo {
1171                outpoint: txid.to_string(),
1172            },
1173            BuildFeeBumpError::FeeRateUnavailable => CreateTxError::FeeRateTooLow {
1174                required: "unavailable".to_string(),
1175            },
1176            BuildFeeBumpError::InvalidOutputIndex(outpoint) => CreateTxError::UnknownUtxo {
1177                outpoint: outpoint.to_string(),
1178            },
1179        }
1180    }
1181}
1182
1183impl From<BdkDescriptorError> for DescriptorError {
1184    fn from(error: BdkDescriptorError) -> Self {
1185        match error {
1186            BdkDescriptorError::InvalidHdKeyPath => DescriptorError::InvalidHdKeyPath,
1187            BdkDescriptorError::InvalidDescriptorChecksum => {
1188                DescriptorError::InvalidDescriptorChecksum
1189            }
1190            BdkDescriptorError::HardenedDerivationXpub => DescriptorError::HardenedDerivationXpub,
1191            BdkDescriptorError::MultiPath => DescriptorError::MultiPath,
1192            BdkDescriptorError::Key(e) => DescriptorError::Key {
1193                error_message: e.to_string(),
1194            },
1195            BdkDescriptorError::Policy(e) => DescriptorError::Policy {
1196                error_message: e.to_string(),
1197            },
1198            BdkDescriptorError::InvalidDescriptorCharacter(char) => {
1199                DescriptorError::InvalidDescriptorCharacter {
1200                    char: char.to_string(),
1201                }
1202            }
1203            BdkDescriptorError::Bip32(e) => DescriptorError::Bip32 {
1204                error_message: e.to_string(),
1205            },
1206            BdkDescriptorError::Base58(e) => DescriptorError::Base58 {
1207                error_message: e.to_string(),
1208            },
1209            BdkDescriptorError::Pk(e) => DescriptorError::Pk {
1210                error_message: e.to_string(),
1211            },
1212            BdkDescriptorError::Miniscript(e) => DescriptorError::Miniscript {
1213                error_message: e.to_string(),
1214            },
1215            BdkDescriptorError::Hex(e) => DescriptorError::Hex {
1216                error_message: e.to_string(),
1217            },
1218            BdkDescriptorError::ExternalAndInternalAreTheSame => {
1219                DescriptorError::ExternalAndInternalAreTheSame
1220            }
1221        }
1222    }
1223}
1224
1225impl From<BdkDescriptorKeyParseError> for DescriptorKeyError {
1226    fn from(err: BdkDescriptorKeyParseError) -> DescriptorKeyError {
1227        DescriptorKeyError::Parse {
1228            error_message: format!("DescriptorKeyError error: {err:?}"),
1229        }
1230    }
1231}
1232
1233impl From<BdkBip32Error> for DescriptorKeyError {
1234    fn from(error: BdkBip32Error) -> DescriptorKeyError {
1235        DescriptorKeyError::Bip32 {
1236            error_message: format!("BIP32 derivation error: {error:?}"),
1237        }
1238    }
1239}
1240
1241impl From<BdkEsploraError> for EsploraError {
1242    fn from(error: BdkEsploraError) -> Self {
1243        match error {
1244            BdkEsploraError::Minreq(e) => EsploraError::Minreq {
1245                error_message: e.to_string(),
1246            },
1247            BdkEsploraError::HttpResponse { status, message } => EsploraError::HttpResponse {
1248                status,
1249                error_message: message,
1250            },
1251            BdkEsploraError::Parsing(e) => EsploraError::Parsing {
1252                error_message: e.to_string(),
1253            },
1254            BdkEsploraError::StatusCode(e) => EsploraError::StatusCode {
1255                error_message: e.to_string(),
1256            },
1257            BdkEsploraError::BitcoinEncoding(e) => EsploraError::BitcoinEncoding {
1258                error_message: e.to_string(),
1259            },
1260            BdkEsploraError::HexToArray(e) => EsploraError::HexToArray {
1261                error_message: e.to_string(),
1262            },
1263            BdkEsploraError::HexToBytes(e) => EsploraError::HexToBytes {
1264                error_message: e.to_string(),
1265            },
1266            BdkEsploraError::TransactionNotFound(_) => EsploraError::TransactionNotFound,
1267            BdkEsploraError::HeaderHeightNotFound(height) => {
1268                EsploraError::HeaderHeightNotFound { height }
1269            }
1270            BdkEsploraError::HeaderHashNotFound(_) => EsploraError::HeaderHashNotFound,
1271            BdkEsploraError::InvalidHttpHeaderName(name) => {
1272                EsploraError::InvalidHttpHeaderName { name }
1273            }
1274            BdkEsploraError::InvalidHttpHeaderValue(value) => {
1275                EsploraError::InvalidHttpHeaderValue { value }
1276            }
1277            BdkEsploraError::InvalidResponse => EsploraError::InvalidResponse,
1278        }
1279    }
1280}
1281
1282impl From<Box<BdkEsploraError>> for EsploraError {
1283    fn from(error: Box<BdkEsploraError>) -> Self {
1284        match *error {
1285            BdkEsploraError::Minreq(e) => EsploraError::Minreq {
1286                error_message: e.to_string(),
1287            },
1288            BdkEsploraError::HttpResponse { status, message } => EsploraError::HttpResponse {
1289                status,
1290                error_message: message,
1291            },
1292            BdkEsploraError::Parsing(e) => EsploraError::Parsing {
1293                error_message: e.to_string(),
1294            },
1295            BdkEsploraError::StatusCode(e) => EsploraError::StatusCode {
1296                error_message: e.to_string(),
1297            },
1298            BdkEsploraError::BitcoinEncoding(e) => EsploraError::BitcoinEncoding {
1299                error_message: e.to_string(),
1300            },
1301            BdkEsploraError::HexToArray(e) => EsploraError::HexToArray {
1302                error_message: e.to_string(),
1303            },
1304            BdkEsploraError::HexToBytes(e) => EsploraError::HexToBytes {
1305                error_message: e.to_string(),
1306            },
1307            BdkEsploraError::TransactionNotFound(_) => EsploraError::TransactionNotFound,
1308            BdkEsploraError::HeaderHeightNotFound(height) => {
1309                EsploraError::HeaderHeightNotFound { height }
1310            }
1311            BdkEsploraError::HeaderHashNotFound(_) => EsploraError::HeaderHashNotFound,
1312            BdkEsploraError::InvalidHttpHeaderName(name) => {
1313                EsploraError::InvalidHttpHeaderName { name }
1314            }
1315            BdkEsploraError::InvalidHttpHeaderValue(value) => {
1316                EsploraError::InvalidHttpHeaderValue { value }
1317            }
1318            BdkEsploraError::InvalidResponse => EsploraError::InvalidResponse,
1319        }
1320    }
1321}
1322
1323impl From<BdkHexToArrayError> for EsploraError {
1324    fn from(error: BdkHexToArrayError) -> Self {
1325        EsploraError::Parsing {
1326            error_message: error.to_string(),
1327        }
1328    }
1329}
1330
1331impl From<BdkExtractTxError> for ExtractTxError {
1332    fn from(error: BdkExtractTxError) -> Self {
1333        match error {
1334            BdkExtractTxError::AbsurdFeeRate { fee_rate, .. } => {
1335                let sat_per_vbyte = fee_rate.to_sat_per_vb_ceil();
1336                ExtractTxError::AbsurdFeeRate {
1337                    fee_rate: sat_per_vbyte,
1338                }
1339            }
1340            BdkExtractTxError::MissingInputValue { .. } => ExtractTxError::MissingInputValue,
1341            BdkExtractTxError::SendingTooMuch { .. } => ExtractTxError::SendingTooMuch,
1342            _ => ExtractTxError::OtherExtractTxErr,
1343        }
1344    }
1345}
1346
1347impl From<BdkFromScriptError> for FromScriptError {
1348    fn from(error: BdkFromScriptError) -> Self {
1349        match error {
1350            BdkFromScriptError::UnrecognizedScript => FromScriptError::UnrecognizedScript,
1351            BdkFromScriptError::WitnessProgram(e) => FromScriptError::WitnessProgram {
1352                error_message: e.to_string(),
1353            },
1354            BdkFromScriptError::WitnessVersion(e) => FromScriptError::WitnessVersion {
1355                error_message: e.to_string(),
1356            },
1357            _ => FromScriptError::OtherFromScriptErr,
1358        }
1359    }
1360}
1361
1362impl From<BdkLoadWithPersistError<chain::rusqlite::Error>> for LoadWithPersistError {
1363    fn from(error: BdkLoadWithPersistError<chain::rusqlite::Error>) -> Self {
1364        match error {
1365            BdkLoadWithPersistError::Persist(e) => LoadWithPersistError::Persist {
1366                error_message: e.to_string(),
1367            },
1368            BdkLoadWithPersistError::InvalidChangeSet(e) => {
1369                LoadWithPersistError::InvalidChangeSet {
1370                    error_message: e.to_string(),
1371                }
1372            }
1373        }
1374    }
1375}
1376
1377impl From<BdkLoadWithPersistError<PersistenceError>> for LoadWithPersistError {
1378    fn from(error: BdkLoadWithPersistError<PersistenceError>) -> Self {
1379        match error {
1380            BdkLoadWithPersistError::Persist(e) => LoadWithPersistError::Persist {
1381                error_message: e.to_string(),
1382            },
1383            BdkLoadWithPersistError::InvalidChangeSet(e) => {
1384                LoadWithPersistError::InvalidChangeSet {
1385                    error_message: e.to_string(),
1386                }
1387            }
1388        }
1389    }
1390}
1391
1392impl From<BdkSqliteError> for PersistenceError {
1393    fn from(error: BdkSqliteError) -> Self {
1394        PersistenceError::Reason {
1395            error_message: error.to_string(),
1396        }
1397    }
1398}
1399
1400impl From<BdkPreV1MigrationError> for PreV1MigrationError {
1401    fn from(error: BdkPreV1MigrationError) -> Self {
1402        match error {
1403            BdkPreV1MigrationError::RusqliteError(error) => PreV1MigrationError::Sqlite {
1404                error_message: error.to_string(),
1405            },
1406            BdkPreV1MigrationError::InvalidKeychain(keychain) => {
1407                PreV1MigrationError::InvalidKeychain { keychain }
1408            }
1409            BdkPreV1MigrationError::InvalidChecksum(error) => {
1410                PreV1MigrationError::InvalidChecksum {
1411                    error_message: error.to_string(),
1412                }
1413            }
1414        }
1415    }
1416}
1417
1418impl From<bdk_wallet::miniscript::Error> for MiniscriptError {
1419    fn from(error: bdk_wallet::miniscript::Error) -> Self {
1420        use bdk_wallet::miniscript::Error as BdkMiniscriptError;
1421        match error {
1422            BdkMiniscriptError::AbsoluteLockTime(_) => MiniscriptError::AbsoluteLockTime,
1423            BdkMiniscriptError::AddrError(e) => MiniscriptError::AddrError {
1424                error_message: e.to_string(),
1425            },
1426            BdkMiniscriptError::AddrP2shError(e) => MiniscriptError::AddrP2shError {
1427                error_message: e.to_string(),
1428            },
1429            BdkMiniscriptError::AnalysisError(e) => MiniscriptError::AnalysisError {
1430                error_message: e.to_string(),
1431            },
1432            BdkMiniscriptError::AtOutsideOr(_) => MiniscriptError::AtOutsideOr,
1433            BdkMiniscriptError::BadDescriptor(s) => {
1434                MiniscriptError::BadDescriptor { error_message: s }
1435            }
1436            BdkMiniscriptError::BareDescriptorAddr => MiniscriptError::BareDescriptorAddr,
1437            BdkMiniscriptError::CmsTooManyKeys(n) => MiniscriptError::CmsTooManyKeys { keys: n },
1438            BdkMiniscriptError::ContextError(e) => MiniscriptError::ContextError {
1439                error_message: e.to_string(),
1440            },
1441            BdkMiniscriptError::CouldNotSatisfy => MiniscriptError::CouldNotSatisfy,
1442            BdkMiniscriptError::ExpectedChar(c) => MiniscriptError::ExpectedChar {
1443                char: c.to_string(),
1444            },
1445            BdkMiniscriptError::ImpossibleSatisfaction => MiniscriptError::ImpossibleSatisfaction,
1446            BdkMiniscriptError::InvalidOpcode(_) => MiniscriptError::InvalidOpcode,
1447            BdkMiniscriptError::InvalidPush(_) => MiniscriptError::InvalidPush,
1448            BdkMiniscriptError::LiftError(e) => MiniscriptError::LiftError {
1449                error_message: e.to_string(),
1450            },
1451            BdkMiniscriptError::MaxRecursiveDepthExceeded => {
1452                MiniscriptError::MaxRecursiveDepthExceeded
1453            }
1454            BdkMiniscriptError::MissingSig(_) => MiniscriptError::MissingSig,
1455            BdkMiniscriptError::MultiATooManyKeys(n) => {
1456                MiniscriptError::MultiATooManyKeys { keys: n }
1457            }
1458            BdkMiniscriptError::MultiColon(_) => MiniscriptError::MultiColon,
1459            BdkMiniscriptError::MultipathDescLenMismatch => {
1460                MiniscriptError::MultipathDescLenMismatch
1461            }
1462            BdkMiniscriptError::NonMinimalVerify(s) => {
1463                MiniscriptError::NonMinimalVerify { error_message: s }
1464            }
1465            BdkMiniscriptError::NonStandardBareScript => MiniscriptError::NonStandardBareScript,
1466            BdkMiniscriptError::NonTopLevel(s) => MiniscriptError::NonTopLevel { error_message: s },
1467            BdkMiniscriptError::ParseThreshold(_) => MiniscriptError::ParseThreshold,
1468            BdkMiniscriptError::PolicyError(e) => MiniscriptError::PolicyError {
1469                error_message: e.to_string(),
1470            },
1471            BdkMiniscriptError::PubKeyCtxError(_, _) => MiniscriptError::PubKeyCtxError,
1472            BdkMiniscriptError::RelativeLockTime(_) => MiniscriptError::RelativeLockTime,
1473            BdkMiniscriptError::Script(e) => MiniscriptError::Script {
1474                error_message: e.to_string(),
1475            },
1476            BdkMiniscriptError::Secp(e) => MiniscriptError::Secp {
1477                error_message: e.to_string(),
1478            },
1479            BdkMiniscriptError::Threshold(_) => MiniscriptError::Threshold,
1480            BdkMiniscriptError::TrNoScriptCode => MiniscriptError::TrNoScriptCode,
1481            BdkMiniscriptError::Trailing(s) => MiniscriptError::Trailing { error_message: s },
1482            BdkMiniscriptError::TypeCheck(s) => MiniscriptError::TypeCheck { error_message: s },
1483            BdkMiniscriptError::Unexpected(s) => MiniscriptError::Unexpected { error_message: s },
1484            BdkMiniscriptError::UnexpectedStart => MiniscriptError::UnexpectedStart,
1485            BdkMiniscriptError::UnknownWrapper(c) => MiniscriptError::UnknownWrapper {
1486                char: c.to_string(),
1487            },
1488            BdkMiniscriptError::Unprintable(b) => MiniscriptError::Unprintable { byte: b },
1489        }
1490    }
1491}
1492
1493impl From<BdkParseAmountError> for ParseAmountError {
1494    fn from(error: BdkParseAmountError) -> Self {
1495        match error {
1496            BdkParseAmountError::OutOfRange(_) => ParseAmountError::OutOfRange,
1497            BdkParseAmountError::TooPrecise(_) => ParseAmountError::TooPrecise,
1498            BdkParseAmountError::MissingDigits(_) => ParseAmountError::MissingDigits,
1499            BdkParseAmountError::InputTooLarge(_) => ParseAmountError::InputTooLarge,
1500            BdkParseAmountError::InvalidCharacter(c) => ParseAmountError::InvalidCharacter {
1501                error_message: c.to_string(),
1502            },
1503            _ => ParseAmountError::OtherParseAmountErr,
1504        }
1505    }
1506}
1507
1508impl From<std::io::Error> for PersistenceError {
1509    fn from(error: std::io::Error) -> Self {
1510        PersistenceError::Reason {
1511            error_message: error.to_string(),
1512        }
1513    }
1514}
1515
1516impl From<BdkPsbtError> for PsbtError {
1517    fn from(error: BdkPsbtError) -> Self {
1518        match error {
1519            BdkPsbtError::InvalidMagic => PsbtError::InvalidMagic,
1520            BdkPsbtError::MissingUtxo => PsbtError::MissingUtxo,
1521            BdkPsbtError::InvalidSeparator => PsbtError::InvalidSeparator,
1522            BdkPsbtError::PsbtUtxoOutOfbounds => PsbtError::PsbtUtxoOutOfBounds,
1523            BdkPsbtError::InvalidKey(key) => PsbtError::InvalidKey {
1524                key: key.to_string(),
1525            },
1526            BdkPsbtError::InvalidProprietaryKey => PsbtError::InvalidProprietaryKey,
1527            BdkPsbtError::DuplicateKey(key) => PsbtError::DuplicateKey {
1528                key: key.to_string(),
1529            },
1530            BdkPsbtError::UnsignedTxHasScriptSigs => PsbtError::UnsignedTxHasScriptSigs,
1531            BdkPsbtError::UnsignedTxHasScriptWitnesses => PsbtError::UnsignedTxHasScriptWitnesses,
1532            BdkPsbtError::MustHaveUnsignedTx => PsbtError::MustHaveUnsignedTx,
1533            BdkPsbtError::NoMorePairs => PsbtError::NoMorePairs,
1534            BdkPsbtError::UnexpectedUnsignedTx { .. } => PsbtError::UnexpectedUnsignedTx,
1535            BdkPsbtError::NonStandardSighashType(sighash) => {
1536                PsbtError::NonStandardSighashType { sighash }
1537            }
1538            BdkPsbtError::InvalidHash(hash) => PsbtError::InvalidHash {
1539                hash: hash.to_string(),
1540            },
1541            BdkPsbtError::InvalidPreimageHashPair { .. } => PsbtError::InvalidPreimageHashPair,
1542            BdkPsbtError::CombineInconsistentKeySources(xpub) => {
1543                PsbtError::CombineInconsistentKeySources {
1544                    xpub: xpub.to_string(),
1545                }
1546            }
1547            BdkPsbtError::ConsensusEncoding(encoding_error) => PsbtError::ConsensusEncoding {
1548                encoding_error: encoding_error.to_string(),
1549            },
1550            BdkPsbtError::NegativeFee => PsbtError::NegativeFee,
1551            BdkPsbtError::FeeOverflow => PsbtError::FeeOverflow,
1552            BdkPsbtError::InvalidPublicKey(e) => PsbtError::InvalidPublicKey {
1553                error_message: e.to_string(),
1554            },
1555            BdkPsbtError::InvalidSecp256k1PublicKey(e) => PsbtError::InvalidSecp256k1PublicKey {
1556                secp256k1_error: e.to_string(),
1557            },
1558            BdkPsbtError::InvalidXOnlyPublicKey => PsbtError::InvalidXOnlyPublicKey,
1559            BdkPsbtError::InvalidEcdsaSignature(e) => PsbtError::InvalidEcdsaSignature {
1560                error_message: e.to_string(),
1561            },
1562            BdkPsbtError::InvalidTaprootSignature(e) => PsbtError::InvalidTaprootSignature {
1563                error_message: e.to_string(),
1564            },
1565            BdkPsbtError::InvalidControlBlock => PsbtError::InvalidControlBlock,
1566            BdkPsbtError::InvalidLeafVersion => PsbtError::InvalidLeafVersion,
1567            BdkPsbtError::Taproot(_) => PsbtError::Taproot,
1568            BdkPsbtError::TapTree(e) => PsbtError::TapTree {
1569                error_message: e.to_string(),
1570            },
1571            BdkPsbtError::XPubKey(_) => PsbtError::XPubKey,
1572            BdkPsbtError::Version(e) => PsbtError::Version {
1573                error_message: e.to_string(),
1574            },
1575            BdkPsbtError::PartialDataConsumption => PsbtError::PartialDataConsumption,
1576            BdkPsbtError::Io(e) => PsbtError::Io {
1577                error_message: e.to_string(),
1578            },
1579            _ => PsbtError::OtherPsbtErr,
1580        }
1581    }
1582}
1583
1584impl From<BdkPsbtParseError> for PsbtParseError {
1585    fn from(error: BdkPsbtParseError) -> Self {
1586        match error {
1587            BdkPsbtParseError::PsbtEncoding(e) => PsbtParseError::PsbtEncoding {
1588                error_message: e.to_string(),
1589            },
1590            BdkPsbtParseError::Base64Encoding(e) => PsbtParseError::Base64Encoding {
1591                error_message: e.to_string(),
1592            },
1593            _ => {
1594                unreachable!("this is required because of the non-exhaustive enum in rust-bitcoin")
1595            }
1596        }
1597    }
1598}
1599
1600impl From<std::io::Error> for PsbtError {
1601    fn from(error: std::io::Error) -> Self {
1602        PsbtError::Io {
1603            error_message: error.to_string(),
1604        }
1605    }
1606}
1607
1608impl From<bdk_wallet::bitcoin::io::Error> for PsbtError {
1609    fn from(error: bdk_wallet::bitcoin::io::Error) -> Self {
1610        PsbtError::Io {
1611            error_message: error.to_string(),
1612        }
1613    }
1614}
1615
1616impl From<BdkPsbtFinalizeError> for PsbtFinalizeError {
1617    fn from(value: BdkPsbtFinalizeError) -> Self {
1618        match value {
1619            BdkPsbtFinalizeError::InputError(input_error, index) => PsbtFinalizeError::InputError {
1620                reason: input_error.to_string(),
1621                index: index as u32,
1622            },
1623            BdkPsbtFinalizeError::WrongInputCount { in_tx, in_map } => {
1624                PsbtFinalizeError::WrongInputCount {
1625                    in_tx: in_tx as u32,
1626                    in_map: in_map as u32,
1627                }
1628            }
1629            BdkPsbtFinalizeError::InputIdxOutofBounds { psbt_inp, index } => {
1630                PsbtFinalizeError::InputIdxOutofBounds {
1631                    psbt_inp: psbt_inp as u32,
1632                    requested: index as u32,
1633                }
1634            }
1635        }
1636    }
1637}
1638
1639#[allow(deprecated)]
1640impl From<BdkSignerError> for SignerError {
1641    fn from(error: BdkSignerError) -> Self {
1642        match error {
1643            BdkSignerError::MissingKey => SignerError::MissingKey,
1644            BdkSignerError::InvalidKey => SignerError::InvalidKey,
1645            BdkSignerError::UserCanceled => SignerError::UserCanceled,
1646            BdkSignerError::InputIndexOutOfRange(_) => SignerError::InputIndexOutOfRange,
1647            BdkSignerError::MissingNonWitnessUtxo => SignerError::MissingNonWitnessUtxo,
1648            BdkSignerError::InvalidNonWitnessUtxo => SignerError::InvalidNonWitnessUtxo,
1649            BdkSignerError::MissingWitnessUtxo => SignerError::MissingWitnessUtxo,
1650            BdkSignerError::MissingWitnessScript => SignerError::MissingWitnessScript,
1651            BdkSignerError::MissingHdKeypath => SignerError::MissingHdKeypath,
1652            BdkSignerError::NonStandardSighash => SignerError::NonStandardSighash,
1653            BdkSignerError::InvalidSighash => SignerError::InvalidSighash,
1654            BdkSignerError::SighashTaproot(e) => SignerError::SighashTaproot {
1655                error_message: e.to_string(),
1656            },
1657            BdkSignerError::MiniscriptPsbt(e) => SignerError::MiniscriptPsbt {
1658                error_message: e.to_string(),
1659            },
1660            BdkSignerError::External(e) => SignerError::External { error_message: e },
1661            BdkSignerError::Psbt(e) => SignerError::Psbt {
1662                error_message: e.to_string(),
1663            },
1664        }
1665    }
1666}
1667
1668impl From<BdkEncodeError> for TransactionError {
1669    fn from(error: BdkEncodeError) -> Self {
1670        match error {
1671            BdkEncodeError::Io(_) => TransactionError::Io,
1672            BdkEncodeError::OversizedVectorAllocation { .. } => {
1673                TransactionError::OversizedVectorAllocation
1674            }
1675            BdkEncodeError::InvalidChecksum { expected, actual } => {
1676                TransactionError::InvalidChecksum {
1677                    expected: DisplayHex::to_lower_hex_string(&expected),
1678                    actual: DisplayHex::to_lower_hex_string(&actual),
1679                }
1680            }
1681            BdkEncodeError::NonMinimalVarInt => TransactionError::NonMinimalVarInt,
1682            BdkEncodeError::ParseFailed(_) => TransactionError::ParseFailed,
1683            BdkEncodeError::UnsupportedSegwitFlag(flag) => {
1684                TransactionError::UnsupportedSegwitFlag { flag }
1685            }
1686            _ => TransactionError::OtherTransactionErr,
1687        }
1688    }
1689}
1690
1691impl From<bdk_kyoto::bip157::ClientError> for CbfError {
1692    fn from(_value: bdk_kyoto::bip157::ClientError) -> Self {
1693        CbfError::NodeStopped
1694    }
1695}