👻
Aave Book
  • Introduction
  • TradFi vs DeFi: Lending
  • Market forces x Interest Rate Models
  • On Indexes
    • Why use indexes?
  • Scaling and ATokens
  • Deposit & Borrow Interest
  • Stable borrowing
    • 🚧Under construction
  • Liquidation
    • 🚧TODO: Full example
    • 🚧Under construction: oracles
  • Primer
    • Bitmap & Masks
      • 🚧padding and bytes
    • WadRayLibrary
      • Math Operations
      • 🚧WIP: Scaling different decimal representations
      • 🚧WIP: 2's complement
      • 🚧casting: to uint128
    • PercentageMath
    • Embedded vs Linked Libraries
  • Functions
    • General Execution flow
    • Architecture & Design choices
      • 🚧Upgradability and Proxies
    • Common Functions
      • getReserveFactor, getDecimals
      • .cache
      • .updateState
      • .updateInterestRates
      • SupplyCap, BorrowCap
      • getFlags
        • 🚧more on flags
      • calculateUserAccountData
    • supply
      • validateSupply
      • transfer & mint
      • isFirstSupply
        • isUsingAsCollateralOne, isUsingAsCollateralAny
      • On check-effects-interactions pattern
    • withdraw
      • get user balance & withdraw amount
      • validateWithdraw
      • collateral check
      • burn ATokens
      • Ensure existing loans are collateralized
    • borrow
      • getIsolationModeState
      • .validateBorrow
      • Mint debt token
      • setBorrowing
      • update IsolationMode debt
      • transfer underlying to user
    • repay
      • get current debt
      • validateRepay, paybackAmount
      • burn debt tokens
      • Cleanup + Collect repay
    • liquidate
      • _calculateDebt
      • validateLiquidationCall
      • getConfigurationData
      • calculateAvailableCollateralToLiquidate
      • 🚧_burnDebtTokens
      • liquidate/burn collateral
      • liquidation Fee
      • Wrap-up
    • 🚧swapBorrowRateMode
    • 🚧setUserUseReserveAsCollateral
  • Contracts
    • AToken
      • Simple example: mint & balanceOf
    • StableDebtToken
      • Implementation explained
    • VariableDebtToken
    • DefaultReserveInterestRateStrategy
    • L2
      • 🚧PriceOracleSentinel
  • Audit findings
    • 🚧Under construction
  • Appendix
    • Simple, Compound, APR, APY
  • Aave Features
    • Risk Management
      • Supply & Borrow Caps
      • Isolation Mode
      • Siloed Borrowing
    • Other features
      • Repay with ATokens
      • eMode: High efficiency Mode
      • 🚧Aave Vault
      • 🚧Portal
Powered by GitBook
On this page

Was this helpful?

Edit on GitHub

Last updated 1 year ago

Was this helpful?

This Aave library provides functions to perform percentage calculations.

  • Percentages are defined by with 2 decimals of precision (100.00).

  • The precision is indicated by PERCENTAGE_FACTOR.

  • Operations are rounded. If a value is >=.5, will be rounded up, otherwise rounded down.

Fixed-point representations of percentages: (2 dp of precision)

  • 100% is represented as 10000 -> 100.00%

  • 50% is represented as 5000 -> 50.00%

  • 1% is represented as 100 -> 1.00%

percentMul

Test example

  • for value: 10000, percentage: 100 -> result: 100

We know this to be true as 1% of 10000 is indeed 100. Feel free to experiment on remix!

Multiplication operation

Let's start by examining the multiplication operation:

  • Divide by PERCENTAGE_FACTOR: To negate the effect of representing 0.01 as 100

  • Adding HALF_PERCENTAGE_FACTOR: For rounding to the nearest integer.

The reason for adding half of the divisor to the dividend was covered earlier, in the fixed-point section on rounding.

* maybe show diag of when round down vs round up?

overflow

Revert if

  • the percentage is 0 , OR

The explanation is similar to the overflow check explanation given with regards to wadMul, in the earlier section.

Both percentage and value were received as uint256 inputs - so we have no concerns there of overflow. However, with the manipulations made to the dividend, A, we cannot be sure that in some instances it might not overflow beyond uint256.

  • Essentially, with this condition, we are saying that the dividend cannot exceed what can be represented by uint256.

  • This is a necessary check as we did supply A as a uint256 input, but rather "created" it via our operations within the function.

  • Remember, the compiler checks for {over,under}flow do not apply within assembly blocks!

give example on when inputs lead to overflow?

percentDiv

Division operation

Example

  • value = 100

  • percentage = 100 (1%)

  • result => 10000

Let's start by examining the division operation:

overflow

Revert if:

  • percentage is 0 , OR

The dividend must be <= type(uint256).max to avoid an overflow. The condition is obtained by observing the manipulations made in the dividend:

value (type(uint256).max - HALF_PERCENTAGE_FACTOR) / percentage

Why should value (type(uint256).max - HALF_PERCENTAGE_FACTOR) / percentage, you ask?

value (type(uint256).max - halfPercentage) / PERCENTAGE_FACTOR

// Maximum percentage factor (100.00%)
uint256 internal constant PERCENTAGE_FACTOR = 1e4;

// Half percentage factor (50.00%)
uint256 internal constant HALF_PERCENTAGE_FACTOR = 0.5e4;
result := div(add(mul(value, percentage), HALF_PERCENTAGE_FACTOR), PERCENTAGE_FACTOR)

// translated:
[(value * percentage) + HALF_PERCENTAGE_FACTOR] / PERCENTAGE_FACTOR
>\gt>
if iszero(
  or(
    iszero(percentage),
    iszero(gt(value, div(sub(not(0), HALF_PERCENTAGE_FACTOR), percentage)))
  )
) {
  revert(0, 0)
}

// Overflow check, if percentage != 0
// value <= (type(uint256).max - HALF_PERCENTAGE_FACTOR) / percentage
iszero(percentage), iszero(gt(value, div(sub(not(0), HALF_PERCENTAGE_FACTOR), percentage)))
≤ \leq≤
[(value * percentage) + HALF_PERCENTAGE_FACTOR] / PERCENTAGE_FACTOR
A / PERCENTAGE_FACTOR, where A: [(value * percentage) + HALF_PERCENTAGE_FACTOR]
value <= (type(uint256).max - HALF_PERCENTAGE_FACTOR) / percentage
value * percentage <= (type(uint256).max - HALF_PERCENTAGE_FACTOR)
(value * percentage) + HALF_PERCENTAGE_FACTOR <= type(uint256).max
A <= type(uint256).max
dividend <= type(uint256).max
result := div(add(mul(value, PERCENTAGE_FACTOR), div(percentage, 2)), percentage)

// translated:
[(value * PERCENTAGE_FACTOR) + percentage/2] / percentage
if or(
  iszero(percentage),
  iszero(iszero(gt(value, div(sub(not(0), div(percentage, 2)), PERCENTAGE_FACTOR))))
) {
  revert(0, 0)
}
>\gt>
[(value * PERCENTAGE_FACTOR) + percentage/2] <= type(uint256).max
(value * PERCENTAGE_FACTOR) <= type(uint256).max - percentage/2
value <= [type(uint256).max - percentage/2] / PERCENTAGE_FACTOR
  1. Primer

PercentageMath

Previouscasting: to uint128NextEmbedded vs Linked Libraries
  • percentMul
  • Multiplication operation
  • overflow
  • percentDiv
  • Division operation
  • overflow
percentMul