diff --git a/reporting/src/lib.rs b/reporting/src/lib.rs index a4670393..f5709b3d 100644 --- a/reporting/src/lib.rs +++ b/reporting/src/lib.rs @@ -206,6 +206,8 @@ pub enum ReportingError { InvalidDependencyAddressConfiguration = 6, /// Report period range is invalid (`period_start` is greater than `period_end`). InvalidPeriod = 7, + /// Invalid percentage split summing to > 10000 or != 10000 + InvalidPercentageSplit = 8, } #[contracttype] @@ -799,13 +801,26 @@ impl ReportingContract { } }; - let split_amounts = match split_client.try_calculate_split(&total_amount) { - Ok(Ok(res)) => res, - _ => { - availability = DataAvailability::Partial; - Vec::new(env) + let mut split_amounts = Vec::new(env); + if availability == DataAvailability::Complete { + let mut sum = 0u32; + // Percentages are stored as basis points (bps), where 10000 = 100.00% + for i in 0..split_percentages.len() { + let p = split_percentages.get(i).unwrap_or(0); + sum = sum.checked_add(p).ok_or(ReportingError::InvalidPercentageSplit)?; + if sum > 10000 { + return Err(ReportingError::InvalidPercentageSplit); + } + + // Formula used is (amount * percentage) / 10000 + let amount = total_amount.checked_mul(p as i128).unwrap_or(0) / 10000; + split_amounts.push_back(amount); } - }; + + if sum != 10000 { + return Err(ReportingError::InvalidPercentageSplit); + } + } let mut breakdown = Vec::new(env); let categories = [ @@ -1140,7 +1155,7 @@ impl ReportingContract { let health_score = Self::calculate_health_score_internal(&env, user.clone(), total_remittance); let remittance_summary = - Self::get_remittance_summary_internal(&env, total_remittance, period_start, period_end); + Self::get_remittance_summary_internal(&env, total_remittance, period_start, period_end)?; let savings_report = Self::get_savings_report_internal(&env, user.clone(), period_start, period_end); let bill_compliance = diff --git a/reporting/src/tests.rs b/reporting/src/tests.rs index f2c4b2a9..a3eda5f9 100644 --- a/reporting/src/tests.rs +++ b/reporting/src/tests.rs @@ -29,19 +29,19 @@ mod remittance_split { impl RemittanceSplit { pub fn get_split(env: &Env) -> Vec { let mut split = Vec::new(env); - split.push_back(50); - split.push_back(30); - split.push_back(15); - split.push_back(5); + split.push_back(5000); + split.push_back(3000); + split.push_back(1500); + split.push_back(500); split } pub fn calculate_split(env: Env, total_amount: i128) -> Vec { let mut amounts = Vec::new(&env); - amounts.push_back(total_amount * 50 / 100); - amounts.push_back(total_amount * 30 / 100); - amounts.push_back(total_amount * 15 / 100); - amounts.push_back(total_amount * 5 / 100); + amounts.push_back(total_amount * 5000 / 10000); + amounts.push_back(total_amount * 3000 / 10000); + amounts.push_back(total_amount * 1500 / 10000); + amounts.push_back(total_amount * 500 / 10000); amounts } } @@ -590,7 +590,7 @@ fn test_get_remittance_summary() { let spending = summary.category_breakdown.get(0).unwrap(); assert_eq!(spending.category, Category::Spending); assert_eq!(spending.amount, 5000); - assert_eq!(spending.percentage, 50); + assert_eq!(spending.percentage, 5000); } #[test] diff --git a/reporting/src/tests_updated.rs b/reporting/src/tests_updated.rs index 7d2f710a..438dd1ab 100644 --- a/reporting/src/tests_updated.rs +++ b/reporting/src/tests_updated.rs @@ -12,19 +12,19 @@ mod remittance_split { impl RemittanceSplit { pub fn get_split(env: &Env) -> Vec { let mut split = Vec::new(env); - split.push_back(50); - split.push_back(30); - split.push_back(15); - split.push_back(5); + split.push_back(5000); + split.push_back(3000); + split.push_back(1500); + split.push_back(500); split } pub fn calculate_split(env: Env, total_amount: i128) -> Vec { let mut amounts = Vec::new(&env); - amounts.push_back(total_amount * 50 / 100); - amounts.push_back(total_amount * 30 / 100); - amounts.push_back(total_amount * 15 / 100); - amounts.push_back(total_amount * 5 / 100); + amounts.push_back(total_amount * 5000 / 10000); + amounts.push_back(total_amount * 3000 / 10000); + amounts.push_back(total_amount * 1500 / 10000); + amounts.push_back(total_amount * 500 / 10000); amounts } } @@ -457,7 +457,7 @@ fn test_get_remittance_summary() { // Check category breakdown let spending = summary.category_breakdown.get(0).unwrap(); assert_eq!(spending.amount, 5000); - assert_eq!(spending.percentage, 50); + assert_eq!(spending.percentage, 5000); } #[test]