mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-19 13:44:55 +01:00
feat: remove mint and wallet errors
This commit is contained in:
@@ -59,13 +59,13 @@ pub async fn get_mint_bolt11_quote(
|
|||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
tracing::info!("Bolt11 mint request for unsupported unit");
|
tracing::info!("Bolt11 mint request for unsupported unit");
|
||||||
|
|
||||||
into_response(Error::UnsupportedUnit)
|
into_response(Error::UnitUnsupported)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let amount =
|
let amount =
|
||||||
to_unit(payload.amount, &payload.unit, &ln.get_settings().unit).map_err(|err| {
|
to_unit(payload.amount, &payload.unit, &ln.get_settings().unit).map_err(|err| {
|
||||||
tracing::error!("Backed does not support unit: {}", 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;
|
let quote_expiry = unix_time() + state.quote_ttl;
|
||||||
@@ -139,7 +139,7 @@ pub async fn get_melt_bolt11_quote(
|
|||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
tracing::info!("Could not get ln backend for {}, bolt11 ", payload.unit);
|
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| {
|
let payment_quote = ln.get_payment_quote(&payload).await.map_err(|err| {
|
||||||
@@ -149,7 +149,7 @@ pub async fn get_melt_bolt11_quote(
|
|||||||
err
|
err
|
||||||
);
|
);
|
||||||
|
|
||||||
into_response(Error::UnsupportedUnit)
|
into_response(Error::UnitUnsupported)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let quote = state
|
let quote = state
|
||||||
@@ -199,7 +199,7 @@ pub async fn post_melt_bolt11(
|
|||||||
if let Err(err) = state.mint.process_unpaid_melt(&payload).await {
|
if let Err(err) = state.mint.process_unpaid_melt(&payload).await {
|
||||||
tracing::error!("Could not reset melt quote state: {}", err);
|
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 {
|
if let Err(err) = state.mint.process_unpaid_melt(&payload).await {
|
||||||
tracing::error!("Could not reset melt quote state: {}", err);
|
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 {
|
if let Err(err) = state.mint.process_unpaid_melt(&payload).await {
|
||||||
tracing::error!("Could not reset melt quote state: {}", err);
|
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;
|
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 {
|
if let Err(err) = state.mint.process_unpaid_melt(&payload).await {
|
||||||
tracing::error!("Could not reset melt quote state: {}", err);
|
tracing::error!("Could not reset melt quote state: {}", err);
|
||||||
}
|
}
|
||||||
return Err(into_response(Error::DatabaseError));
|
return Err(into_response(Error::Internal));
|
||||||
}
|
}
|
||||||
|
|
||||||
(None, amount)
|
(None, amount)
|
||||||
@@ -305,7 +305,7 @@ pub async fn post_melt_bolt11(
|
|||||||
|
|
||||||
Some(
|
Some(
|
||||||
to_unit(partial_msats, &CurrencyUnit::Msat, "e.unit)
|
to_unit(partial_msats, &CurrencyUnit::Msat, "e.unit)
|
||||||
.map_err(|_| into_response(Error::UnsupportedUnit))?,
|
.map_err(|_| into_response(Error::UnitUnsupported))?,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
false => None,
|
false => None,
|
||||||
@@ -314,7 +314,7 @@ pub async fn post_melt_bolt11(
|
|||||||
let amount_to_pay = match partial_amount {
|
let amount_to_pay = match partial_amount {
|
||||||
Some(amount_to_pay) => amount_to_pay,
|
Some(amount_to_pay) => amount_to_pay,
|
||||||
None => to_unit(invoice_amount_msats, &CurrencyUnit::Msat, "e.unit)
|
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 {
|
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 {
|
if let Err(err) = state.mint.process_unpaid_melt(&payload).await {
|
||||||
tracing::error!("Could not reset melt quote state: {}", err);
|
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);
|
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)
|
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)
|
(pre.payment_preimage, amount_spent)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ pub async fn start_mint(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let quote_ttl = 2000;
|
let quote_ttl = 100000;
|
||||||
|
|
||||||
let mint_arc = Arc::new(mint);
|
let mint_arc = Arc::new(mint);
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ use bip39::Mnemonic;
|
|||||||
use cdk::amount::SplitTarget;
|
use cdk::amount::SplitTarget;
|
||||||
use cdk::cdk_database::WalletMemoryDatabase;
|
use cdk::cdk_database::WalletMemoryDatabase;
|
||||||
use cdk::nuts::CurrencyUnit;
|
use cdk::nuts::CurrencyUnit;
|
||||||
use cdk::wallet::error::Error;
|
|
||||||
use cdk::wallet::SendKind;
|
use cdk::wallet::SendKind;
|
||||||
|
use cdk::Error;
|
||||||
use cdk::Wallet;
|
use cdk::Wallet;
|
||||||
use cdk_integration_tests::{create_backends_fake_wallet, start_mint, wallet_mint, MINT_URL};
|
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);
|
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
|
let token = wallet
|
||||||
.send(
|
.send(
|
||||||
@@ -72,6 +73,7 @@ pub async fn test_mint_double_receive() -> Result<()> {
|
|||||||
match err {
|
match err {
|
||||||
Error::TokenAlreadySpent => (),
|
Error::TokenAlreadySpent => (),
|
||||||
_ => {
|
_ => {
|
||||||
|
println!("{}", err);
|
||||||
bail!("Expected an already spent error");
|
bail!("Expected an already spent error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use std::time::Duration;
|
|||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use cdk::amount::SplitTarget;
|
use cdk::amount::SplitTarget;
|
||||||
use cdk::nuts::{PreMintSecrets, SwapRequest};
|
use cdk::nuts::{PreMintSecrets, SwapRequest};
|
||||||
|
use cdk::Error;
|
||||||
use cdk::HttpClient;
|
use cdk::HttpClient;
|
||||||
use cdk_integration_tests::{create_backends_fake_wallet, mint_proofs, start_mint, MINT_URL};
|
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.
|
// 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
|
// It means the mint does not allow us to swap for more then we should by overflowing
|
||||||
Err(err) => match err {
|
Err(err) => match err {
|
||||||
cdk::wallet::error::Error::TransactionUnbalanced => {
|
Error::TransactionUnbalanced(_, _, _) => {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
@@ -40,12 +40,15 @@ pub enum Error {
|
|||||||
/// CDK Error
|
/// CDK Error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
CDK(#[from] cdk::error::Error),
|
CDK(#[from] cdk::error::Error),
|
||||||
/// NUT02 Error
|
|
||||||
#[error(transparent)]
|
|
||||||
CDKNUT02(#[from] cdk::nuts::nut02::Error),
|
|
||||||
/// NUT00 Error
|
/// NUT00 Error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
CDKNUT00(#[from] cdk::nuts::nut00::Error),
|
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
|
/// Unknown Mint Info
|
||||||
#[error("Unknown mint info")]
|
#[error("Unknown mint info")]
|
||||||
UnknownMintInfo,
|
UnknownMintInfo,
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ pub enum Error {
|
|||||||
/// Serde Error
|
/// Serde Error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Serde(#[from] serde_json::Error),
|
Serde(#[from] serde_json::Error),
|
||||||
/// Wallet Error
|
|
||||||
#[error(transparent)]
|
|
||||||
CDKWallet(#[from] cdk::wallet::error::Error),
|
|
||||||
/// NUT00 Error
|
/// NUT00 Error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
CDKNUT00(#[from] cdk::nuts::nut00::Error),
|
CDKNUT00(#[from] cdk::nuts::nut00::Error),
|
||||||
|
|||||||
@@ -6,8 +6,18 @@ use std::cmp::Ordering;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
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
|
/// Amount can be any unit
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ pub enum Error {
|
|||||||
/// Database Error
|
/// Database Error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Database(Box<dyn std::error::Error + Send + Sync>),
|
Database(Box<dyn std::error::Error + Send + Sync>),
|
||||||
/// CDK Error
|
/// DHKE error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Cdk(#[from] crate::error::Error),
|
DHKE(#[from] crate::dhke::Error),
|
||||||
/// NUT00 Error
|
/// NUT00 Error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
NUT00(#[from] crate::nuts::nut00::Error),
|
NUT00(#[from] crate::nuts::nut00::Error),
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ use bitcoin::hashes::Hash;
|
|||||||
use bitcoin::secp256k1::{
|
use bitcoin::secp256k1::{
|
||||||
Parity, PublicKey as NormalizedPublicKey, Scalar, Secp256k1, XOnlyPublicKey,
|
Parity, PublicKey as NormalizedPublicKey, Scalar, Secp256k1, XOnlyPublicKey,
|
||||||
};
|
};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::error::Error;
|
|
||||||
use crate::nuts::nut01::{PublicKey, SecretKey};
|
use crate::nuts::nut01::{PublicKey, SecretKey};
|
||||||
use crate::nuts::nut12::ProofDleq;
|
use crate::nuts::nut12::ProofDleq;
|
||||||
use crate::nuts::{BlindSignature, Keys, Proof, Proofs};
|
use crate::nuts::{BlindSignature, Keys, Proof, Proofs};
|
||||||
@@ -18,6 +18,24 @@ use crate::SECP256K1;
|
|||||||
|
|
||||||
const DOMAIN_SEPARATOR: &[u8; 28] = b"Secp256k1_HashToCurve_Cashu_";
|
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
|
/// Deterministically maps a message to a public key point on the secp256k1
|
||||||
/// curve, utilizing a domain separator to ensure uniqueness.
|
/// curve, utilizing a domain separator to ensure uniqueness.
|
||||||
///
|
///
|
||||||
@@ -103,7 +121,7 @@ pub fn construct_proofs(
|
|||||||
keys: &Keys,
|
keys: &Keys,
|
||||||
) -> Result<Proofs, Error> {
|
) -> Result<Proofs, Error> {
|
||||||
if (promises.len() != rs.len()) || (promises.len() != secrets.len()) {
|
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(),
|
"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 blinded_c: PublicKey = blinded_signature.c;
|
||||||
let a: PublicKey = keys
|
let a: PublicKey = keys
|
||||||
.amount_key(blinded_signature.amount)
|
.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)?;
|
let unblinded_signature: PublicKey = unblind_message(&blinded_c, &r, &a)?;
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
//! Errors
|
//! Errors
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::string::FromUtf8Error;
|
|
||||||
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::util::hex;
|
#[cfg(feature = "wallet")]
|
||||||
|
use crate::wallet::multi_mint_wallet::WalletKey;
|
||||||
|
use crate::{util::hex, Amount};
|
||||||
|
|
||||||
/// CDK Error
|
/// CDK Error
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
@@ -15,57 +16,146 @@ pub enum Error {
|
|||||||
/// Mint does not have a key for amount
|
/// Mint does not have a key for amount
|
||||||
#[error("No Key for Amount")]
|
#[error("No Key for Amount")]
|
||||||
AmountKey,
|
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
|
/// Payment failed
|
||||||
#[error("Payment failed")]
|
#[error("Payment failed")]
|
||||||
PaymentFailed,
|
PaymentFailed,
|
||||||
/// Melt Request is not valid
|
|
||||||
#[error("Melt request is not valid")]
|
|
||||||
MeltRequestInvalid,
|
|
||||||
/// Invoice already paid
|
/// Invoice already paid
|
||||||
#[error("Request already paid")]
|
#[error("Request already paid")]
|
||||||
RequestAlreadyPaid,
|
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
|
/// Invalid payment request
|
||||||
#[error("Invalid payment request")]
|
#[error("Invalid payment request")]
|
||||||
InvalidPaymentRequest,
|
InvalidPaymentRequest,
|
||||||
/// Bolt11 invoice does not have amount
|
/// Bolt11 invoice does not have amount
|
||||||
#[error("Invoice Amount undefined")]
|
#[error("Invoice Amount undefined")]
|
||||||
InvoiceAmountUndefined,
|
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
|
/// Split Values must be less then or equal to amount
|
||||||
#[error("Split Values must be less then or equal to amount")]
|
#[error("Split Values must be less then or equal to amount")]
|
||||||
SplitValuesGreater,
|
SplitValuesGreater,
|
||||||
/// Amount overflow
|
/// Amount overflow
|
||||||
#[error("Amount Overflow")]
|
#[error("Amount Overflow")]
|
||||||
AmountOverflow,
|
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)]
|
#[error(transparent)]
|
||||||
Secp256k1(#[from] bitcoin::secp256k1::Error),
|
Invoice(#[from] lightning_invoice::ParseOrSemanticError),
|
||||||
/// Secret error
|
|
||||||
#[error(transparent)]
|
|
||||||
Secret(#[from] super::secret::Error),
|
|
||||||
/// Bip32 error
|
/// Bip32 error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Bip32(#[from] bitcoin::bip32::Error),
|
Bip32(#[from] bitcoin::bip32::Error),
|
||||||
@@ -77,7 +167,7 @@ pub enum Error {
|
|||||||
UrlParseError(#[from] url::ParseError),
|
UrlParseError(#[from] url::ParseError),
|
||||||
/// Utf8 parse error
|
/// Utf8 parse error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Utf8ParseError(#[from] FromUtf8Error),
|
Utf8ParseError(#[from] std::string::FromUtf8Error),
|
||||||
/// Serde Json error
|
/// Serde Json error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
SerdeJsonError(#[from] serde_json::Error),
|
SerdeJsonError(#[from] serde_json::Error),
|
||||||
@@ -91,18 +181,51 @@ pub enum Error {
|
|||||||
/// From hex error
|
/// From hex error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ReqwestError(#[from] reqwest::Error),
|
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
|
/// Nut01 error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
NUT01(#[from] crate::nuts::nut01::Error),
|
NUT01(#[from] crate::nuts::nut01::Error),
|
||||||
/// NUT02 error
|
/// NUT02 error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
NUT02(#[from] crate::nuts::nut02::Error),
|
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
|
/// NUT11 Error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
NUT11(#[from] crate::nuts::nut11::Error),
|
NUT11(#[from] crate::nuts::nut11::Error),
|
||||||
/// Custom error
|
/// NUT12 Error
|
||||||
#[error("`{0}`")]
|
#[error(transparent)]
|
||||||
CustomError(String),
|
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
|
/// CDK Error Response
|
||||||
@@ -163,17 +286,7 @@ impl ErrorResponse {
|
|||||||
impl From<Error> for ErrorResponse {
|
impl From<Error> for ErrorResponse {
|
||||||
fn from(err: Error) -> ErrorResponse {
|
fn from(err: Error) -> ErrorResponse {
|
||||||
match err {
|
match err {
|
||||||
Error::TokenSpent => ErrorResponse {
|
Error::UnitUnsupported => 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 {
|
|
||||||
code: ErrorCode::UnitUnsupported,
|
code: ErrorCode::UnitUnsupported,
|
||||||
error: Some(err.to_string()),
|
error: Some(err.to_string()),
|
||||||
detail: None,
|
detail: None,
|
||||||
@@ -188,6 +301,51 @@ impl From<Error> for ErrorResponse {
|
|||||||
error: Some("Invoice already paid.".to_string()),
|
error: Some("Invoice already paid.".to_string()),
|
||||||
detail: None,
|
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 {
|
_ => ErrorResponse {
|
||||||
code: ErrorCode::Unknown(9999),
|
code: ErrorCode::Unknown(9999),
|
||||||
error: Some(err.to_string()),
|
error: Some(err.to_string()),
|
||||||
@@ -197,6 +355,30 @@ impl From<Error> for ErrorResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ErrorResponse> 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
|
/// Possible Error Codes
|
||||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub enum ErrorCode {
|
pub enum ErrorCode {
|
||||||
@@ -204,14 +386,14 @@ pub enum ErrorCode {
|
|||||||
TokenAlreadySpent,
|
TokenAlreadySpent,
|
||||||
/// Quote is not paid
|
/// Quote is not paid
|
||||||
QuoteNotPaid,
|
QuoteNotPaid,
|
||||||
|
/// Quote is not expired
|
||||||
|
QuoteExpired,
|
||||||
|
/// Quote Pending
|
||||||
|
QuotePending,
|
||||||
/// Keyset is not found
|
/// Keyset is not found
|
||||||
KeysetNotFound,
|
KeysetNotFound,
|
||||||
/// Keyset inactive
|
/// Keyset inactive
|
||||||
KeysetInactive,
|
KeysetInactive,
|
||||||
/// Fee Overpaid
|
|
||||||
FeeOverPaid,
|
|
||||||
/// Insufficient Fee
|
|
||||||
InsufficientFee,
|
|
||||||
/// Blinded Message Already signed
|
/// Blinded Message Already signed
|
||||||
BlindedMessageAlreadySigned,
|
BlindedMessageAlreadySigned,
|
||||||
/// Unsupported unit
|
/// Unsupported unit
|
||||||
@@ -220,8 +402,6 @@ pub enum ErrorCode {
|
|||||||
TokensAlreadyIssued,
|
TokensAlreadyIssued,
|
||||||
/// Minting Disabled
|
/// Minting Disabled
|
||||||
MintingDisabled,
|
MintingDisabled,
|
||||||
/// Quote Pending
|
|
||||||
QuotePending,
|
|
||||||
/// Invoice Already Paid
|
/// Invoice Already Paid
|
||||||
InvoiceAlreadyPaid,
|
InvoiceAlreadyPaid,
|
||||||
/// Token Not Verified
|
/// Token Not Verified
|
||||||
@@ -230,6 +410,8 @@ pub enum ErrorCode {
|
|||||||
LightningError,
|
LightningError,
|
||||||
/// Unbalanced Error
|
/// Unbalanced Error
|
||||||
TransactionUnbalanced,
|
TransactionUnbalanced,
|
||||||
|
/// Amount outside of allowed range
|
||||||
|
AmountOutofLimitRange,
|
||||||
/// Unknown error code
|
/// Unknown error code
|
||||||
Unknown(u16),
|
Unknown(u16),
|
||||||
}
|
}
|
||||||
@@ -243,8 +425,7 @@ impl ErrorCode {
|
|||||||
11001 => Self::TokenAlreadySpent,
|
11001 => Self::TokenAlreadySpent,
|
||||||
11002 => Self::TransactionUnbalanced,
|
11002 => Self::TransactionUnbalanced,
|
||||||
11005 => Self::UnitUnsupported,
|
11005 => Self::UnitUnsupported,
|
||||||
11006 => Self::InsufficientFee,
|
11006 => Self::AmountOutofLimitRange,
|
||||||
11007 => Self::FeeOverPaid,
|
|
||||||
12001 => Self::KeysetNotFound,
|
12001 => Self::KeysetNotFound,
|
||||||
12002 => Self::KeysetInactive,
|
12002 => Self::KeysetInactive,
|
||||||
20000 => Self::LightningError,
|
20000 => Self::LightningError,
|
||||||
@@ -253,6 +434,7 @@ impl ErrorCode {
|
|||||||
20003 => Self::MintingDisabled,
|
20003 => Self::MintingDisabled,
|
||||||
20005 => Self::QuotePending,
|
20005 => Self::QuotePending,
|
||||||
20006 => Self::InvoiceAlreadyPaid,
|
20006 => Self::InvoiceAlreadyPaid,
|
||||||
|
20007 => Self::QuoteExpired,
|
||||||
_ => Self::Unknown(code),
|
_ => Self::Unknown(code),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,8 +447,7 @@ impl ErrorCode {
|
|||||||
Self::TokenAlreadySpent => 11001,
|
Self::TokenAlreadySpent => 11001,
|
||||||
Self::TransactionUnbalanced => 11002,
|
Self::TransactionUnbalanced => 11002,
|
||||||
Self::UnitUnsupported => 11005,
|
Self::UnitUnsupported => 11005,
|
||||||
Self::InsufficientFee => 11006,
|
Self::AmountOutofLimitRange => 11006,
|
||||||
Self::FeeOverPaid => 11007,
|
|
||||||
Self::KeysetNotFound => 12001,
|
Self::KeysetNotFound => 12001,
|
||||||
Self::KeysetInactive => 12002,
|
Self::KeysetInactive => 12002,
|
||||||
Self::LightningError => 20000,
|
Self::LightningError => 20000,
|
||||||
@@ -275,6 +456,7 @@ impl ErrorCode {
|
|||||||
Self::MintingDisabled => 20003,
|
Self::MintingDisabled => 20003,
|
||||||
Self::QuotePending => 20005,
|
Self::QuotePending => 20005,
|
||||||
Self::InvoiceAlreadyPaid => 20006,
|
Self::InvoiceAlreadyPaid => 20006,
|
||||||
|
Self::QuoteExpired => 20007,
|
||||||
Self::Unknown(code) => *code,
|
Self::Unknown(code) => *code,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ pub mod wallet;
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use bitcoin::secp256k1;
|
pub use bitcoin::secp256k1;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
pub use error::Error;
|
||||||
|
#[doc(hidden)]
|
||||||
pub use lightning_invoice::{self, Bolt11Invoice};
|
pub use lightning_invoice::{self, Bolt11Invoice};
|
||||||
#[cfg(feature = "mint")]
|
#[cfg(feature = "mint")]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|||||||
@@ -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<Error> for cdk_database::Error {
|
|
||||||
fn from(e: Error) -> Self {
|
|
||||||
Self::Database(Box::new(e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Error> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,6 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey};
|
use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey};
|
||||||
use bitcoin::secp256k1::{self, Secp256k1};
|
use bitcoin::secp256k1::{self, Secp256k1};
|
||||||
use error::Error;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
@@ -15,13 +14,13 @@ use self::nut05::QuoteState;
|
|||||||
use self::nut11::EnforceSigFlag;
|
use self::nut11::EnforceSigFlag;
|
||||||
use crate::cdk_database::{self, MintDatabase};
|
use crate::cdk_database::{self, MintDatabase};
|
||||||
use crate::dhke::{hash_to_curve, sign_message, verify_message};
|
use crate::dhke::{hash_to_curve, sign_message, verify_message};
|
||||||
|
use crate::error::Error;
|
||||||
use crate::mint_url::MintUrl;
|
use crate::mint_url::MintUrl;
|
||||||
use crate::nuts::nut11::enforce_sig_flag;
|
use crate::nuts::nut11::enforce_sig_flag;
|
||||||
use crate::nuts::*;
|
use crate::nuts::*;
|
||||||
use crate::util::unix_time;
|
use crate::util::unix_time;
|
||||||
use crate::Amount;
|
use crate::Amount;
|
||||||
|
|
||||||
pub mod error;
|
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
pub use types::{MeltQuote, MintQuote};
|
pub use types::{MeltQuote, MintQuote};
|
||||||
@@ -212,18 +211,26 @@ impl Mint {
|
|||||||
.max_amount
|
.max_amount
|
||||||
.map_or(false, |max_amount| amount > 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
|
if settings
|
||||||
.min_amount
|
.min_amount
|
||||||
.map_or(false, |min_amount| amount < 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 => {
|
None => {
|
||||||
return Err(Error::UnsupportedUnit);
|
return Err(Error::UnitUnsupported);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,18 +366,26 @@ impl Mint {
|
|||||||
.max_amount
|
.max_amount
|
||||||
.map_or(false, |max_amount| amount > 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
|
if settings
|
||||||
.min_amount
|
.min_amount
|
||||||
.map_or(false, |min_amount| amount < 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 => {
|
None => {
|
||||||
return Err(Error::UnsupportedUnit);
|
return Err(Error::UnitUnsupported);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,6 +570,18 @@ impl Mint {
|
|||||||
&self,
|
&self,
|
||||||
mint_request: nut04::MintBolt11Request,
|
mint_request: nut04::MintBolt11Request,
|
||||||
) -> Result<nut04::MintBolt11Response, Error> {
|
) -> Result<nut04::MintBolt11Response, Error> {
|
||||||
|
// 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
|
let state = self
|
||||||
.localstore
|
.localstore
|
||||||
.update_mint_quote_state(&mint_request.quote, MintQuoteState::Pending)
|
.update_mint_quote_state(&mint_request.quote, MintQuoteState::Pending)
|
||||||
|
|||||||
@@ -59,9 +59,18 @@ pub enum Error {
|
|||||||
/// Ciborium error
|
/// Ciborium error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
CiboriumError(#[from] ciborium::de::Error<std::io::Error>),
|
CiboriumError(#[from] ciborium::de::Error<std::io::Error>),
|
||||||
/// CDK error
|
/// Amount Error
|
||||||
#[error(transparent)]
|
#[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
|
/// NUT11 error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
NUT11(#[from] crate::nuts::nut11::Error),
|
NUT11(#[from] crate::nuts::nut11::Error),
|
||||||
|
|||||||
@@ -3,9 +3,21 @@
|
|||||||
//! <https://github.com/cashubtc/nuts/blob/main/03.md>
|
//! <https://github.com/cashubtc/nuts/blob/main/03.md>
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use super::nut00::{BlindSignature, BlindedMessage, PreMintSecrets, Proofs};
|
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
|
/// Preswap information
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||||
@@ -37,12 +49,16 @@ impl SwapRequest {
|
|||||||
|
|
||||||
/// Total value of proofs in [`SwapRequest`]
|
/// Total value of proofs in [`SwapRequest`]
|
||||||
pub fn input_amount(&self) -> Result<Amount, Error> {
|
pub fn input_amount(&self) -> Result<Amount, Error> {
|
||||||
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`]
|
/// Total value of outputs in [`SwapRequest`]
|
||||||
pub fn output_amount(&self) -> Result<Amount, Error> {
|
pub fn output_amount(&self) -> Result<Amount, Error> {
|
||||||
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
|
/// Total [`Amount`] of promises
|
||||||
pub fn promises_amount(&self) -> Result<Amount, Error> {
|
pub fn promises_amount(&self) -> Result<Amount, Error> {
|
||||||
Amount::try_sum(
|
Ok(Amount::try_sum(
|
||||||
self.signatures
|
self.signatures
|
||||||
.iter()
|
.iter()
|
||||||
.map(|BlindSignature { amount, .. }| *amount),
|
.map(|BlindSignature { amount, .. }| *amount),
|
||||||
)
|
)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,18 @@ use std::str::FromStr;
|
|||||||
|
|
||||||
use serde::ser::SerializeTuple;
|
use serde::ser::SerializeTuple;
|
||||||
use serde::{Deserialize, Serialize, Serializer};
|
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
|
/// NUT10 Secret Kind
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ pub enum Error {
|
|||||||
/// Invalid DLEQ Proof
|
/// Invalid DLEQ Proof
|
||||||
#[error("Invalid DLEQ proof")]
|
#[error("Invalid DLEQ proof")]
|
||||||
InvalidDleqProof,
|
InvalidDleqProof,
|
||||||
/// Cashu Error
|
/// DHKE error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Cashu(#[from] crate::error::Error),
|
DHKE(#[from] crate::dhke::Error),
|
||||||
/// NUT01 Error
|
/// NUT01 Error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
NUT01(#[from] crate::nuts::nut01::Error),
|
NUT01(#[from] crate::nuts::nut01::Error),
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
//! <https://github.com/cashubtc/nuts/blob/main/13.md>
|
//! <https://github.com/cashubtc/nuts/blob/main/13.md>
|
||||||
|
|
||||||
use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey};
|
use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey};
|
||||||
|
use thiserror::Error;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use super::nut00::{BlindedMessage, PreMint, PreMintSecrets};
|
use super::nut00::{BlindedMessage, PreMint, PreMintSecrets};
|
||||||
@@ -10,11 +11,30 @@ use super::nut01::SecretKey;
|
|||||||
use super::nut02::Id;
|
use super::nut02::Id;
|
||||||
use crate::amount::SplitTarget;
|
use crate::amount::SplitTarget;
|
||||||
use crate::dhke::blind_message;
|
use crate::dhke::blind_message;
|
||||||
use crate::error::Error;
|
|
||||||
use crate::secret::Secret;
|
use crate::secret::Secret;
|
||||||
use crate::util::hex;
|
use crate::util::hex;
|
||||||
use crate::{Amount, SECP256K1};
|
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 {
|
impl Secret {
|
||||||
/// Create new [`Secret`] from xpriv
|
/// Create new [`Secret`] from xpriv
|
||||||
pub fn from_xpriv(xpriv: ExtendedPrivKey, keyset_id: Id, counter: u32) -> Result<Self, Error> {
|
pub fn from_xpriv(xpriv: ExtendedPrivKey, keyset_id: Id, counter: u32) -> Result<Self, Error> {
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ pub enum Error {
|
|||||||
/// Hex Error
|
/// Hex Error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Hex(#[from] hex::Error),
|
Hex(#[from] hex::Error),
|
||||||
|
/// Serde Json error
|
||||||
|
#[error(transparent)]
|
||||||
|
SerdeJsonError(#[from] serde_json::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Secret {
|
impl Default for Secret {
|
||||||
@@ -119,10 +122,10 @@ impl TryFrom<Secret> for crate::nuts::nut10::Secret {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&Secret> 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<crate::nuts::nut10::Secret, Self::Error> {
|
fn try_from(unchecked_secret: &Secret) -> Result<crate::nuts::nut10::Secret, Self::Error> {
|
||||||
serde_json::from_str(&unchecked_secret.0)
|
Ok(serde_json::from_str(&unchecked_secret.0)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,9 +44,7 @@ impl ProofInfo {
|
|||||||
state: State,
|
state: State,
|
||||||
unit: CurrencyUnit,
|
unit: CurrencyUnit,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let y = proof
|
let y = proof.y()?;
|
||||||
.y()
|
|
||||||
.map_err(|_| Error::CustomError("Could not find y".to_string()))?;
|
|
||||||
|
|
||||||
let spending_condition: Option<SpendingConditions> = (&proof.secret).try_into().ok();
|
let spending_condition: Option<SpendingConditions> = (&proof.secret).try_into().ok();
|
||||||
|
|
||||||
|
|||||||
@@ -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<Error> for cdk_database::Error {
|
|
||||||
fn from(e: Error) -> Self {
|
|
||||||
Self::Database(Box::new(e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ErrorResponse> 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()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,12 +9,12 @@ use bitcoin::hashes::sha256::Hash as Sha256Hash;
|
|||||||
use bitcoin::hashes::Hash;
|
use bitcoin::hashes::Hash;
|
||||||
use bitcoin::key::XOnlyPublicKey;
|
use bitcoin::key::XOnlyPublicKey;
|
||||||
use bitcoin::Network;
|
use bitcoin::Network;
|
||||||
use error::Error;
|
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use crate::amount::SplitTarget;
|
use crate::amount::SplitTarget;
|
||||||
use crate::cdk_database::{self, WalletDatabase};
|
use crate::cdk_database::{self, WalletDatabase};
|
||||||
use crate::dhke::{construct_proofs, hash_to_curve};
|
use crate::dhke::{construct_proofs, hash_to_curve};
|
||||||
|
use crate::error::Error;
|
||||||
use crate::mint_url::MintUrl;
|
use crate::mint_url::MintUrl;
|
||||||
use crate::nuts::nut00::token::Token;
|
use crate::nuts::nut00::token::Token;
|
||||||
use crate::nuts::{
|
use crate::nuts::{
|
||||||
@@ -28,7 +28,6 @@ use crate::util::{hex, unix_time};
|
|||||||
use crate::{Amount, Bolt11Invoice, HttpClient, SECP256K1};
|
use crate::{Amount, Bolt11Invoice, HttpClient, SECP256K1};
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod error;
|
|
||||||
pub mod multi_mint_wallet;
|
pub mod multi_mint_wallet;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
@@ -108,7 +107,7 @@ impl Wallet {
|
|||||||
.localstore
|
.localstore
|
||||||
.get_keyset_by_id(&proof.keyset_id)
|
.get_keyset_by_id(&proof.keyset_id)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(Error::UnknownKey)?;
|
.ok_or(Error::UnknownKeySet)?;
|
||||||
|
|
||||||
sum_fee += input_fee_ppk.input_fee_ppk;
|
sum_fee += input_fee_ppk.input_fee_ppk;
|
||||||
}
|
}
|
||||||
@@ -125,7 +124,7 @@ impl Wallet {
|
|||||||
.localstore
|
.localstore
|
||||||
.get_keyset_by_id(keyset_id)
|
.get_keyset_by_id(keyset_id)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(Error::UnknownKey)?
|
.ok_or(Error::UnknownKeySet)?
|
||||||
.input_fee_ppk;
|
.input_fee_ppk;
|
||||||
|
|
||||||
let fee = (input_fee_ppk * count + 999) / 1000;
|
let fee = (input_fee_ppk * count + 999) / 1000;
|
||||||
@@ -615,12 +614,12 @@ impl Wallet {
|
|||||||
|
|
||||||
let quote_info = if let Some(quote) = quote_info {
|
let quote_info = if let Some(quote) = quote_info {
|
||||||
if quote.expiry.le(&unix_time()) && quote.expiry.ne(&0) {
|
if quote.expiry.le(&unix_time()) && quote.expiry.ne(&0) {
|
||||||
return Err(Error::QuoteExpired);
|
return Err(Error::ExpiredQuote(quote.expiry, unix_time()));
|
||||||
}
|
}
|
||||||
|
|
||||||
quote.clone()
|
quote.clone()
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::QuoteUnknown);
|
return Err(Error::UnknownQuote);
|
||||||
};
|
};
|
||||||
|
|
||||||
let active_keyset_id = self.get_active_mint_keyset().await?.id;
|
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) {
|
for (sig, premint) in mint_res.signatures.iter().zip(&premint_secrets.secrets) {
|
||||||
let keys = self.get_keyset_keys(sig.keyset_id).await?;
|
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) {
|
match sig.verify_dleq(key, premint.blinded_message.blinded_secret) {
|
||||||
Ok(_) | Err(nut12::Error::MissingDleqProof) => (),
|
Ok(_) | Err(nut12::Error::MissingDleqProof) => (),
|
||||||
Err(_) => return Err(Error::CouldNotVerifyDleq),
|
Err(_) => return Err(Error::CouldNotVerifyDleq),
|
||||||
@@ -1292,7 +1291,7 @@ impl Wallet {
|
|||||||
let amount = match self.unit {
|
let amount = match self.unit {
|
||||||
CurrencyUnit::Sat => Amount::from(request_amount / 1000),
|
CurrencyUnit::Sat => Amount::from(request_amount / 1000),
|
||||||
CurrencyUnit::Msat => Amount::from(request_amount),
|
CurrencyUnit::Msat => Amount::from(request_amount),
|
||||||
_ => return Err(Error::UnitNotSupported),
|
_ => return Err(Error::UnitUnsupported),
|
||||||
};
|
};
|
||||||
|
|
||||||
let quote_res = self
|
let quote_res = self
|
||||||
@@ -1352,12 +1351,12 @@ impl Wallet {
|
|||||||
let quote_info = self.localstore.get_melt_quote(quote_id).await?;
|
let quote_info = self.localstore.get_melt_quote(quote_id).await?;
|
||||||
let quote_info = if let Some(quote) = quote_info {
|
let quote_info = if let Some(quote) = quote_info {
|
||||||
if quote.expiry.le(&unix_time()) {
|
if quote.expiry.le(&unix_time()) {
|
||||||
return Err(Error::QuoteExpired);
|
return Err(Error::ExpiredQuote(quote.expiry, unix_time()));
|
||||||
}
|
}
|
||||||
|
|
||||||
quote.clone()
|
quote.clone()
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::QuoteUnknown);
|
return Err(Error::UnknownQuote);
|
||||||
};
|
};
|
||||||
|
|
||||||
let ys = proofs
|
let ys = proofs
|
||||||
@@ -1503,12 +1502,12 @@ impl Wallet {
|
|||||||
|
|
||||||
let quote_info = if let Some(quote) = quote_info {
|
let quote_info = if let Some(quote) = quote_info {
|
||||||
if quote.expiry.le(&unix_time()) {
|
if quote.expiry.le(&unix_time()) {
|
||||||
return Err(Error::QuoteExpired);
|
return Err(Error::ExpiredQuote(quote.expiry, unix_time()));
|
||||||
}
|
}
|
||||||
|
|
||||||
quote.clone()
|
quote.clone()
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::QuoteUnknown);
|
return Err(Error::UnknownQuote);
|
||||||
};
|
};
|
||||||
|
|
||||||
let inputs_needed_amount = quote_info.amount + quote_info.fee_reserve;
|
let inputs_needed_amount = quote_info.amount + quote_info.fee_reserve;
|
||||||
@@ -1684,7 +1683,7 @@ impl Wallet {
|
|||||||
// Verify that proof DLEQ is valid
|
// Verify that proof DLEQ is valid
|
||||||
if proof.dleq.is_some() {
|
if proof.dleq.is_some() {
|
||||||
let keys = self.get_keyset_keys(proof.keyset_id).await?;
|
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)?;
|
proof.verify_dleq(key)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1815,7 +1814,7 @@ impl Wallet {
|
|||||||
let unit = token_data.unit().unwrap_or_default();
|
let unit = token_data.unit().unwrap_or_default();
|
||||||
|
|
||||||
if unit != self.unit {
|
if unit != self.unit {
|
||||||
return Err(Error::UnitNotSupported);
|
return Err(Error::UnitUnsupported);
|
||||||
}
|
}
|
||||||
|
|
||||||
let proofs = token_data.proofs();
|
let proofs = token_data.proofs();
|
||||||
@@ -2108,7 +2107,7 @@ impl Wallet {
|
|||||||
key
|
key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ok_or(Error::UnknownKey)?;
|
.ok_or(Error::AmountKey)?;
|
||||||
|
|
||||||
proof
|
proof
|
||||||
.verify_dleq(mint_pubkey)
|
.verify_dleq(mint_pubkey)
|
||||||
|
|||||||
5
justfile
5
justfile
@@ -7,7 +7,7 @@ alias t := test
|
|||||||
default:
|
default:
|
||||||
@just --list
|
@just --list
|
||||||
|
|
||||||
final-check: format clippy test
|
final-check: typos format clippy test
|
||||||
|
|
||||||
# run `cargo build` on everything
|
# run `cargo build` on everything
|
||||||
build *ARGS="--workspace --all-targets":
|
build *ARGS="--workspace --all-targets":
|
||||||
@@ -54,6 +54,9 @@ clippy *ARGS="--locked --offline --workspace --all-targets":
|
|||||||
clippy-fix *ARGS="--locked --offline --workspace --all-targets":
|
clippy-fix *ARGS="--locked --offline --workspace --all-targets":
|
||||||
cargo clippy {{ARGS}} --fix
|
cargo clippy {{ARGS}} --fix
|
||||||
|
|
||||||
|
typos:
|
||||||
|
typos
|
||||||
|
|
||||||
# fix all typos
|
# fix all typos
|
||||||
[no-exit-message]
|
[no-exit-message]
|
||||||
typos-fix:
|
typos-fix:
|
||||||
|
|||||||
Reference in New Issue
Block a user