diff --git a/crates/cdk-axum/src/router_handlers.rs b/crates/cdk-axum/src/router_handlers.rs index 83d0d1c7..4cd2cf4d 100644 --- a/crates/cdk-axum/src/router_handlers.rs +++ b/crates/cdk-axum/src/router_handlers.rs @@ -59,13 +59,13 @@ pub async fn get_mint_bolt11_quote( .ok_or_else(|| { tracing::info!("Bolt11 mint request for unsupported unit"); - into_response(Error::UnsupportedUnit) + into_response(Error::UnitUnsupported) })?; let amount = to_unit(payload.amount, &payload.unit, &ln.get_settings().unit).map_err(|err| { tracing::error!("Backed does not support unit: {}", err); - into_response(Error::UnsupportedUnit) + into_response(Error::UnitUnsupported) })?; let quote_expiry = unix_time() + state.quote_ttl; @@ -139,7 +139,7 @@ pub async fn get_melt_bolt11_quote( .ok_or_else(|| { tracing::info!("Could not get ln backend for {}, bolt11 ", payload.unit); - into_response(Error::UnsupportedUnit) + into_response(Error::UnitUnsupported) })?; let payment_quote = ln.get_payment_quote(&payload).await.map_err(|err| { @@ -149,7 +149,7 @@ pub async fn get_melt_bolt11_quote( err ); - into_response(Error::UnsupportedUnit) + into_response(Error::UnitUnsupported) })?; let quote = state @@ -199,7 +199,7 @@ pub async fn post_melt_bolt11( if let Err(err) = state.mint.process_unpaid_melt(&payload).await { tracing::error!("Could not reset melt quote state: {}", err); } - return Err(into_response(Error::MeltRequestInvalid)); + return Err(into_response(Error::UnitUnsupported)); } }; @@ -219,7 +219,7 @@ pub async fn post_melt_bolt11( if let Err(err) = state.mint.process_unpaid_melt(&payload).await { tracing::error!("Could not reset melt quote state: {}", err); } - return Err(into_response(Error::DatabaseError)); + return Err(into_response(Error::Internal)); } }; @@ -247,7 +247,7 @@ pub async fn post_melt_bolt11( if let Err(err) = state.mint.process_unpaid_melt(&payload).await { tracing::error!("Could not reset melt quote state: {}", err); } - return Err(into_response(Error::InsufficientInputProofs)); + return Err(into_response(Error::InsufficientFunds)); } mint_quote.state = MintQuoteState::Paid; @@ -258,7 +258,7 @@ pub async fn post_melt_bolt11( if let Err(err) = state.mint.process_unpaid_melt(&payload).await { tracing::error!("Could not reset melt quote state: {}", err); } - return Err(into_response(Error::DatabaseError)); + return Err(into_response(Error::Internal)); } (None, amount) @@ -305,7 +305,7 @@ pub async fn post_melt_bolt11( Some( to_unit(partial_msats, &CurrencyUnit::Msat, "e.unit) - .map_err(|_| into_response(Error::UnsupportedUnit))?, + .map_err(|_| into_response(Error::UnitUnsupported))?, ) } false => None, @@ -314,7 +314,7 @@ pub async fn post_melt_bolt11( let amount_to_pay = match partial_amount { Some(amount_to_pay) => amount_to_pay, None => to_unit(invoice_amount_msats, &CurrencyUnit::Msat, "e.unit) - .map_err(|_| into_response(Error::UnsupportedUnit))?, + .map_err(|_| into_response(Error::UnitUnsupported))?, }; if amount_to_pay + quote.fee_reserve > inputs_amount_quote_unit { @@ -327,7 +327,11 @@ pub async fn post_melt_bolt11( if let Err(err) = state.mint.process_unpaid_melt(&payload).await { tracing::error!("Could not reset melt quote state: {}", err); } - return Err(into_response(Error::InsufficientInputProofs)); + return Err(into_response(Error::InsufficientInputs( + inputs_amount_quote_unit.into(), + amount_to_pay.into(), + quote.fee_reserve.into(), + ))); } } @@ -339,7 +343,7 @@ pub async fn post_melt_bolt11( tracing::error!("Could not reset melt quote state: {}", err); } - return Err(into_response(Error::UnsupportedUnit)); + return Err(into_response(Error::UnitUnsupported)); } }; @@ -364,7 +368,7 @@ pub async fn post_melt_bolt11( }; let amount_spent = to_unit(pre.total_spent, &ln.get_settings().unit, "e.unit) - .map_err(|_| into_response(Error::UnsupportedUnit))?; + .map_err(|_| into_response(Error::UnitUnsupported))?; (pre.payment_preimage, amount_spent) } diff --git a/crates/cdk-integration-tests/src/lib.rs b/crates/cdk-integration-tests/src/lib.rs index 265cfd08..df0ff619 100644 --- a/crates/cdk-integration-tests/src/lib.rs +++ b/crates/cdk-integration-tests/src/lib.rs @@ -79,7 +79,7 @@ pub async fn start_mint( ) .await?; - let quote_ttl = 2000; + let quote_ttl = 100000; let mint_arc = Arc::new(mint); diff --git a/crates/cdk-integration-tests/tests/mint.rs b/crates/cdk-integration-tests/tests/mint.rs index 1c0be299..a9102755 100644 --- a/crates/cdk-integration-tests/tests/mint.rs +++ b/crates/cdk-integration-tests/tests/mint.rs @@ -8,8 +8,8 @@ use bip39::Mnemonic; use cdk::amount::SplitTarget; use cdk::cdk_database::WalletMemoryDatabase; use cdk::nuts::CurrencyUnit; -use cdk::wallet::error::Error; use cdk::wallet::SendKind; +use cdk::Error; use cdk::Wallet; use cdk_integration_tests::{create_backends_fake_wallet, start_mint, wallet_mint, MINT_URL}; @@ -35,7 +35,8 @@ pub async fn test_mint_double_receive() -> Result<()> { let wallet = Arc::new(wallet); - wallet_mint(Arc::clone(&wallet), 100.into()).await?; + wallet_mint(Arc::clone(&wallet), 100.into()).await.unwrap(); + println!("Minted"); let token = wallet .send( @@ -72,6 +73,7 @@ pub async fn test_mint_double_receive() -> Result<()> { match err { Error::TokenAlreadySpent => (), _ => { + println!("{}", err); bail!("Expected an already spent error"); } } diff --git a/crates/cdk-integration-tests/tests/unbalanced.rs b/crates/cdk-integration-tests/tests/unbalanced.rs index 9ecf765b..6ab8d0e2 100644 --- a/crates/cdk-integration-tests/tests/unbalanced.rs +++ b/crates/cdk-integration-tests/tests/unbalanced.rs @@ -5,6 +5,7 @@ use std::time::Duration; use anyhow::{bail, Result}; use cdk::amount::SplitTarget; use cdk::nuts::{PreMintSecrets, SwapRequest}; +use cdk::Error; use cdk::HttpClient; use cdk_integration_tests::{create_backends_fake_wallet, mint_proofs, start_mint, MINT_URL}; @@ -40,7 +41,7 @@ pub async fn test_unbalanced_swap() -> Result<()> { // In the context of this test an error response here is good. // It means the mint does not allow us to swap for more then we should by overflowing Err(err) => match err { - cdk::wallet::error::Error::TransactionUnbalanced => { + Error::TransactionUnbalanced(_, _, _) => { return Ok(()); } _ => { diff --git a/crates/cdk-redb/src/error.rs b/crates/cdk-redb/src/error.rs index e9b46c88..556adb78 100644 --- a/crates/cdk-redb/src/error.rs +++ b/crates/cdk-redb/src/error.rs @@ -40,12 +40,15 @@ pub enum Error { /// CDK Error #[error(transparent)] CDK(#[from] cdk::error::Error), - /// NUT02 Error - #[error(transparent)] - CDKNUT02(#[from] cdk::nuts::nut02::Error), /// NUT00 Error #[error(transparent)] CDKNUT00(#[from] cdk::nuts::nut00::Error), + /// NUT02 Error + #[error(transparent)] + CDKNUT02(#[from] cdk::nuts::nut02::Error), + /// DHKE Error + #[error(transparent)] + DHKE(#[from] cdk::dhke::Error), /// Unknown Mint Info #[error("Unknown mint info")] UnknownMintInfo, diff --git a/crates/cdk-sqlite/src/wallet/error.rs b/crates/cdk-sqlite/src/wallet/error.rs index 5363fef0..bfebdf26 100644 --- a/crates/cdk-sqlite/src/wallet/error.rs +++ b/crates/cdk-sqlite/src/wallet/error.rs @@ -11,9 +11,6 @@ pub enum Error { /// Serde Error #[error(transparent)] Serde(#[from] serde_json::Error), - /// Wallet Error - #[error(transparent)] - CDKWallet(#[from] cdk::wallet::error::Error), /// NUT00 Error #[error(transparent)] CDKNUT00(#[from] cdk::nuts::nut00::Error), diff --git a/crates/cdk/src/amount.rs b/crates/cdk/src/amount.rs index cba702f8..904125d0 100644 --- a/crates/cdk/src/amount.rs +++ b/crates/cdk/src/amount.rs @@ -6,8 +6,18 @@ use std::cmp::Ordering; use std::fmt; use serde::{Deserialize, Serialize}; +use thiserror::Error; -use crate::error::Error; +/// Amount Error +#[derive(Debug, Error)] +pub enum Error { + /// Split Values must be less then or equal to amount + #[error("Split Values must be less then or equal to amount")] + SplitValuesGreater, + /// Amount overflow + #[error("Amount Overflow")] + AmountOverflow, +} /// Amount can be any unit #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] diff --git a/crates/cdk/src/cdk_database/mod.rs b/crates/cdk/src/cdk_database/mod.rs index 33e3bd00..2a55279c 100644 --- a/crates/cdk/src/cdk_database/mod.rs +++ b/crates/cdk/src/cdk_database/mod.rs @@ -43,9 +43,9 @@ pub enum Error { /// Database Error #[error(transparent)] Database(Box), - /// CDK Error + /// DHKE error #[error(transparent)] - Cdk(#[from] crate::error::Error), + DHKE(#[from] crate::dhke::Error), /// NUT00 Error #[error(transparent)] NUT00(#[from] crate::nuts::nut00::Error), diff --git a/crates/cdk/src/dhke.rs b/crates/cdk/src/dhke.rs index 5dd2a738..119ade05 100644 --- a/crates/cdk/src/dhke.rs +++ b/crates/cdk/src/dhke.rs @@ -7,8 +7,8 @@ use bitcoin::hashes::Hash; use bitcoin::secp256k1::{ Parity, PublicKey as NormalizedPublicKey, Scalar, Secp256k1, XOnlyPublicKey, }; +use thiserror::Error; -use crate::error::Error; use crate::nuts::nut01::{PublicKey, SecretKey}; use crate::nuts::nut12::ProofDleq; use crate::nuts::{BlindSignature, Keys, Proof, Proofs}; @@ -18,6 +18,24 @@ use crate::SECP256K1; const DOMAIN_SEPARATOR: &[u8; 28] = b"Secp256k1_HashToCurve_Cashu_"; +/// NUT00 Error +#[derive(Debug, Error)] +pub enum Error { + /// Token could not be validated + #[error("Token not verified")] + TokenNotVerified, + /// No valid point on curve + #[error("No valid point found")] + NoValidPoint, + /// Secp256k1 error + #[error(transparent)] + Secp256k1(#[from] bitcoin::secp256k1::Error), + // TODO: Remove use anyhow + /// Custom Error + #[error("`{0}`")] + Custom(String), +} + /// Deterministically maps a message to a public key point on the secp256k1 /// curve, utilizing a domain separator to ensure uniqueness. /// @@ -103,7 +121,7 @@ pub fn construct_proofs( keys: &Keys, ) -> Result { if (promises.len() != rs.len()) || (promises.len() != secrets.len()) { - return Err(Error::CustomError( + return Err(Error::Custom( "Lengths of promises, rs, and secrets must be equal".to_string(), )); } @@ -112,7 +130,7 @@ pub fn construct_proofs( let blinded_c: PublicKey = blinded_signature.c; let a: PublicKey = keys .amount_key(blinded_signature.amount) - .ok_or(Error::CustomError("Could not get proofs".to_string()))?; + .ok_or(Error::Custom("Could not get proofs".to_string()))?; let unblinded_signature: PublicKey = unblind_message(&blinded_c, &r, &a)?; diff --git a/crates/cdk/src/error.rs b/crates/cdk/src/error.rs index f86d392f..e284bcaf 100644 --- a/crates/cdk/src/error.rs +++ b/crates/cdk/src/error.rs @@ -1,13 +1,14 @@ //! Errors use std::fmt; -use std::string::FromUtf8Error; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_json::Value; use thiserror::Error; -use crate::util::hex; +#[cfg(feature = "wallet")] +use crate::wallet::multi_mint_wallet::WalletKey; +use crate::{util::hex, Amount}; /// CDK Error #[derive(Debug, Error)] @@ -15,57 +16,146 @@ pub enum Error { /// Mint does not have a key for amount #[error("No Key for Amount")] AmountKey, - /// Not enough input proofs provided - #[error("Not enough input proofs spent")] - InsufficientInputProofs, - /// Database update failed - #[error("Database error")] - DatabaseError, - /// Unsupported unit - #[error("Unit unsupported")] - UnsupportedUnit, /// Payment failed #[error("Payment failed")] PaymentFailed, - /// Melt Request is not valid - #[error("Melt request is not valid")] - MeltRequestInvalid, /// Invoice already paid #[error("Request already paid")] RequestAlreadyPaid, - /// Amount is not what expected - #[error("Amount miss match")] - Amount, - /// Token is already spent - #[error("Token already spent")] - TokenSpent, - /// Token could not be validated - #[error("Token not verified")] - TokenNotVerified, /// Invalid payment request #[error("Invalid payment request")] InvalidPaymentRequest, /// Bolt11 invoice does not have amount #[error("Invoice Amount undefined")] InvoiceAmountUndefined, - /// Proof is missing a required field - #[error("Proof missing required field")] - MissingProofField, - /// No valid point on curve - #[error("No valid point found")] - NoValidPoint, /// Split Values must be less then or equal to amount #[error("Split Values must be less then or equal to amount")] SplitValuesGreater, /// Amount overflow #[error("Amount Overflow")] AmountOverflow, - /// Secp256k1 error + + // Mint Errors + /// Minting is disabled + #[error("Minting is disabled")] + MintingDisabled, + /// Quote is not known + #[error("Unknown quote")] + UnknownQuote, + /// Quote is expired + #[error("Expired quote: Expired: `{0}`, Time: `{1}`")] + ExpiredQuote(u64, u64), + /// Amount is outside of allowed range + #[error("Amount but be between `{0}` and `{1}` is `{2}`")] + AmountOutofLimitRange(Amount, Amount, Amount), + /// Quote is not paiud + #[error("Quote not paid")] + UnpaidQuote, + /// Quote is pending + #[error("Quote pending")] + PendingQuote, + /// ecash already issued for quote + #[error("Quote already issued")] + IssuedQuote, + /// Quote has already been paid + #[error("Quote is already paid")] + PaidQuote, + /// Melting is disabled + #[error("Minting is disabled")] + MeltingDisabled, + /// Unknown Keyset + #[error("Unknown Keyset")] + UnknownKeySet, + /// BlindedMessage is already signed + #[error("Blinded Message is already signed")] + BlindedMessageAlreadySigned, + /// Inactive Keyset + #[error("Inactive Keyset")] + InactiveKeyset, + /// Not engough inputs provided + #[error("Inputs: `{0}`, Outputs: `{1}`, Expected Fee: `{2}`")] + InsufficientInputs(u64, u64, u64), + /// Transaction unbalanced + #[error("Inputs: `{0}`, Outputs: `{1}`, Expected Fee: `{2}`")] + TransactionUnbalanced(u64, u64, u64), + /// Duplicate proofs provided + #[error("Duplicate proofs")] + DuplicateProofs, + /// Multiple units provided + #[error("Cannot have multiple units")] + MultipleUnits, + /// Sig all cannot be used in melt + #[error("Sig all cannot be used in melt")] + SigAllUsedInMelt, + /// Token is already spent + #[error("Token Already Spent")] + TokenAlreadySpent, + /// Token is already pending + #[error("Token Pending")] + TokenPending, + /// Internal Error + #[error("Internal Error")] + Internal, + + // Wallet Errors + /// P2PK spending conditions not met + #[error("P2PK condition not met `{0}`")] + P2PKConditionsNotMet(String), + /// Spending Locktime not provided + #[error("Spending condition locktime not provided")] + LocktimeNotProvided, + /// Invalid Spending Conditions + #[error("Invalid spending conditions: `{0}`")] + InvalidSpendConditions(String), + /// Incorrect Wallet + #[error("Incorrect wallet: `{0}`")] + IncorrectWallet(String), + /// Unknown Wallet + #[cfg(feature = "wallet")] + #[error("Unknown wallet: `{0}`")] + UnknownWallet(WalletKey), + /// Max Fee Ecxeded + #[error("Max fee exceeded")] + MaxFeeExceeded, + /// Url path segments could not be joined + #[error("Url path segments could not be joined")] + UrlPathSegments, + /// Unknown error response + #[error("Unknown error response: `{0}`")] + UnknownErrorResponse(String), + /// Invalid DLEQ proof + #[error("Could not verify DLEQ proof")] + CouldNotVerifyDleq, + /// Incorrect Mint + /// Token does not match wallet mint + #[error("Token does not match wallet mint")] + IncorrectMint, + /// Receive can only be used with tokens from single mint + #[error("Multiple mint tokens not supported by receive. Please deconstruct the token and use receive with_proof")] + MultiMintTokenNotSupported, + /// Unit Not supported + #[error("Unit not supported for method")] + UnitUnsupported, + /// Preimage not provided + #[error("Preimage not provided")] + PreimageNotProvided, + /// Insufficient Funds + #[error("Insufficient funds")] + InsufficientFunds, + /// No active keyset + #[error("No active keyset")] + NoActiveKeyset, + /// Incorrect quote amount + #[error("Incorrect quote amount")] + IncorrectQuoteAmount, + /// Custom Error + #[error("`{0}`")] + Custom(String), + + // External Error conversions + /// Parse invoice error #[error(transparent)] - Secp256k1(#[from] bitcoin::secp256k1::Error), - /// Secret error - #[error(transparent)] - Secret(#[from] super::secret::Error), + Invoice(#[from] lightning_invoice::ParseOrSemanticError), /// Bip32 error #[error(transparent)] Bip32(#[from] bitcoin::bip32::Error), @@ -77,7 +167,7 @@ pub enum Error { UrlParseError(#[from] url::ParseError), /// Utf8 parse error #[error(transparent)] - Utf8ParseError(#[from] FromUtf8Error), + Utf8ParseError(#[from] std::string::FromUtf8Error), /// Serde Json error #[error(transparent)] SerdeJsonError(#[from] serde_json::Error), @@ -91,18 +181,51 @@ pub enum Error { /// From hex error #[error(transparent)] ReqwestError(#[from] reqwest::Error), + + // Crate error conversions + /// Cashu Url Error + #[error(transparent)] + CashuUrl(#[from] crate::mint_url::Error), + /// Secret error + #[error(transparent)] + Secret(#[from] crate::secret::Error), + /// Amount Error + #[error(transparent)] + AmountError(#[from] crate::amount::Error), + /// DHKE Error + #[error(transparent)] + DHKE(#[from] crate::dhke::Error), + /// NUT00 Error + #[error(transparent)] + NUT00(#[from] crate::nuts::nut00::Error), /// Nut01 error #[error(transparent)] NUT01(#[from] crate::nuts::nut01::Error), /// NUT02 error #[error(transparent)] NUT02(#[from] crate::nuts::nut02::Error), + /// NUT03 error + #[error(transparent)] + NUT03(#[from] crate::nuts::nut03::Error), + /// NUT05 error + #[error(transparent)] + NUT05(#[from] crate::nuts::nut05::Error), /// NUT11 Error #[error(transparent)] NUT11(#[from] crate::nuts::nut11::Error), - /// Custom error - #[error("`{0}`")] - CustomError(String), + /// NUT12 Error + #[error(transparent)] + NUT12(#[from] crate::nuts::nut12::Error), + /// NUT13 Error + #[error(transparent)] + NUT13(#[from] crate::nuts::nut13::Error), + /// NUT14 Error + #[error(transparent)] + NUT14(#[from] crate::nuts::nut14::Error), + /// Database Error + #[cfg(any(feature = "wallet", feature = "mint"))] + #[error(transparent)] + Database(#[from] crate::cdk_database::Error), } /// CDK Error Response @@ -163,17 +286,7 @@ impl ErrorResponse { impl From for ErrorResponse { fn from(err: Error) -> ErrorResponse { match err { - Error::TokenSpent => ErrorResponse { - code: ErrorCode::TokenAlreadySpent, - error: Some(err.to_string()), - detail: None, - }, - Error::InsufficientInputProofs => ErrorResponse { - code: ErrorCode::InsufficientFee, - error: Some(err.to_string()), - detail: None, - }, - Error::UnsupportedUnit => ErrorResponse { + Error::UnitUnsupported => ErrorResponse { code: ErrorCode::UnitUnsupported, error: Some(err.to_string()), detail: None, @@ -188,6 +301,51 @@ impl From for ErrorResponse { error: Some("Invoice already paid.".to_string()), detail: None, }, + Error::TokenAlreadySpent => ErrorResponse { + code: ErrorCode::TokenAlreadySpent, + error: Some("Token is already spent.".to_string()), + detail: None, + }, + Error::TransactionUnbalanced(inputs_total, outputs_total, fee_expected) => { + ErrorResponse { + code: ErrorCode::TransactionUnbalanced, + error: Some(format!( + "Inputs: {}, Outputs: {}, expected_fee: {}", + inputs_total, outputs_total, fee_expected, + )), + detail: Some("Transaction inputs should equal outputs less fee".to_string()), + } + } + Error::MintingDisabled => ErrorResponse { + code: ErrorCode::MintingDisabled, + error: Some(err.to_string()), + detail: None, + }, + Error::BlindedMessageAlreadySigned => ErrorResponse { + code: ErrorCode::BlindedMessageAlreadySigned, + error: Some(err.to_string()), + detail: None, + }, + Error::InsufficientFunds => ErrorResponse { + code: ErrorCode::TransactionUnbalanced, + error: Some(err.to_string()), + detail: None, + }, + Error::AmountOutofLimitRange(_min, _max, _amount) => ErrorResponse { + code: ErrorCode::AmountOutofLimitRange, + error: Some(err.to_string()), + detail: None, + }, + Error::ExpiredQuote(_, _) => ErrorResponse { + code: ErrorCode::QuoteExpired, + error: Some(err.to_string()), + detail: None, + }, + Error::PendingQuote => ErrorResponse { + code: ErrorCode::QuotePending, + error: Some(err.to_string()), + detail: None, + }, _ => ErrorResponse { code: ErrorCode::Unknown(9999), error: Some(err.to_string()), @@ -197,6 +355,30 @@ impl From for ErrorResponse { } } +impl From for Error { + fn from(err: ErrorResponse) -> Error { + match err.code { + ErrorCode::TokenAlreadySpent => Self::TokenAlreadySpent, + ErrorCode::QuoteNotPaid => Self::UnpaidQuote, + ErrorCode::QuotePending => Self::PendingQuote, + ErrorCode::QuoteExpired => Self::ExpiredQuote(0, 0), + ErrorCode::KeysetNotFound => Self::UnknownKeySet, + ErrorCode::KeysetInactive => Self::InactiveKeyset, + ErrorCode::BlindedMessageAlreadySigned => Self::BlindedMessageAlreadySigned, + ErrorCode::UnitUnsupported => Self::UnitUnsupported, + ErrorCode::TransactionUnbalanced => Self::TransactionUnbalanced(0, 0, 0), + ErrorCode::MintingDisabled => Self::MintingDisabled, + ErrorCode::InvoiceAlreadyPaid => Self::RequestAlreadyPaid, + ErrorCode::TokenNotVerified => Self::DHKE(crate::dhke::Error::TokenNotVerified), + ErrorCode::LightningError => Self::PaymentFailed, + ErrorCode::AmountOutofLimitRange => { + Self::AmountOutofLimitRange(Amount::default(), Amount::default(), Amount::default()) + } + _ => Self::UnknownErrorResponse(err.to_string()), + } + } +} + /// Possible Error Codes #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub enum ErrorCode { @@ -204,14 +386,14 @@ pub enum ErrorCode { TokenAlreadySpent, /// Quote is not paid QuoteNotPaid, + /// Quote is not expired + QuoteExpired, + /// Quote Pending + QuotePending, /// Keyset is not found KeysetNotFound, /// Keyset inactive KeysetInactive, - /// Fee Overpaid - FeeOverPaid, - /// Insufficient Fee - InsufficientFee, /// Blinded Message Already signed BlindedMessageAlreadySigned, /// Unsupported unit @@ -220,8 +402,6 @@ pub enum ErrorCode { TokensAlreadyIssued, /// Minting Disabled MintingDisabled, - /// Quote Pending - QuotePending, /// Invoice Already Paid InvoiceAlreadyPaid, /// Token Not Verified @@ -230,6 +410,8 @@ pub enum ErrorCode { LightningError, /// Unbalanced Error TransactionUnbalanced, + /// Amount outside of allowed range + AmountOutofLimitRange, /// Unknown error code Unknown(u16), } @@ -243,8 +425,7 @@ impl ErrorCode { 11001 => Self::TokenAlreadySpent, 11002 => Self::TransactionUnbalanced, 11005 => Self::UnitUnsupported, - 11006 => Self::InsufficientFee, - 11007 => Self::FeeOverPaid, + 11006 => Self::AmountOutofLimitRange, 12001 => Self::KeysetNotFound, 12002 => Self::KeysetInactive, 20000 => Self::LightningError, @@ -253,6 +434,7 @@ impl ErrorCode { 20003 => Self::MintingDisabled, 20005 => Self::QuotePending, 20006 => Self::InvoiceAlreadyPaid, + 20007 => Self::QuoteExpired, _ => Self::Unknown(code), } } @@ -265,8 +447,7 @@ impl ErrorCode { Self::TokenAlreadySpent => 11001, Self::TransactionUnbalanced => 11002, Self::UnitUnsupported => 11005, - Self::InsufficientFee => 11006, - Self::FeeOverPaid => 11007, + Self::AmountOutofLimitRange => 11006, Self::KeysetNotFound => 12001, Self::KeysetInactive => 12002, Self::LightningError => 20000, @@ -275,6 +456,7 @@ impl ErrorCode { Self::MintingDisabled => 20003, Self::QuotePending => 20005, Self::InvoiceAlreadyPaid => 20006, + Self::QuoteExpired => 20007, Self::Unknown(code) => *code, } } diff --git a/crates/cdk/src/lib.rs b/crates/cdk/src/lib.rs index df74ead8..257e1bc2 100644 --- a/crates/cdk/src/lib.rs +++ b/crates/cdk/src/lib.rs @@ -23,6 +23,8 @@ pub mod wallet; #[doc(hidden)] pub use bitcoin::secp256k1; #[doc(hidden)] +pub use error::Error; +#[doc(hidden)] pub use lightning_invoice::{self, Bolt11Invoice}; #[cfg(feature = "mint")] #[doc(hidden)] diff --git a/crates/cdk/src/mint/error.rs b/crates/cdk/src/mint/error.rs deleted file mode 100644 index 5cf9bdc0..00000000 --- a/crates/cdk/src/mint/error.rs +++ /dev/null @@ -1,208 +0,0 @@ -//! Mint Errors - -use thiserror::Error; - -use crate::error::{ErrorCode, ErrorResponse}; -use crate::{cdk_database, mint_url}; - -/// CDK Mint Error -#[derive(Debug, Error)] -pub enum Error { - /// Unknown Keyset - #[error("Unknown Keyset")] - UnknownKeySet, - /// Inactive Keyset - #[error("Inactive Keyset")] - InactiveKeyset, - /// There is not key for amount given - #[error("No key for amount")] - AmountKey, - /// Amount is not what is expected - #[error("Amount")] - Amount, - /// Amount overflow - #[error("Amount Overflow")] - AmountOverflow, - /// Not engough inputs provided - #[error("Inputs: `{0}`, Outputs: `{1}`, Expected Fee: `{2}`")] - InsufficientInputs(u64, u64, u64), - /// Transaction unbalanced - #[error("Inputs: `{0}`, Outputs: `{1}`, Expected Fee: `{2}`")] - TransactionUnbalanced(u64, u64, u64), - /// Duplicate proofs provided - #[error("Duplicate proofs")] - DuplicateProofs, - /// Token is already spent - #[error("Token Already Spent")] - TokenAlreadySpent, - /// Token is already pending - #[error("Token Pending")] - TokenPending, - /// Quote is not paiud - #[error("Quote not paid")] - UnpaidQuote, - /// Quote has already been paid - #[error("Quote is already paid")] - PaidQuote, - /// Quote is not known - #[error("Unknown quote")] - UnknownQuote, - /// Quote is pending - #[error("Quote pending")] - PendingQuote, - /// ecash already issued for quote - #[error("Quote already issued")] - IssuedQuote, - /// Unknown secret kind - #[error("Unknown secret kind")] - UnknownSecretKind, - /// Multiple units provided - #[error("Cannot have multiple units")] - MultipleUnits, - /// Unit not supported - #[error("Unit not supported")] - UnsupportedUnit, - /// BlindMessage is already signed - #[error("Blinded Message is already signed")] - BlindedMessageAlreadySigned, - /// Sig all cannot be used in melt - #[error("Sig all cannot be used in melt")] - SigAllUsedInMelt, - /// Minting is disabled - #[error("Minting is disabled")] - MintingDisabled, - /// Minting request is over mint limit - #[error("Mint request is over mint limit")] - MintOverLimit, - /// Mint request is uver mint limit - #[error("Mint request is under mint limit")] - MintUnderLimit, - /// Melting is disabled - #[error("Minting is disabled")] - MeltingDisabled, - /// Melting request is over mint limit - #[error("Mint request is over mint limit")] - MeltOverLimit, - /// Melt request is uver mint limit - #[error("Mint request is under mint limit")] - MeltUnderLimit, - /// Cashu Error - #[error(transparent)] - Cashu(#[from] crate::error::Error), - /// Secret Error - #[error(transparent)] - Secret(#[from] crate::secret::Error), - /// NUT00 Error - #[error(transparent)] - NUT00(#[from] crate::nuts::nut00::Error), - /// NUT04 Error - #[error(transparent)] - NUT04(#[from] crate::nuts::nut04::Error), - /// NUT05 Error - #[error(transparent)] - NUT05(#[from] crate::nuts::nut05::Error), - /// NUT11 Error - #[error(transparent)] - NUT11(#[from] crate::nuts::nut11::Error), - /// NUT12 Error - #[error(transparent)] - Nut12(#[from] crate::nuts::nut12::Error), - /// NUT14 Error - #[error(transparent)] - Nut14(#[from] crate::nuts::nut14::Error), - /// Database Error - #[error(transparent)] - Database(#[from] cdk_database::Error), - /// Mint Url Error - #[error(transparent)] - MintUrl(#[from] mint_url::Error), - /// Custom Error - #[error("`{0}`")] - Custom(String), -} - -impl From for cdk_database::Error { - fn from(e: Error) -> Self { - Self::Database(Box::new(e)) - } -} - -impl From for ErrorResponse { - fn from(err: Error) -> ErrorResponse { - match err { - Error::TokenAlreadySpent => ErrorResponse { - code: ErrorCode::TokenAlreadySpent, - error: Some(err.to_string()), - detail: None, - }, - Error::TransactionUnbalanced(_inputs_amount, _output_amouns, _expected_fee) => { - ErrorResponse { - code: ErrorCode::TransactionUnbalanced, - error: Some(err.to_string()), - detail: None, - } - } - Error::InsufficientInputs(_inputs_amount, _output_amount, _expected_fee) => { - ErrorResponse { - code: ErrorCode::InsufficientFee, - error: Some(err.to_string()), - detail: None, - } - } - Error::MintingDisabled => ErrorResponse { - code: ErrorCode::MintingDisabled, - error: Some(err.to_string()), - detail: None, - }, - Error::InactiveKeyset => ErrorResponse { - code: ErrorCode::KeysetInactive, - error: Some(err.to_string()), - detail: None, - }, - Error::UnknownKeySet => ErrorResponse { - code: ErrorCode::KeysetNotFound, - error: Some(err.to_string()), - detail: None, - }, - Error::UnpaidQuote => ErrorResponse { - code: ErrorCode::QuoteNotPaid, - error: Some(err.to_string()), - detail: None, - }, - Error::PendingQuote => ErrorResponse { - code: ErrorCode::QuotePending, - error: Some(err.to_string()), - detail: None, - }, - Error::IssuedQuote => ErrorResponse { - code: ErrorCode::TokensAlreadyIssued, - error: Some(err.to_string()), - detail: None, - }, - _ => ErrorResponse { - code: ErrorCode::Unknown(9999), - error: Some(err.to_string()), - detail: None, - }, - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - #[test] - fn test_error_response_enum() { - let error = Error::TokenAlreadySpent; - - let response: ErrorResponse = error.into(); - - let json = serde_json::to_string(&response).unwrap(); - - let error_response: ErrorResponse = serde_json::from_str(&json).unwrap(); - - assert_eq!(response.code, error_response.code); - } -} diff --git a/crates/cdk/src/mint/mod.rs b/crates/cdk/src/mint/mod.rs index 0e599f71..e49f865a 100644 --- a/crates/cdk/src/mint/mod.rs +++ b/crates/cdk/src/mint/mod.rs @@ -6,7 +6,6 @@ use std::sync::Arc; use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey}; use bitcoin::secp256k1::{self, Secp256k1}; -use error::Error; use serde::{Deserialize, Serialize}; use tokio::sync::RwLock; use tracing::instrument; @@ -15,13 +14,13 @@ use self::nut05::QuoteState; use self::nut11::EnforceSigFlag; use crate::cdk_database::{self, MintDatabase}; use crate::dhke::{hash_to_curve, sign_message, verify_message}; +use crate::error::Error; use crate::mint_url::MintUrl; use crate::nuts::nut11::enforce_sig_flag; use crate::nuts::*; use crate::util::unix_time; use crate::Amount; -pub mod error; pub mod types; pub use types::{MeltQuote, MintQuote}; @@ -212,18 +211,26 @@ impl Mint { .max_amount .map_or(false, |max_amount| amount > max_amount) { - return Err(Error::MintOverLimit); + return Err(Error::AmountOutofLimitRange( + settings.min_amount.unwrap_or_default(), + settings.max_amount.unwrap_or_default(), + amount, + )); } if settings .min_amount .map_or(false, |min_amount| amount < min_amount) { - return Err(Error::MintUnderLimit); + return Err(Error::AmountOutofLimitRange( + settings.min_amount.unwrap_or_default(), + settings.max_amount.unwrap_or_default(), + amount, + )); } } None => { - return Err(Error::UnsupportedUnit); + return Err(Error::UnitUnsupported); } } @@ -359,18 +366,26 @@ impl Mint { .max_amount .map_or(false, |max_amount| amount > max_amount) { - return Err(Error::MeltOverLimit); + return Err(Error::AmountOutofLimitRange( + settings.min_amount.unwrap_or_default(), + settings.max_amount.unwrap_or_default(), + amount, + )); } if settings .min_amount .map_or(false, |min_amount| amount < min_amount) { - return Err(Error::MeltUnderLimit); + return Err(Error::AmountOutofLimitRange( + settings.min_amount.unwrap_or_default(), + settings.max_amount.unwrap_or_default(), + amount, + )); } } None => { - return Err(Error::UnsupportedUnit); + return Err(Error::UnitUnsupported); } } @@ -555,6 +570,18 @@ impl Mint { &self, mint_request: nut04::MintBolt11Request, ) -> Result { + // Check quote is known and not expired + match self.localstore.get_mint_quote(&mint_request.quote).await? { + Some(quote) => { + if quote.expiry < unix_time() { + return Err(Error::ExpiredQuote(quote.expiry, unix_time())); + } + } + None => { + return Err(Error::UnknownQuote); + } + } + let state = self .localstore .update_mint_quote_state(&mint_request.quote, MintQuoteState::Pending) diff --git a/crates/cdk/src/nuts/nut00/mod.rs b/crates/cdk/src/nuts/nut00/mod.rs index 08405073..c4eef312 100644 --- a/crates/cdk/src/nuts/nut00/mod.rs +++ b/crates/cdk/src/nuts/nut00/mod.rs @@ -59,9 +59,18 @@ pub enum Error { /// Ciborium error #[error(transparent)] CiboriumError(#[from] ciborium::de::Error), - /// CDK error + /// Amount Error #[error(transparent)] - Cdk(#[from] crate::error::Error), + Amount(#[from] crate::amount::Error), + /// Secret error + #[error(transparent)] + Secret(#[from] crate::secret::Error), + /// DHKE error + #[error(transparent)] + DHKE(#[from] crate::dhke::Error), + /// NUT10 error + #[error(transparent)] + NUT10(#[from] crate::nuts::nut10::Error), /// NUT11 error #[error(transparent)] NUT11(#[from] crate::nuts::nut11::Error), diff --git a/crates/cdk/src/nuts/nut03.rs b/crates/cdk/src/nuts/nut03.rs index 6e2b5f65..eca008ba 100644 --- a/crates/cdk/src/nuts/nut03.rs +++ b/crates/cdk/src/nuts/nut03.rs @@ -3,9 +3,21 @@ //! use serde::{Deserialize, Serialize}; +use thiserror::Error; use super::nut00::{BlindSignature, BlindedMessage, PreMintSecrets, Proofs}; -use crate::{error::Error, Amount}; +use crate::Amount; + +/// NUT03 Error +#[derive(Debug, Error)] +pub enum Error { + /// DHKE error + #[error(transparent)] + DHKE(#[from] crate::dhke::Error), + /// Amount Error + #[error(transparent)] + Amount(#[from] crate::amount::Error), +} /// Preswap information #[derive(Debug, Clone, PartialEq, Eq, Serialize)] @@ -37,12 +49,16 @@ impl SwapRequest { /// Total value of proofs in [`SwapRequest`] pub fn input_amount(&self) -> Result { - Amount::try_sum(self.inputs.iter().map(|proof| proof.amount)) + Ok(Amount::try_sum( + self.inputs.iter().map(|proof| proof.amount), + )?) } /// Total value of outputs in [`SwapRequest`] pub fn output_amount(&self) -> Result { - Amount::try_sum(self.outputs.iter().map(|proof| proof.amount)) + Ok(Amount::try_sum( + self.outputs.iter().map(|proof| proof.amount), + )?) } } @@ -63,10 +79,10 @@ impl SwapResponse { /// Total [`Amount`] of promises pub fn promises_amount(&self) -> Result { - Amount::try_sum( + Ok(Amount::try_sum( self.signatures .iter() .map(|BlindSignature { amount, .. }| *amount), - ) + )?) } } diff --git a/crates/cdk/src/nuts/nut10.rs b/crates/cdk/src/nuts/nut10.rs index 33b9866e..541095c2 100644 --- a/crates/cdk/src/nuts/nut10.rs +++ b/crates/cdk/src/nuts/nut10.rs @@ -6,8 +6,18 @@ use std::str::FromStr; use serde::ser::SerializeTuple; use serde::{Deserialize, Serialize, Serializer}; +use thiserror::Error; -use crate::error::Error; +/// NUT13 Error +#[derive(Debug, Error)] +pub enum Error { + /// Secret error + #[error(transparent)] + Secret(#[from] crate::secret::Error), + /// Serde Json error + #[error(transparent)] + SerdeJsonError(#[from] serde_json::Error), +} /// NUT10 Secret Kind #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/crates/cdk/src/nuts/nut12.rs b/crates/cdk/src/nuts/nut12.rs index 0393cd80..f3928a6e 100644 --- a/crates/cdk/src/nuts/nut12.rs +++ b/crates/cdk/src/nuts/nut12.rs @@ -26,9 +26,9 @@ pub enum Error { /// Invalid DLEQ Proof #[error("Invalid DLEQ proof")] InvalidDleqProof, - /// Cashu Error + /// DHKE error #[error(transparent)] - Cashu(#[from] crate::error::Error), + DHKE(#[from] crate::dhke::Error), /// NUT01 Error #[error(transparent)] NUT01(#[from] crate::nuts::nut01::Error), diff --git a/crates/cdk/src/nuts/nut13.rs b/crates/cdk/src/nuts/nut13.rs index 5ad3ac83..2408ea17 100644 --- a/crates/cdk/src/nuts/nut13.rs +++ b/crates/cdk/src/nuts/nut13.rs @@ -3,6 +3,7 @@ //! use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey}; +use thiserror::Error; use tracing::instrument; use super::nut00::{BlindedMessage, PreMint, PreMintSecrets}; @@ -10,11 +11,30 @@ use super::nut01::SecretKey; use super::nut02::Id; use crate::amount::SplitTarget; use crate::dhke::blind_message; -use crate::error::Error; use crate::secret::Secret; use crate::util::hex; use crate::{Amount, SECP256K1}; +/// NUT13 Error +#[derive(Debug, Error)] +pub enum Error { + /// DHKE error + #[error(transparent)] + DHKE(#[from] crate::dhke::Error), + /// Amount Error + #[error(transparent)] + Amount(#[from] crate::amount::Error), + /// NUT00 Error + #[error(transparent)] + NUT00(#[from] crate::nuts::nut00::Error), + /// NUT02 Error + #[error(transparent)] + NUT02(#[from] crate::nuts::nut02::Error), + /// Bip32 Error + #[error(transparent)] + Bip32(#[from] bitcoin::bip32::Error), +} + impl Secret { /// Create new [`Secret`] from xpriv pub fn from_xpriv(xpriv: ExtendedPrivKey, keyset_id: Id, counter: u32) -> Result { diff --git a/crates/cdk/src/secret.rs b/crates/cdk/src/secret.rs index 423be092..ef388393 100644 --- a/crates/cdk/src/secret.rs +++ b/crates/cdk/src/secret.rs @@ -23,6 +23,9 @@ pub enum Error { /// Hex Error #[error(transparent)] Hex(#[from] hex::Error), + /// Serde Json error + #[error(transparent)] + SerdeJsonError(#[from] serde_json::Error), } impl Default for Secret { @@ -119,10 +122,10 @@ impl TryFrom for crate::nuts::nut10::Secret { } impl TryFrom<&Secret> for crate::nuts::nut10::Secret { - type Error = serde_json::Error; + type Error = Error; fn try_from(unchecked_secret: &Secret) -> Result { - serde_json::from_str(&unchecked_secret.0) + Ok(serde_json::from_str(&unchecked_secret.0)?) } } diff --git a/crates/cdk/src/types.rs b/crates/cdk/src/types.rs index 01e9cae4..2003ec72 100644 --- a/crates/cdk/src/types.rs +++ b/crates/cdk/src/types.rs @@ -44,9 +44,7 @@ impl ProofInfo { state: State, unit: CurrencyUnit, ) -> Result { - let y = proof - .y() - .map_err(|_| Error::CustomError("Could not find y".to_string()))?; + let y = proof.y()?; let spending_condition: Option = (&proof.secret).try_into().ok(); diff --git a/crates/cdk/src/wallet/error.rs b/crates/cdk/src/wallet/error.rs deleted file mode 100644 index 941d3a7c..00000000 --- a/crates/cdk/src/wallet/error.rs +++ /dev/null @@ -1,148 +0,0 @@ -//! CDK Wallet Error - -use std::num::ParseIntError; - -use thiserror::Error; - -use super::multi_mint_wallet::WalletKey; -use crate::cdk_database; -use crate::error::{ErrorCode, ErrorResponse}; -use crate::util::hex; - -/// Wallet Error -#[derive(Debug, Error)] -pub enum Error { - /// Insufficient Funds - #[error("Insufficient funds")] - InsufficientFunds, - /// Quote Expired - #[error("Quote expired")] - QuoteExpired, - /// Unknown Quote - #[error("Quote unknown")] - QuoteUnknown, - /// Not active keyset - #[error("No active keyset")] - NoActiveKeyset, - /// Invalid DLEQ proof - #[error("Could not verify DLEQ proof")] - CouldNotVerifyDleq, - /// P2PK spending conditions not met - #[error("P2PK condition not met `{0}`")] - P2PKConditionsNotMet(String), - /// Invalid Spending Conditions - #[error("Invalid spending conditions: `{0}`")] - InvalidSpendConditions(String), - /// Preimage not provided - #[error("Preimage not provided")] - PreimageNotProvided, - /// Unknown Key - #[error("Unknown key")] - UnknownKey, - /// Amount overflow - #[error("Amount Overflow")] - AmountOverflow, - /// Spending Locktime not provided - #[error("Spending condition locktime not provided")] - LocktimeNotProvided, - /// Url path segments could not be joined - #[error("Url path segments could not be joined")] - UrlPathSegments, - /// Quote not paid - #[error("Quote not paid")] - QuoteNotePaid, - /// Token Already Spent - #[error("Token already spent")] - TokenAlreadySpent, - /// Unit Not supported - #[error("Unit not supported for method")] - UnitNotSupported, - /// Bolt11 invoice does not have amount - #[error("Invoice amount undefined")] - InvoiceAmountUndefined, - /// Incorrect quote amount - #[error("Incorrect quote amount")] - IncorrectQuoteAmount, - /// Keyset Not Found - #[error("Keyset not found")] - KeysetNotFound, - /// Receive can only be used with tokens from single mint - #[error("Multiple mint tokens not supported by receive. Please deconstruct the token and use receive with_proof")] - MultiMintTokenNotSupported, - /// Incorrect Mint - /// Token does not match wallet mint - #[error("Token does not match wallet mint")] - IncorrectMint, - /// From hex error - #[error(transparent)] - ReqwestError(#[from] reqwest::Error), - /// Unknown error response - #[error("Unknown error response: `{0}`")] - UnknownErrorResponse(String), - /// Hex Error - #[error(transparent)] - HexError(#[from] hex::Error), - /// Unknown Wallet - #[error("Unknown wallet: `{0}`")] - UnknownWallet(WalletKey), - /// Incorrect Wallet - #[error("Incorrect wallet: `{0}`")] - IncorrectWallet(String), - /// Max Fee Ecxeded - #[error("Max fee exceeded")] - MaxFeeExceeded, - /// Transaction unbalanced - #[error("Transaction is unbalanced")] - TransactionUnbalanced, - /// CDK Error - #[error(transparent)] - Cashu(#[from] crate::error::Error), - /// Cashu Url Error - #[error(transparent)] - CashuUrl(#[from] crate::mint_url::Error), - /// Database Error - #[error(transparent)] - Database(#[from] crate::cdk_database::Error), - /// NUT00 Error - #[error(transparent)] - NUT00(#[from] crate::nuts::nut00::Error), - /// NUT01 Error - #[error(transparent)] - NUT01(#[from] crate::nuts::nut01::Error), - /// NUT11 Error - #[error(transparent)] - NUT11(#[from] crate::nuts::nut11::Error), - /// NUT12 Error - #[error(transparent)] - NUT12(#[from] crate::nuts::nut12::Error), - /// Parse int - #[error(transparent)] - ParseInt(#[from] ParseIntError), - /// Parse invoice error - #[error(transparent)] - Invoice(#[from] lightning_invoice::ParseOrSemanticError), - /// Serde Error - #[error(transparent)] - Serde(#[from] serde_json::Error), - /// Custom Error - #[error("`{0}`")] - Custom(String), -} - -impl From for cdk_database::Error { - fn from(e: Error) -> Self { - Self::Database(Box::new(e)) - } -} - -impl From for Error { - fn from(err: ErrorResponse) -> Error { - match err.code { - ErrorCode::QuoteNotPaid => Self::QuoteNotePaid, - ErrorCode::TokenAlreadySpent => Self::TokenAlreadySpent, - ErrorCode::KeysetNotFound => Self::KeysetNotFound, - ErrorCode::TransactionUnbalanced => Self::TransactionUnbalanced, - _ => Self::UnknownErrorResponse(err.to_string()), - } - } -} diff --git a/crates/cdk/src/wallet/mod.rs b/crates/cdk/src/wallet/mod.rs index b898bbe1..98e7128c 100644 --- a/crates/cdk/src/wallet/mod.rs +++ b/crates/cdk/src/wallet/mod.rs @@ -9,12 +9,12 @@ use bitcoin::hashes::sha256::Hash as Sha256Hash; use bitcoin::hashes::Hash; use bitcoin::key::XOnlyPublicKey; use bitcoin::Network; -use error::Error; use tracing::instrument; use crate::amount::SplitTarget; use crate::cdk_database::{self, WalletDatabase}; use crate::dhke::{construct_proofs, hash_to_curve}; +use crate::error::Error; use crate::mint_url::MintUrl; use crate::nuts::nut00::token::Token; use crate::nuts::{ @@ -28,7 +28,6 @@ use crate::util::{hex, unix_time}; use crate::{Amount, Bolt11Invoice, HttpClient, SECP256K1}; pub mod client; -pub mod error; pub mod multi_mint_wallet; pub mod types; pub mod util; @@ -108,7 +107,7 @@ impl Wallet { .localstore .get_keyset_by_id(&proof.keyset_id) .await? - .ok_or(Error::UnknownKey)?; + .ok_or(Error::UnknownKeySet)?; sum_fee += input_fee_ppk.input_fee_ppk; } @@ -125,7 +124,7 @@ impl Wallet { .localstore .get_keyset_by_id(keyset_id) .await? - .ok_or(Error::UnknownKey)? + .ok_or(Error::UnknownKeySet)? .input_fee_ppk; let fee = (input_fee_ppk * count + 999) / 1000; @@ -615,12 +614,12 @@ impl Wallet { let quote_info = if let Some(quote) = quote_info { if quote.expiry.le(&unix_time()) && quote.expiry.ne(&0) { - return Err(Error::QuoteExpired); + return Err(Error::ExpiredQuote(quote.expiry, unix_time())); } quote.clone() } else { - return Err(Error::QuoteUnknown); + return Err(Error::UnknownQuote); }; let active_keyset_id = self.get_active_mint_keyset().await?.id; @@ -663,7 +662,7 @@ impl Wallet { { for (sig, premint) in mint_res.signatures.iter().zip(&premint_secrets.secrets) { let keys = self.get_keyset_keys(sig.keyset_id).await?; - let key = keys.amount_key(sig.amount).ok_or(Error::UnknownKey)?; + let key = keys.amount_key(sig.amount).ok_or(Error::AmountKey)?; match sig.verify_dleq(key, premint.blinded_message.blinded_secret) { Ok(_) | Err(nut12::Error::MissingDleqProof) => (), Err(_) => return Err(Error::CouldNotVerifyDleq), @@ -1292,7 +1291,7 @@ impl Wallet { let amount = match self.unit { CurrencyUnit::Sat => Amount::from(request_amount / 1000), CurrencyUnit::Msat => Amount::from(request_amount), - _ => return Err(Error::UnitNotSupported), + _ => return Err(Error::UnitUnsupported), }; let quote_res = self @@ -1352,12 +1351,12 @@ impl Wallet { let quote_info = self.localstore.get_melt_quote(quote_id).await?; let quote_info = if let Some(quote) = quote_info { if quote.expiry.le(&unix_time()) { - return Err(Error::QuoteExpired); + return Err(Error::ExpiredQuote(quote.expiry, unix_time())); } quote.clone() } else { - return Err(Error::QuoteUnknown); + return Err(Error::UnknownQuote); }; let ys = proofs @@ -1503,12 +1502,12 @@ impl Wallet { let quote_info = if let Some(quote) = quote_info { if quote.expiry.le(&unix_time()) { - return Err(Error::QuoteExpired); + return Err(Error::ExpiredQuote(quote.expiry, unix_time())); } quote.clone() } else { - return Err(Error::QuoteUnknown); + return Err(Error::UnknownQuote); }; let inputs_needed_amount = quote_info.amount + quote_info.fee_reserve; @@ -1684,7 +1683,7 @@ impl Wallet { // Verify that proof DLEQ is valid if proof.dleq.is_some() { let keys = self.get_keyset_keys(proof.keyset_id).await?; - let key = keys.amount_key(proof.amount).ok_or(Error::UnknownKey)?; + let key = keys.amount_key(proof.amount).ok_or(Error::AmountKey)?; proof.verify_dleq(key)?; } @@ -1815,7 +1814,7 @@ impl Wallet { let unit = token_data.unit().unwrap_or_default(); if unit != self.unit { - return Err(Error::UnitNotSupported); + return Err(Error::UnitUnsupported); } let proofs = token_data.proofs(); @@ -2108,7 +2107,7 @@ impl Wallet { key } } - .ok_or(Error::UnknownKey)?; + .ok_or(Error::AmountKey)?; proof .verify_dleq(mint_pubkey) diff --git a/justfile b/justfile index 9e954fc2..a5718e6f 100644 --- a/justfile +++ b/justfile @@ -7,7 +7,7 @@ alias t := test default: @just --list -final-check: format clippy test +final-check: typos format clippy test # run `cargo build` on everything build *ARGS="--workspace --all-targets": @@ -54,6 +54,9 @@ clippy *ARGS="--locked --offline --workspace --all-targets": clippy-fix *ARGS="--locked --offline --workspace --all-targets": cargo clippy {{ARGS}} --fix +typos: + typos + # fix all typos [no-exit-message] typos-fix: