|
1 | 1 | use num::rational::Ratio;
|
| 2 | +use num_traits::CheckedSub; |
2 | 3 | use primitives::{BalancesMap, BigNum, Channel, DomainError, ValidatorDesc};
|
3 | 4 |
|
4 | 5 | pub fn get_balances_after_fees_tree(
|
5 | 6 | balances: &BalancesMap,
|
6 | 7 | channel: &Channel,
|
7 | 8 | ) -> Result<BalancesMap, DomainError> {
|
8 |
| - let distribution = Distribution::new(balances, &channel)?; |
| 9 | + let deposit_amount = channel.deposit_amount.clone(); |
| 10 | + |
| 11 | + let total_distributed = balances.iter().map(|(_, balance)| balance).sum::<BigNum>(); |
| 12 | + |
| 13 | + let validators_iter = channel.spec.validators.into_iter(); |
| 14 | + let total_validators_fee = validators_iter |
| 15 | + .map(|validator| &validator.fee) |
| 16 | + .sum::<BigNum>(); |
| 17 | + |
| 18 | + if total_validators_fee > deposit_amount { |
| 19 | + return Err(DomainError::RuleViolation( |
| 20 | + "total fees <= deposit: fee constraint violated".into(), |
| 21 | + )); |
| 22 | + } |
| 23 | + |
| 24 | + if total_distributed > deposit_amount { |
| 25 | + return Err(DomainError::RuleViolation( |
| 26 | + "distributed <= deposit: OUTPACE rule #4".into(), |
| 27 | + )); |
| 28 | + } |
| 29 | + |
| 30 | + let deposit_to_distribute = &deposit_amount - &total_validators_fee; |
| 31 | + |
| 32 | + let ratio = Ratio::new(deposit_to_distribute.clone(), deposit_amount.clone()); |
| 33 | + let fee_ratio = Ratio::new(total_distributed.clone(), deposit_amount.clone()); |
9 | 34 |
|
10 | 35 | let mut balances_after_fees = BalancesMap::default();
|
11 | 36 | let mut total = BigNum::from(0);
|
12 | 37 |
|
13 | 38 | for (key, value) in balances.iter() {
|
14 |
| - let adjusted_balance = value * &distribution.ratio; |
| 39 | + let adjusted_balance = value * ∶ |
15 | 40 |
|
16 | 41 | total += &adjusted_balance;
|
17 | 42 | balances_after_fees.insert(key.clone(), adjusted_balance);
|
18 | 43 | }
|
19 | 44 |
|
20 |
| - let rounding_error = distribution.rounding_error(&total)?; |
| 45 | + let rounding_error = if deposit_amount == total_distributed { |
| 46 | + deposit_to_distribute |
| 47 | + .checked_sub(&total) |
| 48 | + .ok_or(DomainError::RuleViolation( |
| 49 | + "rounding_err should never be negative".to_owned(), |
| 50 | + ))? |
| 51 | + } else { |
| 52 | + BigNum::from(0) |
| 53 | + }; |
21 | 54 |
|
22 | 55 | let balances_after_fees = distribute_fee(
|
23 | 56 | balances_after_fees,
|
24 | 57 | rounding_error,
|
25 |
| - distribution.fee_ratio, |
| 58 | + fee_ratio, |
26 | 59 | channel.spec.validators.into_iter(),
|
27 | 60 | );
|
28 | 61 |
|
@@ -56,77 +89,6 @@ fn distribute_fee<'a>(
|
56 | 89 | balances
|
57 | 90 | }
|
58 | 91 |
|
59 |
| -#[derive(Debug)] |
60 |
| -struct Distribution { |
61 |
| - pub deposit: BigNum, |
62 |
| - /// Total Distributed is the sum of all balances in the BalancesMap |
63 |
| - pub total_distributed: BigNum, |
64 |
| - /// The Sum of all validators fee |
65 |
| - pub validators_fee: BigNum, |
66 |
| - /// Deposit - Validators fee |
67 |
| - pub to_distribute: BigNum, |
68 |
| - /// The ratio that is (Deposit - TotalValidatorFee) / Deposit |
69 |
| - pub ratio: Ratio<BigNum>, |
70 |
| - /// Total Distributed / Deposit |
71 |
| - pub fee_ratio: Ratio<BigNum>, |
72 |
| - _secret: (), |
73 |
| -} |
74 |
| - |
75 |
| -impl Distribution { |
76 |
| - pub fn new(for_balances: &BalancesMap, on_channel: &Channel) -> Result<Self, DomainError> { |
77 |
| - let deposit = on_channel.deposit_amount.clone(); |
78 |
| - |
79 |
| - let total_distributed: BigNum = for_balances.iter().map(|(_, balance)| balance).sum(); |
80 |
| - |
81 |
| - let validators_iter = on_channel.spec.validators.into_iter(); |
82 |
| - let total_validators_fee: BigNum = validators_iter.map(|validator| &validator.fee).sum(); |
83 |
| - |
84 |
| - if total_validators_fee > deposit { |
85 |
| - return Err(DomainError::RuleViolation( |
86 |
| - "total fees <= deposit: fee constraint violated".into(), |
87 |
| - )); |
88 |
| - } |
89 |
| - |
90 |
| - if total_distributed > deposit { |
91 |
| - return Err(DomainError::RuleViolation( |
92 |
| - "distributed <= deposit: OUTPACE rule #4".into(), |
93 |
| - )); |
94 |
| - } |
95 |
| - |
96 |
| - let to_distribute = &deposit - &total_validators_fee; |
97 |
| - |
98 |
| - let ratio = Ratio::new(to_distribute.clone(), deposit.clone()); |
99 |
| - let fee_ratio = Ratio::new(total_distributed.clone(), deposit.clone()); |
100 |
| - |
101 |
| - Ok(Self { |
102 |
| - deposit, |
103 |
| - total_distributed, |
104 |
| - validators_fee: total_validators_fee, |
105 |
| - to_distribute, |
106 |
| - ratio, |
107 |
| - fee_ratio, |
108 |
| - _secret: (), |
109 |
| - }) |
110 |
| - } |
111 |
| - |
112 |
| - /// Returns the rounding error and also checks for rule violation if it is < 0 |
113 |
| - pub fn rounding_error(&self, total_distributed: &BigNum) -> Result<BigNum, DomainError> { |
114 |
| - let rounding_error = if self.deposit == self.total_distributed { |
115 |
| - &self.to_distribute - total_distributed |
116 |
| - } else { |
117 |
| - BigNum::from(0) |
118 |
| - }; |
119 |
| - |
120 |
| - if rounding_error < BigNum::from(0) { |
121 |
| - Err(DomainError::RuleViolation( |
122 |
| - "The Rounding error should never be negative".into(), |
123 |
| - )) |
124 |
| - } else { |
125 |
| - Ok(rounding_error) |
126 |
| - } |
127 |
| - } |
128 |
| -} |
129 |
| - |
130 | 92 | #[cfg(test)]
|
131 | 93 | mod test {
|
132 | 94 | use super::*;
|
|
0 commit comments