Rates Guide

Contents

Supply and Borrow Rates

How are rates calculated?

Variable Borrow Rate

The variable borrow rate is determined is determined programatically based on the interest rate strategy for a reserve. The InterestRateStrategy for each reserve can be queried from the AaveProtocolDataProvider or UiPoolDataProvider view contracts.

Whenever an action occurs on a reserve (supply, borrow, repay, withdraw, liquidation, etc.), updateInterestRates is called. Most reserves implement the DefaultInterestRateStrategy which updates variable borrow rates based on the variable rate slope parameters determined by Aave Governance and borrow utilitization of the reserve.

An exception to this is the Aave GHO facilitator which uses a custom implementation of the interest rate strategy, more details.

Stable Borrow Rate

The stable borrow rate (for new borrows) is determined programatically based on the interest rate strategy for a reserve. The InterestRateStrategy for each reserve can be queried from the AaveProtocolDataProvider or UiPoolDataProvider view contracts.

Whenever an action occurs on a reserve (supply, borrow, repay, withdraw, liquidation, etc.), updateInterestRates is called. All stable borrow reserves implement the DefaultInterestRateStrategy which updates stable borrow rates based on the stable rate slope parameters determined by Aave Governance and borrow utilitization of the reserve.

The rate for each active stable borrower is stored in a mapping and can be queried from the getUserStableBorrowRate function.

In certain conditions, the stable borrow rate for a borrower can be rebalanced, see the FAQ for specific requirements in Aave V2 and V3.

Supply Rate

The supply rate is determined is determined programatically based on the interest rate strategy for a reserve. The InterestRateStrategy for each reserve can be queried from the AaveProtocolDataProvider or UiPoolDataProvider view contracts.

Whenever an action occurs on a reserve (supply, borrow, repay, withdraw, liquidation, etc.), updateInterestRates is called. The supply rate is updated based on the weighted average of all variable and stable borrow rates minus the reserve factor, which is the percentage of borrow interest to the DAO treasury collector, determined by Aave Goveran

How is yield accrued?

Variable Borrow Balances

Variable borrow balances increase over time, based on a checkpointing variable called variableBorrowIndex:

VariableDebtToken.balanceOf(user) = VariableDebtToken.scaledBalanceOf(user) * Pool.getReserveData(underlyingTokenAddress).variableBorrowIndex

where

VariableDebtToken.scaledBalanceOf(user) = initialBorrowAmount / variableBorrowIndexAtTimeOfBorrow

variableBorrowIndex is shared across all variable borrowers and is updated on all reserve state updates (supply, borrow, withdraw, repay, liquidate, etc.) based on the current variable borrow rate and time since last update.

The variableBorrowIndex can be queried from the Pool.getReserveData(underlyingTokenAddress), AaveProtocolDataProvider.getReserveData(underlyingTokenAddress), or UiPoolDataProvider.getReservesData() functions.

In Aave V3, all VariableDebtTokens contain a function getPreviousIndex which can be used to calculate accrued interest:

initialBorrowedAmount = VariableDebtToken.scaledBalanceOf(user) * VariableDebtToken.getPreviousIndex(user)
accruedInterest = VariableDebtToken.balanceOf(user) - initialBorrowedAmount
Stable Borrow Balances
StableDebtToken.balanceOf(user) = StableDebtToken.principalBalanceOf(user) * accuredInterest

where StableDebtToken.principalBalanceOf(user) is the initial borrow amount and accruedInterest is calculated here based on the rate and last update timestamp of an individual address.

The rate and lastUpdateTimestamp for each active stable borrower are stored in mappings and can be queried from the getUserStableBorrowRate and getUserLastUpdated functions respectively.

Supply Balances

The checkpointing for supply balances occurs through the liquidityIndex variable:

AToken.balanceOf(user) = AToken.scaledBalanceOf(user) * Pool.getReserveData(underlyingTokenAddress).liquidityIndex

where

AToken.scaledBalanceOf(user) = initialSupplyAmount / liquidityIndexAtTimeOfSupply

liquidityIndex is a variable shared across all suppliers and is updated on all reserve state updates (supply, borrow, withdraw, repay, liquidate, etc.) based on the current supply rate and time since last update.

The liquidityIndex can be queried from the Pool.getReserveData(underlyingTokenAddress), AaveProtocolDataProvider.getReserveData(underlyingTokenAddress), or UiPoolDataProvider.getReservesData() functions.

In Aave V3, all ATokens contain a function getPreviousIndex which can be used to calculate accrued interest:

initialSuppliedAmount = AToken.scaledBalanceOf(user) * AToken.getPreviousIndex(user)
accruedInterest = AToken.balanceOf(user) - initialSuppliedAmount

How to query live data?

JavaScript SDK

The Aave Utilities SDK is an extension of ethers v5, which simplifies the process of querying Aave Protocol data through a blockhain RPC:

Fetch Data

Format Data

On-Chain

Live rates can queried from the Pool, AaveProtocolDataProvider, or UiPoolDataProvider smart contracts.

The Aave Address Book is a registry of all protocol contract addresses.

Rates queried from contracts are in RAY units (10^27) and are not compounded, see formatting rates to convert to compounded percentage form.

Subgraph

The protocol subgraphs are indexed GraphQL endpoints which can be used to query current reserve states.

Subgraph rates come directly from smart contracts: RAY units (10^27) and are not compounded, see formatting rates to convert to compounded percentage form.

Reserve Query

{
  reserves {
    name
    underlyingAsset
    
    liquidityRate 
    stableBorrowRate
    variableBorrowRate
  }
}

User Data Query (for stable borrow data)


{
  userReserves(where: {user: "insert_lowercase_address_here"}){
    reserve{
      symbol
    }
    stableBorrowRate
    stableBorrowLastUpdateTimestamp
  }
}

How to query historical data?

Historical data for parameters, rates, and balances can be queried through contract events or indexed data sources.

A breakdown of all core protocol events can be found here.

The Aave Protocol subgraphs are an example of an indexed data source that maps contract events to a GraphQL endpoint.

Reward Emissions

This documentation explains the process of reward emissions.

Formatting Rates

All rates and indeces queried on-chain or from subgraphs are expressed in RAY units i.e. 10^27.

Supply and borrow rates queried on-chain or from subgraphs are not compounded (APR). On the smart contract, borrow rates are compounded per second using a binomial approximation (APY). Within each update action, supply rates are applied linearly, however, on an inter-action basis they experience the same compounding effect as the borrow rates, more details.

The Aave Utilities SDK formatting functions (used on the app.aave.com interface) computes the compounded supply and borrow rates using the formula shown below.

Incentive emissions are always non-compounded, they are applied to the scaled supply or borrow balance.

APR -> APY

To convert the APR (non-compounded) to APY (compounded per second), the formula is:

APY=(1+(APR/secondsPerYear))secondsPerYear1APY = (1 + (APR / secondsPerYear))^{secondsPerYear} - 1

where the APY and APR are in decimal form (i.e. 2.5% = 0.025)

Weighted Average APY

Weighted Average APY is the single-sided (supply or borrow) affect of rates on an addresses positions. It is calculated as the sum of ((positionBalanceUSD * positionAPY) / totalBalanceUSD) for each position that an address holds.

Example:

Address supplies 100USD of WETH @ 2% and 200USD of WBTC @ 5%.

Weighted Average Supply APY = ((100 * 0.02) / (100 + 200)) + ((200 * 0.05) / (100 + 200)) = 0.04 = 4%

Net APY

Net APY is the impact of supply and borrow rates on net worth (totalSupplied - totalBorrowed). It is an estimate of how much net worth will change after one year of current rates.

The Net APY can be higher or lower than the individual weighted average APYs, this is most noticeable when the ratio of totalSupplied to netWorth is large.

The forumla is:

netAPY = ((weightedAverageSupplyAPY * totalSuppliedUSD) / netWorthUSD) - ((weightedAverageBorrowAPY * totalBorrowedUSD) / netWorthUSD)

Example:

Address supplies 100USD of WETH @ 2% and 200USD of WBTC @ 5%.

Weighted Average Supply APY = ((100 * 0.02) / (100 + 200)) + ((200 * 0.05) / (100 + 200)) = 0.04 = 4%

Address borrows 75USD of GHO @ 4% and 100USD of WETH @ 3%

Weighted Average Borrow APY = ((75 * 0.04) / (75 + 100)) + ((100 * 0.03) / (75 + 100)) = -0.03428 = 3.428%

Net Worth = (100 + 200) - (75 + 100) = 125USD

Net APY = ((0.04 * 300) / 125) + ((-0.03428 * 175) / 125) = 0.096 - 0.048 = 0.048 = 4.8%

Last updated