From c94979a357dbbcada153b5b63363590e4c81afdc Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Tue, 9 Sep 2025 11:26:24 +0100 Subject: [PATCH] fix: used check math (#1051) --- crates/cashu/src/amount.rs | 33 ++++++++++++++++++++++++--------- crates/cdk/src/wallet/swap.rs | 31 +++++++++++++++++++++---------- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/crates/cashu/src/amount.rs b/crates/cashu/src/amount.rs index 33bf82bf..7fc0fa81 100644 --- a/crates/cashu/src/amount.rs +++ b/crates/cashu/src/amount.rs @@ -132,12 +132,16 @@ impl Amount { /// Splits amount into powers of two while accounting for the swap fee pub fn split_with_fee(&self, fee_ppk: u64) -> Result, Error> { let without_fee_amounts = self.split(); - let fee_ppk = fee_ppk * without_fee_amounts.len() as u64; + let fee_ppk = fee_ppk + .checked_mul(without_fee_amounts.len() as u64) + .ok_or(Error::AmountOverflow)?; let fee = Amount::from(fee_ppk.div_ceil(1000)); let new_amount = self.checked_add(fee).ok_or(Error::AmountOverflow)?; let split = new_amount.split(); - let split_fee_ppk = split.len() as u64 * fee_ppk; + let split_fee_ppk = (split.len() as u64) + .checked_mul(fee_ppk) + .ok_or(Error::AmountOverflow)?; let split_fee = Amount::from(split_fee_ppk.div_ceil(1000)); if let Some(net_amount) = new_amount.checked_sub(split_fee) { @@ -258,13 +262,16 @@ impl std::ops::Add for Amount { type Output = Amount; fn add(self, rhs: Amount) -> Self::Output { - Amount(self.0.checked_add(rhs.0).expect("Addition error")) + self.checked_add(rhs) + .expect("Addition overflow: the sum of the amounts exceeds the maximum value") } } impl std::ops::AddAssign for Amount { fn add_assign(&mut self, rhs: Self) { - self.0 = self.0.checked_add(rhs.0).expect("Addition error"); + *self = self + .checked_add(rhs) + .expect("AddAssign overflow: the sum of the amounts exceeds the maximum value"); } } @@ -272,13 +279,16 @@ impl std::ops::Sub for Amount { type Output = Amount; fn sub(self, rhs: Amount) -> Self::Output { - Amount(self.0 - rhs.0) + self.checked_sub(rhs) + .expect("Subtraction underflow: cannot subtract a larger amount from a smaller amount") } } impl std::ops::SubAssign for Amount { fn sub_assign(&mut self, other: Self) { - self.0 -= other.0; + *self = self + .checked_sub(other) + .expect("SubAssign underflow: cannot subtract a larger amount from a smaller amount"); } } @@ -286,7 +296,8 @@ impl std::ops::Mul for Amount { type Output = Self; fn mul(self, other: Self) -> Self::Output { - Amount(self.0 * other.0) + self.checked_mul(other) + .expect("Multiplication overflow: the product of the amounts exceeds the maximum value") } } @@ -294,7 +305,8 @@ impl std::ops::Div for Amount { type Output = Self; fn div(self, other: Self) -> Self::Output { - Amount(self.0 / other.0) + self.checked_div(other) + .expect("Division error: cannot divide by zero or overflow occurred") } } @@ -347,7 +359,10 @@ where match (current_unit, target_unit) { (CurrencyUnit::Sat, CurrencyUnit::Sat) => Ok(amount.into()), (CurrencyUnit::Msat, CurrencyUnit::Msat) => Ok(amount.into()), - (CurrencyUnit::Sat, CurrencyUnit::Msat) => Ok((amount * MSAT_IN_SAT).into()), + (CurrencyUnit::Sat, CurrencyUnit::Msat) => amount + .checked_mul(MSAT_IN_SAT) + .map(Amount::from) + .ok_or(Error::AmountOverflow), (CurrencyUnit::Msat, CurrencyUnit::Sat) => Ok((amount / MSAT_IN_SAT).into()), (CurrencyUnit::Usd, CurrencyUnit::Usd) => Ok(amount.into()), (CurrencyUnit::Eur, CurrencyUnit::Eur) => Ok(amount.into()), diff --git a/crates/cdk/src/wallet/swap.rs b/crates/cdk/src/wallet/swap.rs index fc70dafa..8adfef6c 100644 --- a/crates/cdk/src/wallet/swap.rs +++ b/crates/cdk/src/wallet/swap.rs @@ -154,14 +154,14 @@ impl Wallet { ) .await?; - let (available_proofs, proofs_sum) = available_proofs.into_iter().map(|p| p.proof).fold( - (Vec::new(), Amount::ZERO), - |(mut acc1, mut acc2), p| { - acc2 += p.amount; + let (available_proofs, proofs_sum) = available_proofs + .into_iter() + .map(|p| p.proof) + .try_fold((Vec::new(), Amount::ZERO), |(mut acc1, acc2), p| { + let new_sum = acc2.checked_add(p.amount).ok_or(Error::AmountOverflow)?; acc1.push(p); - (acc1, acc2) - }, - ); + Ok::<_, Error>((acc1, new_sum)) + })?; ensure_cdk!(proofs_sum >= amount, Error::InsufficientFunds); @@ -215,7 +215,14 @@ impl Wallet { let fee = self.get_proofs_fee(&proofs).await?; - let change_amount: Amount = proofs_total - amount.unwrap_or(Amount::ZERO) - fee; + let total_to_subtract = amount + .unwrap_or(Amount::ZERO) + .checked_add(fee) + .ok_or(Error::AmountOverflow)?; + + let change_amount: Amount = proofs_total + .checked_sub(total_to_subtract) + .ok_or(Error::InsufficientFunds)?; let (send_amount, change_amount) = match include_fees { true => { @@ -230,8 +237,12 @@ impl Wallet { .await?; ( - amount.map(|a| a + fee_to_redeem), - change_amount - fee_to_redeem, + amount + .map(|a| a.checked_add(fee_to_redeem).ok_or(Error::AmountOverflow)) + .transpose()?, + change_amount + .checked_sub(fee_to_redeem) + .ok_or(Error::InsufficientFunds)?, ) } false => (amount, change_amount),