DeFiHardhatFoundry
250,000 USDC
View results
Submission Details
Severity: medium
Invalid

Rounding Errors Leading to Incorrect Token Conversion Amounts

Summary

Rounding errors in integer division operations within the LibUnripe and LibChop libraries lead to inaccurate token conversion amounts. This can result in users receiving fewer Ripe Tokens than expected, with potential financial implications and loss of trust in the protocol.

Affected Functions
1: getRecapPaidPercentAmount:

function getRecapPaidPercentAmount(
uint256 amount
) internal view returns (uint256 penalizedAmount) {
AppStorage storage s = LibAppStorage.diamondStorage();
return s.sys.fert.fertilizedIndex.mul(amount).div(s.sys.fert.unfertilizedIndex);
}

2: _getUnderlying

function _getUnderlying(
address unripeToken,
uint256 amount,
uint256 supply
) internal view returns (uint256 redeem) {
AppStorage storage s = LibAppStorage.diamondStorage();
redeem = s.sys.silo.unripeSettings[unripeToken].balanceOfUnderlying.mul(amount).div(supply);
}

3: LibChop.chop:

function chop(
address unripeToken,
uint256 amount,
uint256 supply
) internal returns (address underlyingToken, uint256 underlyingAmount) {
AppStorage storage s = LibAppStorage.diamondStorage();
underlyingAmount = LibUnripe._getPenalizedUnderlying(unripeToken, amount, supply);
LibUnripe.decrementUnderlying(unripeToken, underlyingAmount);
underlyingToken = s.sys.silo.unripeSettings[unripeToken].underlyingToken;
}
```

Proof of Concept

Consider a scenario where a user attempts to convert 1000 Unripe Tokens to Ripe Tokens. Suppose the internal calculations involve:

  • fertilizedIndex = 100

  • unfertilizedIndex = 3

The calculation in getRecapPaidPercentAmount would be:

  • 100 * 1000 / 3 = 33333 (truncated from 33333.3333...)

Next, suppose:

  • balanceOfUnderlying = 50000

  • supply = 10000

The calculation in _getUnderlying would be:

  • 50000 * 33333 / 10000 = 166665 (truncated from 166665.165...)

The user would expect to receive a precise conversion amount, but due to rounding, they receive 166665 instead of the expected 166666. This discrepancy grows with larger numbers or repeated operations.

Impact

  • Users will receive fewer Ripe Tokens than expected when converting Unripe Tokens, leading to potential financial losses and user dissatisfaction.

  • Cumulative rounding errors can propagate through the system, compounding inaccuracies over time.

Tools Used

Manual review

Recommendations

1: Scale calculations to use higher precision. For example, multiply the numerator by a scaling factor before performing the division, then scale down the result to the desired precision.uint256 scaledAmount = amount * 1e18; // Scale up by 1e18
uint256 result = (scaledAmount * numerator) / denominator;
result = result / 1e18; // Scale down to the original precision

2: Introduce rounding mechanisms to ensure that the final results are rounded to the nearest whole number or in a manner that aligns with the protocol's goals.

uint256 result = (numerator * amount + (denominator / 2)) / denominator; // Round to nearest whole number

3: Use Fixed-Point Arithmetic Libraries:
- Utilize libraries designed for fixed-point arithmetic that can handle precision and rounding more gracefully.
- Consider using libraries like ABDKMathQuad or other fixed-point libraries available in the Solidity ecosystem.
Updates

Lead Judging Commences

inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.