1use cdk_common::CurrencyUnit;
4use thiserror::Error;
5use uuid::Uuid;
6
7#[derive(Debug, Error)]
9pub enum Error {
10 #[error("Fee estimation failed: {0}")]
12 FeeEstimationFailed(String),
13 #[error("Fee estimation unavailable")]
15 FeeEstimationUnavailable,
16 #[error("No spendable UTXOs available for onchain payment quote")]
18 NoSpendableUtxos,
19 #[error("Start called but background tasks are already running")]
21 AlreadyStarted,
22
23 #[error("Invalid configuration: {0}")]
25 InvalidConfig(String),
26
27 #[error("Unsupported payment type for onchain backend")]
29 UnsupportedOnchain,
30
31 #[error("unknown fee_index {0}; expected one of the configured BDK fee options")]
33 UnknownFeeIndex(u32),
34
35 #[error("JSON error: {0}")]
37 Json(#[from] serde_json::Error),
38
39 #[error("Amount conversion error: {0}")]
41 AmountConversion(#[from] cdk_common::amount::Error),
42
43 #[error("Amount unit {actual} does not match payment unit {expected}")]
45 AmountUnitMismatch {
46 expected: CurrencyUnit,
48 actual: CurrencyUnit,
50 },
51
52 #[error("Onchain payment amount {amount_msat} msat is not a whole number of satoshis")]
54 FractionalSatoshiAmount {
55 amount_msat: u64,
57 },
58
59 #[error("Database error: {0}")]
61 Database(#[from] bdk_wallet::rusqlite::Error),
62
63 #[error("Wallet error: {0}")]
65 Wallet(String),
66
67 #[cfg(feature = "bitcoin-rpc")]
69 #[error("Bitcoin RPC error: {0}")]
70 BitcoinRpc(#[from] bdk_bitcoind_rpc::bitcoincore_rpc::Error),
71
72 #[error("Esplora error: {0}")]
74 Esplora(String),
75
76 #[error("Bip32 key derivation error: {0}")]
78 Bip32(#[from] bdk_wallet::bitcoin::bip32::Error),
79
80 #[error("Key derivation error: {0}")]
82 KeyDerivation(#[from] bdk_wallet::keys::KeyError),
83
84 #[error("Could not sign transaction")]
86 CouldNotSign,
87
88 #[error("Path error")]
90 Path,
91
92 #[error("IO error: {0}")]
94 Io(#[from] std::io::Error),
95
96 #[error("KV Store error: {0}")]
98 KvStore(#[from] cdk_common::database::Error),
99
100 #[error("Could not find matching output vout in transaction")]
102 VoutNotFound,
103
104 #[error("Send intent not found: {0}")]
106 SendIntentNotFound(Uuid),
107
108 #[error("Send batch not found: {0}")]
110 SendBatchNotFound(Uuid),
111
112 #[error("Send intent already exists for quote id: {0}")]
114 DuplicateQuoteId(String),
115
116 #[error("Batch fee {actual_fee} exceeds combined max fee {max_fee}")]
118 BatchFeeTooHigh {
119 actual_fee: u64,
121 max_fee: u64,
123 },
124
125 #[error("Estimated fee {estimated_fee} exceeds max fee {max_fee}")]
127 EstimatedFeeTooHigh {
128 estimated_fee: u64,
130 max_fee: u64,
132 },
133
134 #[error("No valid fee allocation for batch")]
136 NoValidFeeAllocation,
137
138 #[error("Requested output amount {amount} sats is below dust limit {dust_limit} sats")]
140 DustOutput {
141 amount: u64,
143 dust_limit: u64,
145 },
146
147 #[error("Requested send amount {amount} sats is below minimum {min} sats")]
149 AmountBelowMinimumSend {
150 amount: u64,
152 min: u64,
154 },
155
156 #[error("Batch {batch_id} is missing an output assignment for intent {intent_id}")]
161 BatchAssignmentMissing {
162 batch_id: Uuid,
164 intent_id: Uuid,
166 },
167
168 #[error("Receive intent not found: {0}")]
170 ReceiveIntentNotFound(Uuid),
171
172 #[error("Receive address not found: {0}")]
174 ReceiveAddressNotFound(String),
175
176 #[error("Database error")]
178 BdkPersist,
179}
180
181impl From<Error> for cdk_common::payment::Error {
182 fn from(e: Error) -> Self {
183 Self::Onchain(Box::new(e))
184 }
185}
186
187impl Error {
188 pub fn is_transient(&self) -> bool {
195 match self {
196 #[cfg(feature = "bitcoin-rpc")]
202 Self::BitcoinRpc(_) => true,
203 Self::Esplora(_) => true,
204 Self::Io(e) => matches!(
205 e.kind(),
206 std::io::ErrorKind::TimedOut
207 | std::io::ErrorKind::ConnectionRefused
208 | std::io::ErrorKind::ConnectionReset
209 | std::io::ErrorKind::ConnectionAborted
210 | std::io::ErrorKind::NotConnected
211 | std::io::ErrorKind::BrokenPipe
212 | std::io::ErrorKind::Interrupted
213 | std::io::ErrorKind::UnexpectedEof
214 | std::io::ErrorKind::WouldBlock
215 ),
216 _ => false,
217 }
218 }
219}