Rounding errors after slashing
When slashing happens `_delegatedToValidator` and `_effectiveDelegatedToValidator` values are reduced.\\n```\\nfunction confiscate(uint validatorId, uint amount) external {\\n    uint currentMonth = getCurrentMonth();\\n    Fraction memory coefficient = reduce(\\_delegatedToValidator[validatorId], amount, currentMonth);\\n    reduce(\\_effectiveDelegatedToValidator[validatorId], coefficient, currentMonth);\\n    putToSlashingLog(\\_slashesOfValidator[validatorId], coefficient, currentMonth);\\n    \\_slashes.push(SlashingEvent({reducingCoefficient: coefficient, validatorId: validatorId, month: currentMonth}));\\n}\\n```\\n\\nWhen holders process slashings, they reduce `_delegatedByHolderToValidator`, `_delegatedByHolder`, `_effectiveDelegatedByHolderToValidator` values.\\n```\\nif (oldValue > 0) {\\n    reduce(\\n        \\_delegatedByHolderToValidator[holder][validatorId],\\n        \\_delegatedByHolder[holder],\\n        \\_slashes[index].reducingCoefficient,\\n        month);\\n    reduce(\\n        \\_effectiveDelegatedByHolderToValidator[holder][validatorId],\\n        \\_slashes[index].reducingCoefficient,\\n        month);\\n    slashingSignals[index.sub(begin)].holder = holder;\\n    slashingSignals[index.sub(begin)].penalty = oldValue.sub(getAndUpdateDelegatedByHolderToValidator(holder, validatorId, month));\\n}\\n```\\n\\nAlso when holders are undelegating, they are calculating how many tokens from `delegations[delegationId].amount` were slashed.\\n```\\nuint amountAfterSlashing = calculateDelegationAmountAfterSlashing(delegationId);\\n```\\n\\nAll these values should be calculated one from another, but they all will have different rounding errors after slashing. For example, the assumptions that the total sum of all delegations from holder `X` to validator `Y` should still be equal to `_delegatedByHolderToValidator[X][Y]` is not true anymore. The problem is that these assumptions are still used. For example, when undelegating some delegation with delegated `amount` equals amount(after slashing), the holder will reduce `_delegatedByHolderToValidator[X][Y]`, `_delegatedByHolder[X]` and `_delegatedToValidator[Y]` by `amount`. Since rounding errors of all these values are different that will lead to 2 possible scenarios:\\nIf rounding error reduces `amount` not that much as other values, we can have `uint` underflow. This is especially dangerous because all calculations are delayed and we will know about underflow and `SafeMath` revert in the next month or later.\\nDevelopers already made sure that rounding errors are aligned in a correct way, and that the reduced value should always be larger than the subtracted, so there should not be underflow. This solution is very unstable because it's hard to verify it and keep in mind even during a small code change. 2. If rounding errors make `amount` smaller then it should be, when other values should be zero (for example, when all the delegations are undelegated), these values will become some very small values. The problem here is that it would be impossible to compare values to zero.
Consider not calling `revert` on these subtractions and make result value be equals to zero if underflow happens.\\nConsider comparing to some small `epsilon` value instead of zero. Or similar to the previous point, on every subtraction check if the value is smaller then `epsilon`, and make it zero if it is.
```\\nfunction confiscate(uint validatorId, uint amount) external {\\n    uint currentMonth = getCurrentMonth();\\n    Fraction memory coefficient = reduce(\\_delegatedToValidator[validatorId], amount, currentMonth);\\n    reduce(\\_effectiveDelegatedToValidator[validatorId], coefficient, currentMonth);\\n    putToSlashingLog(\\_slashesOfValidator[validatorId], coefficient, currentMonth);\\n    \\_slashes.push(SlashingEvent({reducingCoefficient: coefficient, validatorId: validatorId, month: currentMonth}));\\n}\\n```\\n