aave / aave-v3-core

This repository contains the core smart contracts of the Aave V3 protocol.
https://aave.com
Other
868 stars 569 forks source link

Difference between deposit interest and borrow interest calculation rule. #819

Closed nzhl closed 1 year ago

nzhl commented 1 year ago

The code shows that when calculating the liquidity index calculateLinearInterest is used but in the case of borrow calculateCompoundedInterest is used. After a little googling, i found the closed issue #702

image

But i am still quite comfused, since "the interest is linear in the supply side and compounded in the debt side", where did the extra compounding interest part go?

I tried to find the answer from aave doc but failed.

miguelmtzinf commented 1 year ago

@nzhl There is no extra compounding interest. Interest get computed based on rates and liquidity rate is calculated from the borrow rate. You can check the implementation at DefaultReserveInterestRateStrategy.

nzhl commented 1 year ago

Yes, it's true liquidity rate is calculated from the borrow rate. But when calculating the borrow index based on borrow rate, compounding is involved but that's not the case for liquidity index. (notice the calculateLinearInterest and calculateCompoundInterest )

They should calculated in the same rule IMO. Did I miss something?

miguelmtzinf commented 1 year ago

They should calculated in the same rule IMO. Did I miss something?

Why? The linear and interest compounding is used just as a way to accumulate the interest. The accumulation depends on the rates, and one rate is based on the other so there is no excess or diff between them.

nzhl commented 1 year ago

Considering the following case:

  1. Init a new lending pool,
  2. User A supply 100 ETH
  3. User B borrow 50 ETH
  4. let's say borrow rate is 30%, reserve factor is 5%. Since usage ratio is 50%, we have liqudity rate 30% 50% (1-5%)= 14.25% right ?
  5. a year later after B's borrow, borrow index should be (1.3 / (365 24 3600) + 1) * (365 24 * 3600) = 3.669 (calculateCompoundInterest),
  6. so B should repay 50 * 3.669 = 183.45, in which 133.45 is the interest accumulated
  7. for A, liquidity index = 1.1425, A can receive 100 * 1.1425 = 114.25 (calculateLinearInterest), in which 14.25 is the intereset accumulated
  8. for the pool, reserve factor is 5% percent, accumulated interest should be 100 30% 50% * 5% = 0.75
  9. Now B repay all and then A withdraw all, 133.45 - 14.25 - 0.75 = 118.45 left in the pool which does not belong to anyone.

I am sorry maybe i misunderstood the code or ignored some significant details. The above is basically what i am struggling about.

eboadom commented 1 year ago

@nzhl some design/architectural tips that maybe will help you to visualize the system:

nzhl commented 1 year ago

I think the "intra-action interest" is what i am seeking for. The more ppl interact with the contracts with less diff there will be between borrow and supply. Big thx to @eboadom @miguelmtzinf , you guys are very nice šŸš€

jfzhou5 commented 1 year ago

@nzhl Nice for this issue

NicolaBernini commented 9 months ago

Hi everybody, I have a question regarding

Both supply and borrow indexes are actually compoundedĀ inter-actionsĀ (check hereĀ https://github.com/aave/aave-v3-core/blob/master/contracts/protocol/libraries/logic/ReserveLogic.sol#L301), but one is linear (supply) and the other compounded (borrow)Ā intra-action.
https://github.com/aave/aave-v3-core/issues/819#issuecomment-1457716858

Just to clarify, does that mean that both the supply and the borrow liquidity indexes are updated using compounded interests "inter actions" ?

With "actions" I am assuming you mean an action that changes the rate and therefore require a liquidity index update so supply, borrow, withdraw and repay

I am asking because I looked into the code and could not find where this happens: I see the supply liquidity index always updated with linear interests and the borrow liquidity index always updated with compounded interests

Let me share my analysis so you can double-check it

So the Pool.borrow() is defined here https://github.com/aave/aave-v3-core/blob/6070e82d962d9b12835c88e68210d0e63f08d035/contracts/protocol/pool/Pool.sol#L219

It calls BorrowLogic.executeBorrow() here

https://github.com/aave/aave-v3-core/blob/6070e82d962d9b12835c88e68210d0e63f08d035/contracts/protocol/libraries/logic/BorrowLogic.sol#L67

which internally calls reserve.updateState(reserveCache); here

https://github.com/aave/aave-v3-core/blob/6070e82d962d9b12835c88e68210d0e63f08d035/contracts/protocol/libraries/logic/BorrowLogic.sol#L77

It is defined in ReserveLogic.updateState() here
https://github.com/aave/aave-v3-core/blob/6070e82d962d9b12835c88e68210d0e63f08d035/contracts/protocol/libraries/logic/ReserveLogic.sol#L93

internally it calls _updateIndexes(reserve, reserveCache); here
https://github.com/aave/aave-v3-core/blob/master/contracts/protocol/libraries/logic/ReserveLogic.sol#L103

It is defined in ReserveLogic._updateIndexes() here
https://github.com/aave/aave-v3-core/blob/6070e82d962d9b12835c88e68210d0e63f08d035/contracts/protocol/libraries/logic/ReserveLogic.sol#L285

This function updates 2 liquidity indexes for the reserve of a specific token

https://github.com/aave/aave-v3-core/blob/6070e82d962d9b12835c88e68210d0e63f08d035/contracts/protocol/libraries/logic/ReserveLogic.sol#L292-L301

the reserve.variableBorrowIndex that represents the variable borrow rate, representing the accrued interests the borrower has to pay and the implementation is here
https://github.com/aave/aave-v3-core/blob/6070e82d962d9b12835c88e68210d0e63f08d035/contracts/protocol/libraries/logic/ReserveLogic.sol#L303-L317

so as you can see the first index is updated with linear interests while the second index is updated with compound interests which seems quite weird since the documentation says the linear update should not be written in storage as they should both compound

The view methods seem aligned with the doc since the getNormalizedIncome() here

https://github.com/aave/aave-v3-core/blob/6070e82d962d9b12835c88e68210d0e63f08d035/contracts/protocol/libraries/logic/ReserveLogic.sol#L47

returns the supply side income and the getNormalizedDebt() here

https://github.com/aave/aave-v3-core/blob/6070e82d962d9b12835c88e68210d0e63f08d035/contracts/protocol/libraries/logic/ReserveLogic.sol#L71

returns the debt side amount using compound interests