.updateState

TLDR

The updateState function serves to update the interest and indexes within the system for a specific asset.

Code

If state has been updated within the same block in a previous transaction, do nothing. Else this function does two things:

  1. _updateIndexes => updates Indexes: nextLiquidityIndex, nextVariableBorrowIndex

  2. _accrueToTreasury => updates Treasury accrual

  3. updates reserve.lastUpdateTimestamp to current block.timestamp

On time

  • .cache assigns reserveCache.reserveLastUpdateTimestamp = reserve.lastUpdateTimestamp

  • .updateState updates reserve.lastUpdateTimestamp to latest

_updateIndexes

Updates nextliquidityIndex by the way of calculateLinearInterest, and updates nextVariableBorrowIndex by the way of calculateCompoundInterest.

  • supply interest is accrued via linear interest (simple interest)

  • borrow interest is accrued via compound interest

calculateLinearInterest

Calculates linear interest accrued from lastUpdateTimeStamp till current block.timestamp.

  • serves to update deposit interest and liquidity index

  • explanation: deposit-interest

calculateCompoundInterest

Calculates interest accrued from lastUpdateTimeStamp till current block.timestamp.

  • interest is compounded every second

  • serves to update variable borrow interest and variable borrow index

  • explanation: borrow-interest

_accrueToTreasury

A portion of repaid borrow interest goes to Aave's treasury; the rest is paid out to suppliers. This portion is determined by the reserve factor: : % of borrow rate that goes to Treasury.

  • reserve.accruedToTreasury represents the treasury's cut of repaid interest to date.

  • _accrueToTreasury serves to increment this value, by accounting for unbooked interest.

  • Unbooked interest: interest accrued from the last update till now.

  • Last update: reserveCache.reserveLastUpdateTimestamp

  • Treasury accrues funds in aTokens.

  • While accruedToTreasury is incremented, the tokens are not minted; that happens when mintToTreasury is called.

In a nutshell, the function calculates the "new debt" accumulated from lastUpdateTimestamp till now, and applies the reserve factor upon - accounting for the treasury's portion.

  • "new debt" comprises of both variable and stable components

Unbooked variable debt

For variable debt, the increase is accounted for by the delta between curr and next indexes:

  • nextVariableBorrowIndex will account for interest accrued up till now

  • currVariableBorrowIndex will account for interest accrued up till lastUpdateTimestamp

Essentially,

The difference gives us the delta of variable debt since lastUpdateTimestamp.

Unbooked stable debt

The approach here has to be different simply because there is no index for stable debt.

First, let's isolate the sections of code for calculating unbooked stable debt.

calculated in .cache:
// from getSupplyData():
reserveCache.currTotalStableDebt = _calcTotalSupply(avgRate)
reserveCache.stableDebtLastUpdateTimestamp = _totalSupplyTimestamp
from _accrueToTreasury:
//calculate the stable debt from stableDebtLastUpdateTimestamp 
//until reserveLastUpdateTimestamp
vars.cumulatedStableInterest = MathUtils.calculateCompoundedInterest(
  reserveCache.currAvgStableBorrowRate,
  reserveCache.stableDebtLastUpdateTimestamp,
  reserveCache.reserveLastUpdateTimestamp
);

//prevTotalStableDebt = currPrincipalStableDebt * cumulatedStableInterest
vars.prevTotalStableDebt = 
reserveCache.currPrincipalStableDebt.rayMul(vars.cumulatedStableInterest);

// to find unbooked component
currTotalStableDebt - prevTotalStableDebt

currTotalStableDebt - prevTotalStableDebt gives us interest accrued from reserveLastUpdateTimestamp till now.

  • currTotalStableDebt: accounts for interest from _totalSupplyTimestamp till now

  • prevTotalStableDebt: accounts for interest from stableDebtLastUpdateTimestamp to reserveLastUpdateTimestamp

stableDebtLastUpdateTimestamp == _totalSupplyTimestamp

Why can't we simply calculate interest from reserveLastUpdateTimestamp, similar to variable debt?

  • reserveLastUpdateTimestamp >= _totalSupplyTimestamp

  • _totalSupplyTimestamp is only updated when mint/burn of the stableDebtToken is called.

  • reserveLastUpdateTimestamp is updated in .updateState, which is called in every state-changing function.

Given how often that that happens,reserveLastUpdateTimestamp is updated far more frequently, while _totalSupplyTimestamp is likely to be 'stale'.

Why ignore stable debt accrued from _totalSupplyTimestamp to reserveLastUpdateTimestamp ?

Putting it together

  • Paid to treasury = amountToMint =totalDebtAccrued * reserveFactor

If amountToMint is a non-zero value, reserve.accruedToTreasury is incremented by: amountToMint / nextLiquidityIndex

This scales against the most recent index; similar to how deposits are scaled.

Visual Aid

Last updated