1use thiserror::Error;
4use uuid::Uuid;
5
6#[derive(Debug, Error)]
8pub enum Error {
9 #[error("Fee estimation failed: {0}")]
11 FeeEstimationFailed(String),
12 #[error("Fee estimation unavailable")]
14 FeeEstimationUnavailable,
15 #[error("No spendable UTXOs available for onchain payment quote")]
17 NoSpendableUtxos,
18 #[error("Start called but background tasks are already running")]
20 AlreadyStarted,
21
22 #[error("Invalid configuration: {0}")]
24 InvalidConfig(String),
25
26 #[error("Unsupported payment type for onchain backend")]
28 UnsupportedOnchain,
29
30 #[error("unknown fee_index {0}; expected one of the configured BDK fee options")]
32 UnknownFeeIndex(u32),
33
34 #[error("JSON error: {0}")]
36 Json(#[from] serde_json::Error),
37
38 #[error("Amount conversion error: {0}")]
40 AmountConversion(#[from] cdk_common::amount::Error),
41
42 #[error("Database error: {0}")]
44 Database(#[from] bdk_wallet::rusqlite::Error),
45
46 #[error("Wallet error: {0}")]
48 Wallet(String),
49
50 #[cfg(feature = "bitcoin-rpc")]
52 #[error("Bitcoin RPC error: {0}")]
53 BitcoinRpc(#[from] bdk_bitcoind_rpc::bitcoincore_rpc::Error),
54
55 #[error("Esplora error: {0}")]
57 Esplora(String),
58
59 #[error("Bip32 key derivation error: {0}")]
61 Bip32(#[from] bdk_wallet::bitcoin::bip32::Error),
62
63 #[error("Key derivation error: {0}")]
65 KeyDerivation(#[from] bdk_wallet::keys::KeyError),
66
67 #[error("Could not sign transaction")]
69 CouldNotSign,
70
71 #[error("Path error")]
73 Path,
74
75 #[error("IO error: {0}")]
77 Io(#[from] std::io::Error),
78
79 #[error("KV Store error: {0}")]
81 KvStore(#[from] cdk_common::database::Error),
82
83 #[error("Could not find matching output vout in transaction")]
85 VoutNotFound,
86
87 #[error("Send intent not found: {0}")]
89 SendIntentNotFound(Uuid),
90
91 #[error("Send batch not found: {0}")]
93 SendBatchNotFound(Uuid),
94
95 #[error("Send intent already exists for quote id: {0}")]
97 DuplicateQuoteId(String),
98
99 #[error("Batch fee {actual_fee} exceeds combined max fee {max_fee}")]
101 BatchFeeTooHigh {
102 actual_fee: u64,
104 max_fee: u64,
106 },
107
108 #[error("Estimated fee {estimated_fee} exceeds max fee {max_fee}")]
110 EstimatedFeeTooHigh {
111 estimated_fee: u64,
113 max_fee: u64,
115 },
116
117 #[error("No valid fee allocation for batch")]
119 NoValidFeeAllocation,
120
121 #[error("Requested output amount {amount} sats is below dust limit {dust_limit} sats")]
123 DustOutput {
124 amount: u64,
126 dust_limit: u64,
128 },
129
130 #[error("Requested send amount {amount} sats is below minimum {min} sats")]
132 AmountBelowMinimumSend {
133 amount: u64,
135 min: u64,
137 },
138
139 #[error("Batch {batch_id} is missing an output assignment for intent {intent_id}")]
144 BatchAssignmentMissing {
145 batch_id: Uuid,
147 intent_id: Uuid,
149 },
150
151 #[error("Receive intent not found: {0}")]
153 ReceiveIntentNotFound(Uuid),
154
155 #[error("Receive address not found: {0}")]
157 ReceiveAddressNotFound(String),
158
159 #[error("Database error")]
161 BdkPersist,
162}
163
164impl From<Error> for cdk_common::payment::Error {
165 fn from(e: Error) -> Self {
166 Self::Onchain(Box::new(e))
167 }
168}
169
170impl Error {
171 pub fn is_transient(&self) -> bool {
178 match self {
179 #[cfg(feature = "bitcoin-rpc")]
185 Self::BitcoinRpc(_) => true,
186 Self::Esplora(_) => true,
187 Self::Io(e) => matches!(
188 e.kind(),
189 std::io::ErrorKind::TimedOut
190 | std::io::ErrorKind::ConnectionRefused
191 | std::io::ErrorKind::ConnectionReset
192 | std::io::ErrorKind::ConnectionAborted
193 | std::io::ErrorKind::NotConnected
194 | std::io::ErrorKind::BrokenPipe
195 | std::io::ErrorKind::Interrupted
196 | std::io::ErrorKind::UnexpectedEof
197 | std::io::ErrorKind::WouldBlock
198 ),
199 _ => false,
200 }
201 }
202}