mirror of
https://github.com/aljazceru/cdk.git
synced 2026-02-08 14:45:47 +01:00
Add more Amount::split_with_fee tests (#1058)
This commit is contained in:
@@ -132,10 +132,10 @@ 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
|
||||
let total_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 fee = Amount::from(total_fee_ppk.div_ceil(1000));
|
||||
let new_amount = self.checked_add(fee).ok_or(Error::AmountOverflow)?;
|
||||
|
||||
let split = new_amount.split();
|
||||
@@ -456,7 +456,135 @@ mod tests {
|
||||
let fee_ppk = 1000;
|
||||
|
||||
let split = amount.split_with_fee(fee_ppk).unwrap();
|
||||
assert_eq!(split, vec![Amount(32)]);
|
||||
// With fee_ppk=1000 (100%), amount 3 requires proofs totaling at least 5
|
||||
// to cover both the amount (3) and fees (~2 for 2 proofs)
|
||||
assert_eq!(split, vec![Amount(4), Amount(1)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_with_fee_reported_issue() {
|
||||
// Test the reported issue: mint 600, send 300 with fee_ppk=100
|
||||
let amount = Amount(300);
|
||||
let fee_ppk = 100;
|
||||
|
||||
let split = amount.split_with_fee(fee_ppk).unwrap();
|
||||
|
||||
// Calculate the total fee for the split
|
||||
let total_fee_ppk = (split.len() as u64) * fee_ppk;
|
||||
let total_fee = Amount::from(total_fee_ppk.div_ceil(1000));
|
||||
|
||||
// The split should cover the amount plus fees
|
||||
let split_total = Amount::try_sum(split.iter().copied()).unwrap();
|
||||
assert!(
|
||||
split_total >= amount + total_fee,
|
||||
"Split total {} should be >= amount {} + fee {}",
|
||||
split_total,
|
||||
amount,
|
||||
total_fee
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_with_fee_edge_cases() {
|
||||
// Test various amounts with fee_ppk=100
|
||||
let test_cases = vec![
|
||||
(Amount(1), 100),
|
||||
(Amount(10), 100),
|
||||
(Amount(50), 100),
|
||||
(Amount(100), 100),
|
||||
(Amount(200), 100),
|
||||
(Amount(300), 100),
|
||||
(Amount(500), 100),
|
||||
(Amount(600), 100),
|
||||
(Amount(1000), 100),
|
||||
(Amount(1337), 100),
|
||||
(Amount(5000), 100),
|
||||
];
|
||||
|
||||
for (amount, fee_ppk) in test_cases {
|
||||
let result = amount.split_with_fee(fee_ppk);
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"split_with_fee failed for amount {} with fee_ppk {}: {:?}",
|
||||
amount,
|
||||
fee_ppk,
|
||||
result.err()
|
||||
);
|
||||
|
||||
let split = result.unwrap();
|
||||
|
||||
// Verify the split covers the required amount
|
||||
let split_total = Amount::try_sum(split.iter().copied()).unwrap();
|
||||
let fee_for_split = (split.len() as u64) * fee_ppk;
|
||||
let total_fee = Amount::from(fee_for_split.div_ceil(1000));
|
||||
|
||||
// The net amount after fees should be at least the original amount
|
||||
let net_amount = split_total.checked_sub(total_fee);
|
||||
assert!(
|
||||
net_amount.is_some(),
|
||||
"Net amount calculation failed for amount {} with fee_ppk {}",
|
||||
amount,
|
||||
fee_ppk
|
||||
);
|
||||
assert!(
|
||||
net_amount.unwrap() >= amount,
|
||||
"Net amount {} is less than required {} for amount {} with fee_ppk {}",
|
||||
net_amount.unwrap(),
|
||||
amount,
|
||||
amount,
|
||||
fee_ppk
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_with_fee_high_fees() {
|
||||
// Test with very high fees
|
||||
let test_cases = vec![
|
||||
(Amount(10), 500), // 50% fee
|
||||
(Amount(10), 1000), // 100% fee
|
||||
(Amount(10), 2000), // 200% fee
|
||||
(Amount(100), 500),
|
||||
(Amount(100), 1000),
|
||||
(Amount(100), 2000),
|
||||
];
|
||||
|
||||
for (amount, fee_ppk) in test_cases {
|
||||
let result = amount.split_with_fee(fee_ppk);
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"split_with_fee failed for amount {} with fee_ppk {}: {:?}",
|
||||
amount,
|
||||
fee_ppk,
|
||||
result.err()
|
||||
);
|
||||
|
||||
let split = result.unwrap();
|
||||
let split_total = Amount::try_sum(split.iter().copied()).unwrap();
|
||||
|
||||
// With high fees, we just need to ensure we can cover the amount
|
||||
assert!(
|
||||
split_total > amount,
|
||||
"Split total {} should be greater than amount {} for fee_ppk {}",
|
||||
split_total,
|
||||
amount,
|
||||
fee_ppk
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_with_fee_recursion_limit() {
|
||||
// Test that the recursion doesn't go infinite
|
||||
// This tests the edge case where the method keeps adding Amount::ONE
|
||||
let amount = Amount(1);
|
||||
let fee_ppk = 10000; // Very high fee that might cause recursion
|
||||
|
||||
let result = amount.split_with_fee(fee_ppk);
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"split_with_fee should handle extreme fees without infinite recursion"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user