anyswap_sdk/driver/
error.rs1use anyswap_core::{
2 transaction::TxError,
3 types::{Chain, SwapNetwork, SwapType},
4};
5use thiserror::Error;
6use uuid::Uuid;
7
8use super::{chain::ChainError, record::StoreError};
9use crate::{client::ClientError, swap_script::ScriptError, utxo::UtxoError};
10
11#[derive(Clone, Debug, Error)]
12pub enum DriverError {
13 #[error(transparent)]
14 Chain(#[from] ChainError),
15
16 #[error("server: {0}")]
17 Server(#[from] ClientError),
18
19 #[error(transparent)]
20 Store(#[from] StoreError),
21
22 #[error("destination: {0}")]
23 Destination(String),
24
25 #[error("wallet: {0}")]
26 Wallet(String),
27
28 #[error("refused: {0}")]
29 Refused(#[from] Refusal),
30
31 #[error(transparent)]
32 Tx(#[from] TxError),
33
34 #[error(transparent)]
35 Utxo(#[from] UtxoError),
36
37 #[error("chain {0} is not configured")]
38 ChainNotConfigured(Chain),
39
40 #[error("chain {0} config: {1}")]
41 InvalidChainConfig(Chain, &'static str),
42
43 #[error("swap {0} is not in the store")]
44 Unknown(Uuid),
45
46 #[error("the record of swap {0} has no {1}")]
47 MissingField(Uuid, String),
48
49 #[error("the record of swap {0} is version {1}, which this SDK does not drive")]
50 RecordVersion(Uuid, u32),
51
52 #[error("swap type {0} is not driven")]
53 Unsupported(SwapType),
54
55 #[error("the server holds no signed request for swap {0}")]
56 Unsigned(Uuid),
57
58 #[error("the signed request of swap {0} does not verify")]
59 BadSignature(Uuid),
60
61 #[error("the quote expired")]
62 QuoteExpired,
63
64 #[error("the swap type does not match")]
65 WrongSwapType,
66
67 #[error("the server offers no quote: {0}")]
68 NotQuotable(&'static str),
69
70 #[error("amount outside {min}..={max}")]
71 AmountOutOfRange { min: u64, max: u64 },
72}
73
74impl DriverError {
75 pub fn retryable(&self) -> bool {
79 match self {
80 Self::Chain(_) | Self::Server(ClientError::Transport(_)) => true,
81 Self::Server(ClientError::Api { status, .. }) => *status == 429 || *status >= 500,
82 _ => false,
83 }
84 }
85}
86
87impl From<ScriptError> for DriverError {
88 fn from(e: ScriptError) -> Self {
89 Self::Refused(e.into())
90 }
91}
92
93#[derive(Clone, Debug, PartialEq, Error)]
95pub enum Refusal {
96 #[error("the server is on {found}, this wallet on {expected}")]
97 Network {
98 expected: SwapNetwork,
99 found: SwapNetwork,
100 },
101
102 #[error("protocol version {found}, asked {expected}")]
103 ProtocolVersion { expected: String, found: String },
104
105 #[error("swap type {0}")]
106 SwapType(SwapType),
107
108 #[error("swap id {0}")]
109 SwapId(Uuid),
110
111 #[error("chain {0}")]
112 Chain(Chain),
113
114 #[error("asset {0}")]
115 Asset(String),
116
117 #[error("receive amount {found}, asked {expected}")]
118 ReceiveAmount { expected: u64, found: u64 },
119
120 #[error(
121 "send amount {found} as {receive_amount} + {base_fee} + {service_fee}, asked {expected}"
122 )]
123 SendAmount {
124 expected: u64,
125 found: u64,
126 receive_amount: u64,
127 base_fee: u64,
128 service_fee: u64,
129 },
130
131 #[error("script: {0}")]
132 Script(String),
133
134 #[error("address: {0}")]
135 Address(String),
136
137 #[error("blinding pubkey")]
138 BlindingPubkey,
139
140 #[error("our pubkey")]
141 OurPubkey,
142
143 #[error("claim invoice differs from the one submitted")]
144 ClaimInvoice,
145
146 #[error("payment hash")]
147 PaymentHash,
148
149 #[error("invoice: {0}")]
150 Invoice(String),
151
152 #[error("csv {csv} outside {min}..={max}")]
153 Csv { csv: u32, min: u32, max: u32 },
154
155 #[error(
156 "funding timeout {funding_timeout} s and {confirm} s to confirm outlast the server's wait of {await_opening_tx} s"
157 )]
158 FundingTimeout {
159 funding_timeout: u64,
160 confirm: u64,
161 await_opening_tx: u64,
162 },
163
164 #[error("wallet: {0}")]
165 Wallet(String),
166
167 #[error("Liquid is not configured")]
168 LiquidNotConfigured,
169
170 #[error("malformed: {0}")]
171 Malformed(String),
172}
173
174impl From<ScriptError> for Refusal {
175 fn from(e: ScriptError) -> Self {
176 match e {
177 ScriptError::LiquidNotConfigured => Self::LiquidNotConfigured,
178 ScriptError::UnexpectedAsset { found, .. } => Self::Asset(found),
179 ScriptError::MissingField(_) => Self::BlindingPubkey,
180 ScriptError::Wallet(e) => Self::Wallet(e),
181 ScriptError::Script(e) => Self::Script(e),
182 }
183 }
184}