Skip to content

Commit

Permalink
Merge pull request #629 from ok300/ok300-ensure-cdk
Browse files Browse the repository at this point in the history
Add `ensure_cdk` macro for validation checks
  • Loading branch information
thesimplekid authored Mar 6, 2025
2 parents c620033 + 8137943 commit a394145
Show file tree
Hide file tree
Showing 19 changed files with 121 additions and 178 deletions.
10 changes: 10 additions & 0 deletions crates/cashu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,13 @@ pub use lightning_invoice::{self, Bolt11Invoice};
pub use self::amount::Amount;
pub use self::nuts::*;
pub use self::util::SECP256K1;

#[doc(hidden)]
#[macro_export]
macro_rules! ensure_cdk {
($cond:expr, $err:expr) => {
if !$cond {
return Err($err);
}
};
}
7 changes: 4 additions & 3 deletions crates/cashu/src/mint_url.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use serde::{Deserialize, Serialize};
use thiserror::Error;
use url::{ParseError, Url};

use crate::ensure_cdk;

/// Url Error
#[derive(Debug, Error, PartialEq, Eq)]
pub enum Error {
Expand All @@ -27,9 +29,8 @@ pub struct MintUrl(String);

impl MintUrl {
fn format_url(url: &str) -> Result<String, Error> {
if url.is_empty() {
return Err(Error::InvalidUrl);
}
ensure_cdk!(!url.is_empty(), Error::InvalidUrl);

let url = url.trim_end_matches('/');
// https://URL.com/path/TO/resource -> https://url.com/path/TO/resource
let protocol = url
Expand Down
34 changes: 10 additions & 24 deletions crates/cashu/src/nuts/nut00/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use super::{Error, Proof, ProofV4, Proofs};
use crate::mint_url::MintUrl;
use crate::nuts::nut00::ProofsMethods;
use crate::nuts::{CurrencyUnit, Id};
use crate::Amount;
use crate::{ensure_cdk, Amount};

/// Token Enum
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
Expand Down Expand Up @@ -103,11 +103,9 @@ impl Token {
Self::TokenV3(token) => {
let mint_urls = token.mint_urls();

if mint_urls.len() != 1 {
return Err(Error::UnsupportedToken);
}
ensure_cdk!(mint_urls.len() == 1, Error::UnsupportedToken);

Ok(mint_urls.first().expect("Length is checked above").clone())
mint_urls.first().ok_or(Error::UnsupportedToken).cloned()
}
Self::TokenV4(token) => Ok(token.mint_url.clone()),
}
Expand Down Expand Up @@ -164,9 +162,7 @@ impl TryFrom<&Vec<u8>> for Token {
type Error = Error;

fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
if bytes.len() < 5 {
return Err(Error::UnsupportedToken);
}
ensure_cdk!(bytes.len() >= 5, Error::UnsupportedToken);

let prefix = String::from_utf8(bytes[..5].to_vec())?;

Expand Down Expand Up @@ -220,9 +216,7 @@ impl TokenV3 {
memo: Option<String>,
unit: Option<CurrencyUnit>,
) -> Result<Self, Error> {
if proofs.is_empty() {
return Err(Error::ProofsRequired);
}
ensure_cdk!(!proofs.is_empty(), Error::ProofsRequired);

Ok(Self {
token: vec![TokenV3Token::new(mint_url, proofs)],
Expand Down Expand Up @@ -400,18 +394,12 @@ impl TryFrom<&Vec<u8>> for TokenV4 {
type Error = Error;

fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
if bytes.len() < 5 {
return Err(Error::UnsupportedToken);
}
ensure_cdk!(bytes.len() >= 5, Error::UnsupportedToken);

let prefix = String::from_utf8(bytes[..5].to_vec())?;
ensure_cdk!(prefix.as_str() == "crawB", Error::UnsupportedToken);

if prefix.as_str() == "crawB" {
let token: TokenV4 = ciborium::from_reader(&bytes[5..])?;
Ok(token)
} else {
Err(Error::UnsupportedToken)
}
Ok(ciborium::from_reader(&bytes[5..])?)
}
}

Expand All @@ -421,11 +409,9 @@ impl TryFrom<TokenV3> for TokenV4 {
let proofs = token.proofs();
let mint_urls = token.mint_urls();

if mint_urls.len() != 1 {
return Err(Error::UnsupportedToken);
}
ensure_cdk!(mint_urls.len() == 1, Error::UnsupportedToken);

let mint_url = mint_urls.first().expect("Len is checked");
let mint_url = mint_urls.first().ok_or(Error::UnsupportedToken)?;

let proofs = proofs
.iter()
Expand Down
10 changes: 3 additions & 7 deletions crates/cashu/src/nuts/nut02.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use super::nut01::Keys;
use super::nut01::{MintKeyPair, MintKeys};
use crate::nuts::nut00::CurrencyUnit;
use crate::util::hex;
use crate::Amount;
use crate::{ensure_cdk, Amount};

/// NUT02 Error
#[derive(Debug, Error)]
Expand Down Expand Up @@ -144,9 +144,7 @@ impl TryFrom<String> for Id {
type Error = Error;

fn try_from(s: String) -> Result<Self, Self::Error> {
if s.len() != 16 {
return Err(Error::Length);
}
ensure_cdk!(s.len() == 16, Error::Length);

Ok(Self {
version: KeySetVersion::from_byte(&hex::decode(&s[..2])?[0])?,
Expand Down Expand Up @@ -230,9 +228,7 @@ impl KeySet {
pub fn verify_id(&self) -> Result<(), Error> {
let keys_id: Id = (&self.keys).into();

if keys_id != self.id {
return Err(Error::IncorrectKeysetId);
}
ensure_cdk!(keys_id == self.id, Error::IncorrectKeysetId);

Ok(())
}
Expand Down
10 changes: 3 additions & 7 deletions crates/cashu/src/nuts/nut11/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use thiserror::Error;
use super::nut00::Witness;
use super::nut01::PublicKey;
use super::{Kind, Nut10Secret, Proof, Proofs, SecretKey};
use crate::ensure_cdk;
use crate::nuts::nut00::BlindedMessage;
use crate::secret::Secret;
use crate::util::{hex, unix_time};
Expand Down Expand Up @@ -422,9 +423,7 @@ impl Conditions {
sig_flag: Option<SigFlag>,
) -> Result<Self, Error> {
if let Some(locktime) = locktime {
if locktime.lt(&unix_time()) {
return Err(Error::LocktimeInPast);
}
ensure_cdk!(locktime.ge(&unix_time()), Error::LocktimeInPast);
}

Ok(Self {
Expand Down Expand Up @@ -704,10 +703,7 @@ where
type Error = Error;

fn try_from(tag: Vec<S>) -> Result<Self, Self::Error> {
let tag_kind: TagKind = match tag.first() {
Some(kind) => TagKind::from(kind),
None => return Err(Error::KindNotFound),
};
let tag_kind = tag.first().map(TagKind::from).ok_or(Error::KindNotFound)?;

match tag_kind {
TagKind::SigFlag => Ok(Tag::SigFlag(SigFlag::from_str(tag[1].as_ref())?)),
Expand Down
6 changes: 3 additions & 3 deletions crates/cashu/src/nuts/nut14/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use super::nut00::Witness;
use super::nut10::Secret;
use super::nut11::valid_signatures;
use super::{Conditions, Proof};
use crate::ensure_cdk;
use crate::util::unix_time;

pub mod serde_htlc_witness;
Expand Down Expand Up @@ -112,9 +113,8 @@ impl Proof {
.map(|s| Signature::from_str(s))
.collect::<Result<Vec<Signature>, _>>()?;

if valid_signatures(self.secret.as_bytes(), &pubkey, &signatures).lt(&req_sigs) {
return Err(Error::IncorrectSecretKind);
}
let valid_sigs = valid_signatures(self.secret.as_bytes(), &pubkey, &signatures);
ensure_cdk!(valid_sigs >= req_sigs, Error::IncorrectSecretKind);
}
}

Expand Down
6 changes: 3 additions & 3 deletions crates/cashu/src/util/hex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use core::fmt;

use crate::ensure_cdk;

/// Hex error
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
Expand Down Expand Up @@ -76,9 +78,7 @@ where
let hex = hex.as_ref();
let len = hex.len();

if len % 2 != 0 {
return Err(Error::OddLength);
}
ensure_cdk!(len % 2 == 0, Error::OddLength);

let mut bytes: Vec<u8> = Vec::with_capacity(len / 2);

Expand Down
2 changes: 1 addition & 1 deletion crates/cdk-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ pub use cashu::mint;
pub use cashu::nuts::{self, *};
#[cfg(feature = "wallet")]
pub use cashu::wallet;
pub use cashu::{dhke, mint_url, secret, util, SECP256K1};
pub use cashu::{dhke, ensure_cdk, mint_url, secret, util, SECP256K1};
6 changes: 2 additions & 4 deletions crates/cdk-fake-wallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ use cdk::amount::{Amount, MSAT_IN_SAT};
use cdk::cdk_lightning::{
self, CreateInvoiceResponse, MintLightning, PayInvoiceResponse, PaymentQuoteResponse, Settings,
};
use cdk::mint;
use cdk::mint::FeeReserve;
use cdk::nuts::{CurrencyUnit, MeltQuoteBolt11Request, MeltQuoteState, MintQuoteState};
use cdk::util::unix_time;
use cdk::{ensure_cdk, mint};
use error::Error;
use futures::stream::StreamExt;
use futures::Stream;
Expand Down Expand Up @@ -182,9 +182,7 @@ impl MintLightning for FakeWallet {
fail.insert(payment_hash.clone());
}

if description.pay_err {
return Err(Error::UnknownInvoice.into());
}
ensure_cdk!(!description.pay_err, Error::UnknownInvoice.into());
}

Ok(PayInvoiceResponse {
Expand Down
2 changes: 1 addition & 1 deletion crates/cdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub mod pub_sub;
/// Re-export amount type
#[doc(hidden)]
pub use cdk_common::{
amount, common as types, dhke,
amount, common as types, dhke, ensure_cdk,
error::{self, Error},
lightning_invoice, mint_url, nuts, secret, util, ws, Amount, Bolt11Invoice,
};
Expand Down
14 changes: 4 additions & 10 deletions crates/cdk/src/mint/melt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::nuts::nut11::{enforce_sig_flag, EnforceSigFlag};
use crate::nuts::MeltQuoteState;
use crate::types::LnKey;
use crate::util::unix_time;
use crate::{cdk_lightning, Amount, Error};
use crate::{cdk_lightning, ensure_cdk, Amount, Error};

impl Mint {
#[instrument(skip_all)]
Expand All @@ -35,9 +35,7 @@ impl Mint {
let nut05 = mint_info.nuts.nut05;
let nut15 = mint_info.nuts.nut15;

if nut05.disabled {
return Err(Error::MeltingDisabled);
}
ensure_cdk!(!nut05.disabled, Error::MeltingDisabled);

let settings = nut05
.get_settings(&unit, &method)
Expand Down Expand Up @@ -330,19 +328,15 @@ impl Mint {

let EnforceSigFlag { sig_flag, .. } = enforce_sig_flag(melt_request.inputs.clone());

if sig_flag.eq(&SigFlag::SigAll) {
return Err(Error::SigAllUsedInMelt);
}
ensure_cdk!(sig_flag.ne(&SigFlag::SigAll), Error::SigAllUsedInMelt);

if let Some(outputs) = &melt_request.outputs {
let Verification {
amount: _,
unit: output_unit,
} = self.verify_outputs(outputs).await?;

if input_unit != output_unit {
return Err(Error::UnsupportedUnit);
}
ensure_cdk!(input_unit == output_unit, Error::UnsupportedUnit);
}

tracing::debug!("Verified melt quote: {}", melt_request.quote);
Expand Down
71 changes: 29 additions & 42 deletions crates/cdk/src/mint/mint_nut04.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use super::{
use crate::nuts::MintQuoteState;
use crate::types::LnKey;
use crate::util::unix_time;
use crate::{Amount, Error};
use crate::{ensure_cdk, Amount, Error};

impl Mint {
/// Checks that minting is enabled, request is supported unit and within range
Expand All @@ -21,38 +21,28 @@ impl Mint {
let mint_info = self.localstore.get_mint_info().await?;
let nut04 = &mint_info.nuts.nut04;

if nut04.disabled {
return Err(Error::MintingDisabled);
}

match nut04.get_settings(unit, &PaymentMethod::Bolt11) {
Some(settings) => {
if settings
.max_amount
.map_or(false, |max_amount| amount > max_amount)
{
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::AmountOutofLimitRange(
settings.min_amount.unwrap_or_default(),
settings.max_amount.unwrap_or_default(),
amount,
));
}
}
None => {
return Err(Error::UnsupportedUnit);
}
}
ensure_cdk!(!nut04.disabled, Error::MintingDisabled);

let settings = nut04
.get_settings(unit, &PaymentMethod::Bolt11)
.ok_or(Error::UnsupportedUnit)?;

let is_above_max = settings
.max_amount
.map_or(false, |max_amount| amount > max_amount);
let is_below_min = settings
.min_amount
.map_or(false, |min_amount| amount < min_amount);
let is_out_of_range = is_above_max || is_below_min;

ensure_cdk!(
!is_out_of_range,
Error::AmountOutofLimitRange(
settings.min_amount.unwrap_or_default(),
settings.max_amount.unwrap_or_default(),
amount,
)
);

Ok(())
}
Expand Down Expand Up @@ -263,12 +253,11 @@ impl Mint {
&self,
mint_request: nut04::MintBolt11Request<Uuid>,
) -> Result<nut04::MintBolt11Response, Error> {
let mint_quote =
if let Some(mint_quote) = self.localstore.get_mint_quote(&mint_request.quote).await? {
mint_quote
} else {
return Err(Error::UnknownQuote);
};
let mint_quote = self
.localstore
.get_mint_quote(&mint_request.quote)
.await?
.ok_or(Error::UnknownQuote)?;

let state = self
.localstore
Expand Down Expand Up @@ -329,9 +318,7 @@ impl Mint {
));
}

if unit != mint_quote.unit {
return Err(Error::UnsupportedUnit);
}
ensure_cdk!(unit == mint_quote.unit, Error::UnsupportedUnit);

let mut blind_signatures = Vec::with_capacity(mint_request.outputs.len());

Expand Down
Loading

0 comments on commit a394145

Please sign in to comment.