Custom math libraries are a common practice for many lending protocols. Interaction between different assets, calculation of ratios, percentages, and asset amounts with different precision requires the unification of maths in the protocol. In Aave, the main library is
WadRayMath.sol, which manages overflows, precision loss, and ensures correct ordering in multiplication/division operations. It operates with two main precision types: 18 and 27 digits. For example, the
rayMul() or
rayDiv() functions are used almost everywhere instead of regular multiplication/division, allowing for handling potential problems with precision and operations ordering.
While Aave uses protocol supply/debt tokens to track user supplies and debts, these balances alone are not enough to cover all aspects of the logic, especially for tracking the specific assets a user is borrowing or supplying. To resolve this, Aave employs an additional "per-user" value stored as single
uint256 (struct
UserConfigurationMap). Each time a user changes their position, the flags in the user configuration bitmap are changed (examples for "isBorrowing"
here or
here). This requires additional steps during operations (like
here), but it helps to make the validation cheaper at many stages (example in
validateBorrow here), especially with queries like "is user borrowing any assets", which would otherwise involve querying numerous token balances without these configuration maps.
Aave V3 supports operations with permits, featuring special versions of
supplyWithPermit() and
repayWithPermit() functions, which enable offchain signatures. This allows users to delegate these operations to external accounts, such as third-party providers, if they don't want to execute them directly.
Another important addition in Aave V3 is
L2Pool.sol. It mirrors the functionality of the base
Pool.sol but accepts arguments as packed
bytes32 values. These values are internally decoded by
L2Pool.sol and then forwarded to the corresponding functions in
Pool.sol. This approach enables executing operations like
supply(),
borrow(), and others using a single
bytes32 parameter, significantly reducing transaction costs in L2 rollups.
Aave V3 also introduces a second variant of flashloans. The
executeFlashLoan() function works similarly to Aave V2, allowing users to borrow multiple assets and repay the flashloan debt along with fees by increasing their debt in the protocol. Additionally, V3 provides a simplified version of flashloan (
the executeFlashLoanSimple() function) which enables borrowing a single asset without the option to pay with "debt increase", thus reducing gas costs. V3 also allows for setting authorized "flashborrowers" addresses that are exempt from flashloan fees.