Browse Source

fix: used check math (#1051)

thesimplekid 1 month ago
parent
commit
c94979a357
2 changed files with 45 additions and 19 deletions
  1. 24 9
      crates/cashu/src/amount.rs
  2. 21 10
      crates/cdk/src/wallet/swap.rs

+ 24 - 9
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<Vec<Self>, 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()),

+ 21 - 10
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),