Tadle

Tadle
DeFiFoundry
27,750 USDC
View results
Submission Details
Severity: low
Valid

Cumulative Precision Loss in Token Calculations

Vulnerability Details

The contract uses floor rounding in multiple division operations, which can lead to precision loss. This is particularly evident in functions like closeBidTaker where calculations involving token amounts are performed.

Impact

Over time and multiple transactions, the cumulative effect of always rounding down could result in a non-trivial amount of value being lost. This affects the accuracy of token distributions and could lead to discrepancies between expected and actual balances.

Proof of Concept

Consider the following scenario in the closeBidTaker function:

Link to code

uint256 collateralFee = 1000000; // 1 million tokens
uint256 userRemainingPoints = 999;
uint256 offerInfo.usedPoints = 1000;
uint256 userCollateralFee = collateralFee.mulDiv(
userRemainingPoints,
offerInfo.usedPoints,
Math.Rounding.Floor
);
// userCollateralFee = 1000000 * 999 / 1000 = 999000

In this case, the user should receive 999,000 tokens. However, if this calculation is performed 1000 times with similar ratios, the cumulative loss would be:

1000 * (1000000 - 999000) = 1,000,000 tokens

This demonstrates how small rounding errors can accumulate to significant amounts over multiple transactions.

This calculation uses integer division with floor rounding. If userRemainingPoints is significantly smaller than offerInfo.usedPoints, it could lead to rounding down to zero, even when a non-zero fee should be applied.

For example, if collateralFee is 100, userRemainingPoints is 1, and offerInfo.usedPoints is 1000, the result would be:

100 * 1 / 1000 = 0 (rounded down)

When in reality, it should be 0.1, which would round to 1 in integer arithmetic.

Tools Used

Manual Review

Recommendations

  • Consider using a higher precision for calculations. Multiply by a large factor before division and then scale back down:

uint256 PRECISION = 1e18;
uint256 userCollateralFee = collateralFee.mulDiv(
userRemainingPoints * PRECISION,
offerInfo.usedPoints,
Math.Rounding.Floor
) / PRECISION;
  • Implement a minimum fee threshold to ensure that very small fees are not rounded down to zero:

uint256 userCollateralFee = collateralFee.mulDiv(
userRemainingPoints,
offerInfo.usedPoints,
Math.Rounding.Floor
);
uint256 MIN_FEE = 1; // Or another appropriate minimum value
if (userCollateralFee == 0 && collateralFee > 0) {
userCollateralFee = MIN_FEE;
}
Updates

Lead Judging Commences

0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-PreMarkets-Rounding-Direction

Duplicate of #456, however, for issues noting rounding directions, will be low severity given the impact is not proven sufficiently with a PoC/numerical example and most rounding will not result in significant losses e.g. most examples only proved at most a 1 wei difference when computing `depositAmount/platFormFees` and involves lower amount offers

Support

FAQs

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

Give us feedback!