error.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. //! Errors
  2. use std::fmt;
  3. use cashu::{CurrencyUnit, PaymentMethod};
  4. use serde::{Deserialize, Deserializer, Serialize, Serializer};
  5. use serde_json::Value;
  6. use thiserror::Error;
  7. use crate::nuts::Id;
  8. use crate::util::hex;
  9. #[cfg(feature = "wallet")]
  10. use crate::wallet::WalletKey;
  11. use crate::Amount;
  12. /// CDK Error
  13. #[derive(Debug, Error)]
  14. pub enum Error {
  15. /// Mint does not have a key for amount
  16. #[error("No Key for Amount")]
  17. AmountKey,
  18. /// Keyset is not known
  19. #[error("Keyset id not known: `{0}`")]
  20. KeysetUnknown(Id),
  21. /// Unsupported unit
  22. #[error("Unit unsupported")]
  23. UnsupportedUnit,
  24. /// Payment failed
  25. #[error("Payment failed")]
  26. PaymentFailed,
  27. /// Payment pending
  28. #[error("Payment pending")]
  29. PaymentPending,
  30. /// Invoice already paid
  31. #[error("Request already paid")]
  32. RequestAlreadyPaid,
  33. /// Invalid payment request
  34. #[error("Invalid payment request")]
  35. InvalidPaymentRequest,
  36. /// Bolt11 invoice does not have amount
  37. #[error("Invoice Amount undefined")]
  38. InvoiceAmountUndefined,
  39. /// Split Values must be less then or equal to amount
  40. #[error("Split Values must be less then or equal to amount")]
  41. SplitValuesGreater,
  42. /// Amount overflow
  43. #[error("Amount Overflow")]
  44. AmountOverflow,
  45. /// Witness missing or invalid
  46. #[error("Signature missing or invalid")]
  47. SignatureMissingOrInvalid,
  48. /// Amountless Invoice Not supported
  49. #[error("Amount Less Invoice is not allowed")]
  50. AmountLessNotAllowed,
  51. /// Multi-Part Internal Melt Quotes are not supported
  52. #[error("Multi-Part Internal Melt Quotes are not supported")]
  53. InternalMultiPartMeltQuote,
  54. /// Multi-Part Payment not supported for unit and method
  55. #[error("Multi-Part payment is not supported for unit `{0}` and method `{1}`")]
  56. MppUnitMethodNotSupported(CurrencyUnit, PaymentMethod),
  57. /// Clear Auth Required
  58. #[error("Clear Auth Required")]
  59. ClearAuthRequired,
  60. /// Blind Auth Required
  61. #[error("Blind Auth Required")]
  62. BlindAuthRequired,
  63. /// Clear Auth Failed
  64. #[error("Clear Auth Failed")]
  65. ClearAuthFailed,
  66. /// Blind Auth Failed
  67. #[error("Blind Auth Failed")]
  68. BlindAuthFailed,
  69. /// Auth settings undefined
  70. #[error("Auth settings undefined")]
  71. AuthSettingsUndefined,
  72. /// Mint time outside of tolerance
  73. #[error("Mint time outside of tolerance")]
  74. MintTimeExceedsTolerance,
  75. /// Insufficient blind auth tokens
  76. #[error("Insufficient blind auth tokens, must reauth")]
  77. InsufficientBlindAuthTokens,
  78. /// Auth localstore undefined
  79. #[error("Auth localstore undefined")]
  80. AuthLocalstoreUndefined,
  81. /// Wallet cat not set
  82. #[error("Wallet cat not set")]
  83. CatNotSet,
  84. /// Could not get mint info
  85. #[error("Could not get mint info")]
  86. CouldNotGetMintInfo,
  87. /// Multi-Part Payment not supported for unit and method
  88. #[error("Amountless invoices are not supported for unit `{0}` and method `{1}`")]
  89. AmountlessInvoiceNotSupported(CurrencyUnit, PaymentMethod),
  90. /// Internal Error - Send error
  91. #[error("Internal send error: {0}")]
  92. SendError(String),
  93. /// Internal Error - Recv error
  94. #[error("Internal receive error: {0}")]
  95. RecvError(String),
  96. /// Not supported
  97. #[error("Functionality not supported")]
  98. NotSupported,
  99. // Mint Errors
  100. /// Minting is disabled
  101. #[error("Minting is disabled")]
  102. MintingDisabled,
  103. /// Quote is not known
  104. #[error("Unknown quote")]
  105. UnknownQuote,
  106. /// Quote is expired
  107. #[error("Expired quote: Expired: `{0}`, Time: `{1}`")]
  108. ExpiredQuote(u64, u64),
  109. /// Amount is outside of allowed range
  110. #[error("Amount must be between `{0}` and `{1}` is `{2}`")]
  111. AmountOutofLimitRange(Amount, Amount, Amount),
  112. /// Quote is not paiud
  113. #[error("Quote not paid")]
  114. UnpaidQuote,
  115. /// Quote is pending
  116. #[error("Quote pending")]
  117. PendingQuote,
  118. /// ecash already issued for quote
  119. #[error("Quote already issued")]
  120. IssuedQuote,
  121. /// Quote has already been paid
  122. #[error("Quote is already paid")]
  123. PaidQuote,
  124. /// Payment state is unknown
  125. #[error("Payment state is unknown")]
  126. UnknownPaymentState,
  127. /// Melting is disabled
  128. #[error("Minting is disabled")]
  129. MeltingDisabled,
  130. /// Unknown Keyset
  131. #[error("Unknown Keyset")]
  132. UnknownKeySet,
  133. /// BlindedMessage is already signed
  134. #[error("Blinded Message is already signed")]
  135. BlindedMessageAlreadySigned,
  136. /// Inactive Keyset
  137. #[error("Inactive Keyset")]
  138. InactiveKeyset,
  139. /// Transaction unbalanced
  140. #[error("Inputs: `{0}`, Outputs: `{1}`, Expected Fee: `{2}`")]
  141. TransactionUnbalanced(u64, u64, u64),
  142. /// Duplicate proofs provided
  143. #[error("Duplicate Inputs")]
  144. DuplicateInputs,
  145. /// Duplicate output
  146. #[error("Duplicate outputs")]
  147. DuplicateOutputs,
  148. /// Multiple units provided
  149. #[error("Cannot have multiple units")]
  150. MultipleUnits,
  151. /// Unit mismatch
  152. #[error("Input unit must match output")]
  153. UnitMismatch,
  154. /// Sig all cannot be used in melt
  155. #[error("Sig all cannot be used in melt")]
  156. SigAllUsedInMelt,
  157. /// Token is already spent
  158. #[error("Token Already Spent")]
  159. TokenAlreadySpent,
  160. /// Token is already pending
  161. #[error("Token Pending")]
  162. TokenPending,
  163. /// Internal Error
  164. #[error("Internal Error")]
  165. Internal,
  166. /// Oidc config not set
  167. #[error("Oidc client not set")]
  168. OidcNotSet,
  169. // Wallet Errors
  170. /// P2PK spending conditions not met
  171. #[error("P2PK condition not met `{0}`")]
  172. P2PKConditionsNotMet(String),
  173. /// Spending Locktime not provided
  174. #[error("Spending condition locktime not provided")]
  175. LocktimeNotProvided,
  176. /// Invalid Spending Conditions
  177. #[error("Invalid spending conditions: `{0}`")]
  178. InvalidSpendConditions(String),
  179. /// Incorrect Wallet
  180. #[error("Incorrect wallet: `{0}`")]
  181. IncorrectWallet(String),
  182. /// Unknown Wallet
  183. #[error("Unknown wallet: `{0}`")]
  184. #[cfg(feature = "wallet")]
  185. UnknownWallet(WalletKey),
  186. /// Max Fee Ecxeded
  187. #[error("Max fee exceeded")]
  188. MaxFeeExceeded,
  189. /// Url path segments could not be joined
  190. #[error("Url path segments could not be joined")]
  191. UrlPathSegments,
  192. /// Unknown error response
  193. #[error("Unknown error response: `{0}`")]
  194. UnknownErrorResponse(String),
  195. /// Invalid DLEQ proof
  196. #[error("Could not verify DLEQ proof")]
  197. CouldNotVerifyDleq,
  198. /// Dleq Proof not provided for signature
  199. #[error("Dleq proof not provided for signature")]
  200. DleqProofNotProvided,
  201. /// Incorrect Mint
  202. /// Token does not match wallet mint
  203. #[error("Token does not match wallet mint")]
  204. IncorrectMint,
  205. /// Receive can only be used with tokens from single mint
  206. #[error("Multiple mint tokens not supported by receive. Please deconstruct the token and use receive with_proof")]
  207. MultiMintTokenNotSupported,
  208. /// Preimage not provided
  209. #[error("Preimage not provided")]
  210. PreimageNotProvided,
  211. /// Insufficient Funds
  212. #[error("Insufficient funds")]
  213. InsufficientFunds,
  214. /// Unexpected proof state
  215. #[error("Unexpected proof state")]
  216. UnexpectedProofState,
  217. /// No active keyset
  218. #[error("No active keyset")]
  219. NoActiveKeyset,
  220. /// Incorrect quote amount
  221. #[error("Incorrect quote amount")]
  222. IncorrectQuoteAmount,
  223. /// Invoice Description not supported
  224. #[error("Invoice Description not supported")]
  225. InvoiceDescriptionUnsupported,
  226. /// Invalid transaction direction
  227. #[error("Invalid transaction direction")]
  228. InvalidTransactionDirection,
  229. /// Invalid transaction id
  230. #[error("Invalid transaction id")]
  231. InvalidTransactionId,
  232. /// Transaction not found
  233. #[error("Transaction not found")]
  234. TransactionNotFound,
  235. /// Custom Error
  236. #[error("`{0}`")]
  237. Custom(String),
  238. // External Error conversions
  239. /// Parse invoice error
  240. #[error(transparent)]
  241. Invoice(#[from] lightning_invoice::ParseOrSemanticError),
  242. /// Bip32 error
  243. #[error(transparent)]
  244. Bip32(#[from] bitcoin::bip32::Error),
  245. /// Parse int error
  246. #[error(transparent)]
  247. ParseInt(#[from] std::num::ParseIntError),
  248. /// Parse 9rl Error
  249. #[error(transparent)]
  250. UrlParseError(#[from] url::ParseError),
  251. /// Utf8 parse error
  252. #[error(transparent)]
  253. Utf8ParseError(#[from] std::string::FromUtf8Error),
  254. /// Serde Json error
  255. #[error(transparent)]
  256. SerdeJsonError(#[from] serde_json::Error),
  257. /// Base64 error
  258. #[error(transparent)]
  259. Base64Error(#[from] bitcoin::base64::DecodeError),
  260. /// From hex error
  261. #[error(transparent)]
  262. HexError(#[from] hex::Error),
  263. /// Http transport error
  264. #[error("Http transport error: {0}")]
  265. HttpError(String),
  266. #[cfg(feature = "wallet")]
  267. // Crate error conversions
  268. /// Cashu Url Error
  269. #[error(transparent)]
  270. CashuUrl(#[from] crate::mint_url::Error),
  271. /// Secret error
  272. #[error(transparent)]
  273. Secret(#[from] crate::secret::Error),
  274. /// Amount Error
  275. #[error(transparent)]
  276. AmountError(#[from] crate::amount::Error),
  277. /// DHKE Error
  278. #[error(transparent)]
  279. DHKE(#[from] crate::dhke::Error),
  280. /// NUT00 Error
  281. #[error(transparent)]
  282. NUT00(#[from] crate::nuts::nut00::Error),
  283. /// Nut01 error
  284. #[error(transparent)]
  285. NUT01(#[from] crate::nuts::nut01::Error),
  286. /// NUT02 error
  287. #[error(transparent)]
  288. NUT02(#[from] crate::nuts::nut02::Error),
  289. /// NUT03 error
  290. #[error(transparent)]
  291. NUT03(#[from] crate::nuts::nut03::Error),
  292. /// NUT04 error
  293. #[error(transparent)]
  294. NUT04(#[from] crate::nuts::nut04::Error),
  295. /// NUT05 error
  296. #[error(transparent)]
  297. NUT05(#[from] crate::nuts::nut05::Error),
  298. /// NUT11 Error
  299. #[error(transparent)]
  300. NUT11(#[from] crate::nuts::nut11::Error),
  301. /// NUT12 Error
  302. #[error(transparent)]
  303. NUT12(#[from] crate::nuts::nut12::Error),
  304. /// NUT13 Error
  305. #[error(transparent)]
  306. #[cfg(feature = "wallet")]
  307. NUT13(#[from] crate::nuts::nut13::Error),
  308. /// NUT14 Error
  309. #[error(transparent)]
  310. NUT14(#[from] crate::nuts::nut14::Error),
  311. /// NUT18 Error
  312. #[error(transparent)]
  313. NUT18(#[from] crate::nuts::nut18::Error),
  314. /// NUT20 Error
  315. #[error(transparent)]
  316. NUT20(#[from] crate::nuts::nut20::Error),
  317. /// NUT21 Error
  318. #[error(transparent)]
  319. NUT21(#[from] crate::nuts::nut21::Error),
  320. /// NUT22 Error
  321. #[error(transparent)]
  322. NUT22(#[from] crate::nuts::nut22::Error),
  323. /// NUT23 Error
  324. #[error(transparent)]
  325. NUT23(#[from] crate::nuts::nut23::Error),
  326. /// Database Error
  327. #[error(transparent)]
  328. Database(crate::database::Error),
  329. /// Payment Error
  330. #[error(transparent)]
  331. #[cfg(feature = "mint")]
  332. Payment(#[from] crate::payment::Error),
  333. }
  334. /// CDK Error Response
  335. ///
  336. /// See NUT definition in [00](https://github.com/cashubtc/nuts/blob/main/00.md)
  337. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
  338. #[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
  339. pub struct ErrorResponse {
  340. /// Error Code
  341. pub code: ErrorCode,
  342. /// Human readable Text
  343. pub error: Option<String>,
  344. /// Longer human readable description
  345. pub detail: Option<String>,
  346. }
  347. impl fmt::Display for ErrorResponse {
  348. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  349. write!(
  350. f,
  351. "code: {}, error: {}, detail: {}",
  352. self.code,
  353. self.error.clone().unwrap_or_default(),
  354. self.detail.clone().unwrap_or_default()
  355. )
  356. }
  357. }
  358. impl ErrorResponse {
  359. /// Create new [`ErrorResponse`]
  360. pub fn new(code: ErrorCode, error: Option<String>, detail: Option<String>) -> Self {
  361. Self {
  362. code,
  363. error,
  364. detail,
  365. }
  366. }
  367. /// Error response from json
  368. pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
  369. let value: Value = serde_json::from_str(json)?;
  370. Self::from_value(value)
  371. }
  372. /// Error response from json Value
  373. pub fn from_value(value: Value) -> Result<Self, serde_json::Error> {
  374. match serde_json::from_value::<ErrorResponse>(value.clone()) {
  375. Ok(res) => Ok(res),
  376. Err(_) => Ok(Self {
  377. code: ErrorCode::Unknown(999),
  378. error: Some(value.to_string()),
  379. detail: None,
  380. }),
  381. }
  382. }
  383. }
  384. impl From<Error> for ErrorResponse {
  385. fn from(err: Error) -> ErrorResponse {
  386. match err {
  387. Error::TokenAlreadySpent => ErrorResponse {
  388. code: ErrorCode::TokenAlreadySpent,
  389. error: Some(err.to_string()),
  390. detail: None,
  391. },
  392. Error::UnsupportedUnit => ErrorResponse {
  393. code: ErrorCode::UnsupportedUnit,
  394. error: Some(err.to_string()),
  395. detail: None,
  396. },
  397. Error::PaymentFailed => ErrorResponse {
  398. code: ErrorCode::LightningError,
  399. error: Some(err.to_string()),
  400. detail: None,
  401. },
  402. Error::RequestAlreadyPaid => ErrorResponse {
  403. code: ErrorCode::InvoiceAlreadyPaid,
  404. error: Some("Invoice already paid.".to_string()),
  405. detail: None,
  406. },
  407. Error::TransactionUnbalanced(inputs_total, outputs_total, fee_expected) => {
  408. ErrorResponse {
  409. code: ErrorCode::TransactionUnbalanced,
  410. error: Some(format!(
  411. "Inputs: {inputs_total}, Outputs: {outputs_total}, expected_fee: {fee_expected}",
  412. )),
  413. detail: Some("Transaction inputs should equal outputs less fee".to_string()),
  414. }
  415. }
  416. Error::MintingDisabled => ErrorResponse {
  417. code: ErrorCode::MintingDisabled,
  418. error: Some(err.to_string()),
  419. detail: None,
  420. },
  421. Error::BlindedMessageAlreadySigned => ErrorResponse {
  422. code: ErrorCode::BlindedMessageAlreadySigned,
  423. error: Some(err.to_string()),
  424. detail: None,
  425. },
  426. Error::InsufficientFunds => ErrorResponse {
  427. code: ErrorCode::TransactionUnbalanced,
  428. error: Some(err.to_string()),
  429. detail: None,
  430. },
  431. Error::AmountOutofLimitRange(_min, _max, _amount) => ErrorResponse {
  432. code: ErrorCode::AmountOutofLimitRange,
  433. error: Some(err.to_string()),
  434. detail: None,
  435. },
  436. Error::ExpiredQuote(_, _) => ErrorResponse {
  437. code: ErrorCode::QuoteExpired,
  438. error: Some(err.to_string()),
  439. detail: None,
  440. },
  441. Error::PendingQuote => ErrorResponse {
  442. code: ErrorCode::QuotePending,
  443. error: Some(err.to_string()),
  444. detail: None,
  445. },
  446. Error::TokenPending => ErrorResponse {
  447. code: ErrorCode::TokenPending,
  448. error: Some(err.to_string()),
  449. detail: None,
  450. },
  451. Error::ClearAuthRequired => ErrorResponse {
  452. code: ErrorCode::ClearAuthRequired,
  453. error: None,
  454. detail: None,
  455. },
  456. Error::ClearAuthFailed => ErrorResponse {
  457. code: ErrorCode::ClearAuthFailed,
  458. error: None,
  459. detail: None,
  460. },
  461. Error::BlindAuthRequired => ErrorResponse {
  462. code: ErrorCode::BlindAuthRequired,
  463. error: None,
  464. detail: None,
  465. },
  466. Error::BlindAuthFailed => ErrorResponse {
  467. code: ErrorCode::BlindAuthFailed,
  468. error: None,
  469. detail: None,
  470. },
  471. Error::NUT20(err) => ErrorResponse {
  472. code: ErrorCode::WitnessMissingOrInvalid,
  473. error: Some(err.to_string()),
  474. detail: None,
  475. },
  476. Error::DuplicateInputs => ErrorResponse {
  477. code: ErrorCode::DuplicateInputs,
  478. error: Some(err.to_string()),
  479. detail: None,
  480. },
  481. Error::DuplicateOutputs => ErrorResponse {
  482. code: ErrorCode::DuplicateOutputs,
  483. error: Some(err.to_string()),
  484. detail: None,
  485. },
  486. Error::MultipleUnits => ErrorResponse {
  487. code: ErrorCode::MultipleUnits,
  488. error: Some(err.to_string()),
  489. detail: None,
  490. },
  491. Error::UnitMismatch => ErrorResponse {
  492. code: ErrorCode::UnitMismatch,
  493. error: Some(err.to_string()),
  494. detail: None,
  495. },
  496. _ => ErrorResponse {
  497. code: ErrorCode::Unknown(9999),
  498. error: Some(err.to_string()),
  499. detail: None,
  500. },
  501. }
  502. }
  503. }
  504. #[cfg(feature = "mint")]
  505. impl From<crate::database::Error> for Error {
  506. fn from(db_error: crate::database::Error) -> Self {
  507. match db_error {
  508. crate::database::Error::InvalidStateTransition(state) => match state {
  509. crate::state::Error::Pending => Self::TokenPending,
  510. crate::state::Error::AlreadySpent => Self::TokenAlreadySpent,
  511. state => Self::Database(crate::database::Error::InvalidStateTransition(state)),
  512. },
  513. db_error => Self::Database(db_error),
  514. }
  515. }
  516. }
  517. #[cfg(not(feature = "mint"))]
  518. impl From<crate::database::Error> for Error {
  519. fn from(db_error: crate::database::Error) -> Self {
  520. Self::Database(db_error)
  521. }
  522. }
  523. impl From<ErrorResponse> for Error {
  524. fn from(err: ErrorResponse) -> Error {
  525. match err.code {
  526. ErrorCode::TokenAlreadySpent => Self::TokenAlreadySpent,
  527. ErrorCode::QuoteNotPaid => Self::UnpaidQuote,
  528. ErrorCode::QuotePending => Self::PendingQuote,
  529. ErrorCode::QuoteExpired => Self::ExpiredQuote(0, 0),
  530. ErrorCode::KeysetNotFound => Self::UnknownKeySet,
  531. ErrorCode::KeysetInactive => Self::InactiveKeyset,
  532. ErrorCode::BlindedMessageAlreadySigned => Self::BlindedMessageAlreadySigned,
  533. ErrorCode::UnsupportedUnit => Self::UnsupportedUnit,
  534. ErrorCode::TransactionUnbalanced => Self::TransactionUnbalanced(0, 0, 0),
  535. ErrorCode::MintingDisabled => Self::MintingDisabled,
  536. ErrorCode::InvoiceAlreadyPaid => Self::RequestAlreadyPaid,
  537. ErrorCode::TokenNotVerified => Self::DHKE(crate::dhke::Error::TokenNotVerified),
  538. ErrorCode::LightningError => Self::PaymentFailed,
  539. ErrorCode::AmountOutofLimitRange => {
  540. Self::AmountOutofLimitRange(Amount::default(), Amount::default(), Amount::default())
  541. }
  542. ErrorCode::TokenPending => Self::TokenPending,
  543. ErrorCode::WitnessMissingOrInvalid => Self::SignatureMissingOrInvalid,
  544. ErrorCode::DuplicateInputs => Self::DuplicateInputs,
  545. ErrorCode::DuplicateOutputs => Self::DuplicateOutputs,
  546. ErrorCode::MultipleUnits => Self::MultipleUnits,
  547. ErrorCode::UnitMismatch => Self::UnitMismatch,
  548. ErrorCode::ClearAuthRequired => Self::ClearAuthRequired,
  549. ErrorCode::BlindAuthRequired => Self::BlindAuthRequired,
  550. _ => Self::UnknownErrorResponse(err.to_string()),
  551. }
  552. }
  553. }
  554. /// Possible Error Codes
  555. #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
  556. #[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
  557. pub enum ErrorCode {
  558. /// Token is already spent
  559. TokenAlreadySpent,
  560. /// Token Pending
  561. TokenPending,
  562. /// Quote is not paid
  563. QuoteNotPaid,
  564. /// Quote is not expired
  565. QuoteExpired,
  566. /// Quote Pending
  567. QuotePending,
  568. /// Keyset is not found
  569. KeysetNotFound,
  570. /// Keyset inactive
  571. KeysetInactive,
  572. /// Blinded Message Already signed
  573. BlindedMessageAlreadySigned,
  574. /// Unsupported unit
  575. UnsupportedUnit,
  576. /// Token already issed for quote
  577. TokensAlreadyIssued,
  578. /// Minting Disabled
  579. MintingDisabled,
  580. /// Invoice Already Paid
  581. InvoiceAlreadyPaid,
  582. /// Token Not Verified
  583. TokenNotVerified,
  584. /// Lightning Error
  585. LightningError,
  586. /// Unbalanced Error
  587. TransactionUnbalanced,
  588. /// Amount outside of allowed range
  589. AmountOutofLimitRange,
  590. /// Witness missing or invalid
  591. WitnessMissingOrInvalid,
  592. /// Duplicate Inputs
  593. DuplicateInputs,
  594. /// Duplicate Outputs
  595. DuplicateOutputs,
  596. /// Multiple Units
  597. MultipleUnits,
  598. /// Input unit does not match output
  599. UnitMismatch,
  600. /// Clear Auth Required
  601. ClearAuthRequired,
  602. /// Clear Auth Failed
  603. ClearAuthFailed,
  604. /// Blind Auth Required
  605. BlindAuthRequired,
  606. /// Blind Auth Failed
  607. BlindAuthFailed,
  608. /// Unknown error code
  609. Unknown(u16),
  610. }
  611. impl ErrorCode {
  612. /// Error code from u16
  613. pub fn from_code(code: u16) -> Self {
  614. match code {
  615. 10002 => Self::BlindedMessageAlreadySigned,
  616. 10003 => Self::TokenNotVerified,
  617. 11001 => Self::TokenAlreadySpent,
  618. 11002 => Self::TransactionUnbalanced,
  619. 11005 => Self::UnsupportedUnit,
  620. 11006 => Self::AmountOutofLimitRange,
  621. 11007 => Self::DuplicateInputs,
  622. 11008 => Self::DuplicateOutputs,
  623. 11009 => Self::MultipleUnits,
  624. 11010 => Self::UnitMismatch,
  625. 11012 => Self::TokenPending,
  626. 12001 => Self::KeysetNotFound,
  627. 12002 => Self::KeysetInactive,
  628. 20000 => Self::LightningError,
  629. 20001 => Self::QuoteNotPaid,
  630. 20002 => Self::TokensAlreadyIssued,
  631. 20003 => Self::MintingDisabled,
  632. 20005 => Self::QuotePending,
  633. 20006 => Self::InvoiceAlreadyPaid,
  634. 20007 => Self::QuoteExpired,
  635. 20008 => Self::WitnessMissingOrInvalid,
  636. 30001 => Self::ClearAuthRequired,
  637. 30002 => Self::ClearAuthFailed,
  638. 31001 => Self::BlindAuthRequired,
  639. 31002 => Self::BlindAuthFailed,
  640. _ => Self::Unknown(code),
  641. }
  642. }
  643. /// Error code to u16
  644. pub fn to_code(&self) -> u16 {
  645. match self {
  646. Self::BlindedMessageAlreadySigned => 10002,
  647. Self::TokenNotVerified => 10003,
  648. Self::TokenAlreadySpent => 11001,
  649. Self::TransactionUnbalanced => 11002,
  650. Self::UnsupportedUnit => 11005,
  651. Self::AmountOutofLimitRange => 11006,
  652. Self::DuplicateInputs => 11007,
  653. Self::DuplicateOutputs => 11008,
  654. Self::MultipleUnits => 11009,
  655. Self::UnitMismatch => 11010,
  656. Self::TokenPending => 11012,
  657. Self::KeysetNotFound => 12001,
  658. Self::KeysetInactive => 12002,
  659. Self::LightningError => 20000,
  660. Self::QuoteNotPaid => 20001,
  661. Self::TokensAlreadyIssued => 20002,
  662. Self::MintingDisabled => 20003,
  663. Self::QuotePending => 20005,
  664. Self::InvoiceAlreadyPaid => 20006,
  665. Self::QuoteExpired => 20007,
  666. Self::WitnessMissingOrInvalid => 20008,
  667. Self::ClearAuthRequired => 30001,
  668. Self::ClearAuthFailed => 30002,
  669. Self::BlindAuthRequired => 31001,
  670. Self::BlindAuthFailed => 31002,
  671. Self::Unknown(code) => *code,
  672. }
  673. }
  674. }
  675. impl Serialize for ErrorCode {
  676. fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  677. where
  678. S: Serializer,
  679. {
  680. serializer.serialize_u16(self.to_code())
  681. }
  682. }
  683. impl<'de> Deserialize<'de> for ErrorCode {
  684. fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
  685. where
  686. D: Deserializer<'de>,
  687. {
  688. let code = u16::deserialize(deserializer)?;
  689. Ok(ErrorCode::from_code(code))
  690. }
  691. }
  692. impl fmt::Display for ErrorCode {
  693. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  694. write!(f, "{}", self.to_code())
  695. }
  696. }