Skip to content

Latest commit

 

History

History
80 lines (55 loc) · 3.6 KB

051.md

File metadata and controls

80 lines (55 loc) · 3.6 KB

Glamorous Plum Baboon

Medium

Potential Precision Loss in executeBorrow Due to Division and Conversion to uint128

Summary:

The BorrowLogic:executeBorrow function performs a division operation to calculate the next isolation mode total debt, followed by a conversion to uint128. This calculation risks precision loss due to integer division and potential silent truncation during the conversion to uint128. This could lead to inaccuracies in debt tracking and possible over- or under-collateralization in isolation mode.

Description:

In the BorrowLogic:executeBorrow function, the calculation of nextIsolationModeTotalDebt involves dividing params.amount by a power of 10 determined by (reserveCache.reserveConfiguration.getDecimals() - ReserveConfiguration.DEBT_CEILING_DECIMALS). This result is then cast to a uint128.
1, Solidity performs integer division, discarding any fractional parts, leading to potential precision loss. 2, The conversion to uint128 risks truncation if the result exceeds the range of uint128.

This could cause inaccuracies in isolation mode debt calculations and potentially result in unintended protocol behavior.

Root Cause:

The calculation:

uint256 nextIsolationModeTotalDebt = reservesData[isolationModeCollateralAddress]
  .isolationModeTotalDebt += (params.amount /
    10 **
      (reserveCache.reserveConfiguration.getDecimals() -
        ReserveConfiguration.DEBT_CEILING_DECIMALS)).toUint128();

performs:

  1. Integer division, leading to truncation of fractional parts.
  2. Conversion to uint128, which can silently truncate values exceeding the maximum range of uint128.

https://github.com/sherlock-audit/2025-01-aave-v3-3/blob/main/aave-v3-origin/src/contracts/protocol/libraries/logic/BorrowLogic.sol#L110-L120

Impact:

i, Precision Loss: Integer division truncates fractional values, leading to imprecise debt calculations. ii, Truncation on Casting: If the calculated value exceeds uint128 limits, it will be silently truncated. iii, Risk of Over-/Under-Collateralization: In isolation mode, debt tracking inaccuracies could cause protocol inefficiencies or financial risk to users.

Proof of Concept (PoC):

Consider a scenario where: params.amount = 1,000,000 reserveCache.reserveConfiguration.getDecimals() = 18 ReserveConfiguration.DEBT_CEILING_DECIMALS = 2

The calculation becomes:

nextIsolationModeTotalDebt = reservesData[isolationModeCollateralAddress]
  .isolationModeTotalDebt += (1,000,000 / 10 ** (18 - 2)).toUint128();

Here:

  1. The division results in 1,000,000 / 10 ** 16, which equals 0.0001 but is truncated to 0 due to integer division.
  2. The toUint128 conversion would then cast this incorrect value, resulting in precision loss.

Mitigation:

To mitigate the precision loss and truncation:

  1. Use fixed-point arithmetic libraries, such as WadRayMath, to perform precise calculations.
  2. Ensure safe conversion to uint128 by adding a validation step to confirm the calculated value fits within the range of uint128.

Updated Code:

uint256 calculatedAmount = (params.amount *
    10 ** ReserveConfiguration.DEBT_CEILING_DECIMALS) /
    10 ** reserveCache.reserveConfiguration.getDecimals();

require(calculatedAmount <= type(uint128).max, "Overflow in uint128 conversion");

uint256 nextIsolationModeTotalDebt = reservesData[isolationModeCollateralAddress]
  .isolationModeTotalDebt += uint128(calculatedAmount);
  • Fixed-point arithmetic ensures fractional values are handled correctly.
  • Validation check ensures no overflow occurs during the uint128 conversion.