aave v3 存款与借款利息的计算方式
本文只涉及到利率计算的数学原理,不作源码解析:
存款
首先我们假设小明在aave里面存了10000usdt,存的时候年化收益率是5%,那么半年后其存款的利息是多少呢?常规的计算方式如下:
利息=10000*5%*(存款的时长/一年的时长)
这么做有什么问题呢?假设现在的存款利率有变化,存的时候是5%,过了两个月变成了6%,那么现在到了第6个月用户提款的时候其利息就会变为:
利息=10000*0.05*(2/12)+10000*0.06*(4/12)
如果利率多变动几次,分步计算的数量会更多,并且需要把用户存款的时间点,以及每次利率变化的时间点和当时对应的利率记录下来,这样才能完整的计算利息。
aave的利率本身是动态的,每次有人存款,取款,借贷,还款都会触发利率的变化,如果把这些都记录下来的话对于智能合约来说是个很大的负担,不仅耗费存储量空间,在最终结息时候的计算量也是巨大的,随着合约的运行,其gas费用会越来越高!
liquidityIndex
aave使用了引入流动性指数这个参数来解决这个问题,aave中存储的每一种资产都有一个liquidityIndex的变量记录储备资产的累积流动性增长率。
一个用户最终的结息金额和三个条件相关:本金,储蓄时间,利率。实际上我们的期望是不管我存了多长时间,结息的时候乘以存款的最终利率是就好,打个比方在利率不变的情况下,年化利率5%,5%/12就是每个月的利率,存半年的最终利率就是5%/12*6=2.5%,那如果每个月利率都在变的情况下最终利率怎么算呢,按照上面的举例前面两个月是5%,后面4个月是6%,半年后取款的最终利率是多少(aave对利率计算的时间精确到秒,这里方便说明使用月代替),计算方式如下:
把时间作为权重,乘以相应的利率在累加就是最后的利率。结息的时候用本金乘以最终的利率就可以得到最后的利息金额。
这意味着每一种资产只需要记录3个值,当前的利率(currentLiquidityRate);上一次更新利率的时间戳(lastUpdateTimestamp);从存款开始到上一次更新利率所累计的总利率(liquidityIndex)
liquidityIndex的初始值为1,代表尚未产生任何利润,lastUpdateTimestamp就是存款发生的时间,随着时间的推移,liquidityIndex的值会逐渐变大,因为每时每刻都在累积利息,但其并不会被更新,直到发生了利率变化,比如当前资产发生了存取,借贷,资金池的金额发生变化就会促使利率发生变化。这个时候就会发生liquidityIndex的累加,还是用上面的例子,前面两个月利率是5%:
后面4个月利率是6%则:
如果此时取款,直接用本金乘以liquidityIndex就可以得到本息的金额。
scaledBalance
细心的同学此时可能会有个疑问,上面的例子阐述了一种资产一个用户进行储蓄时的利息计算,如果有多个用户在不同的时间点存入金额,只用一个公共的liquidityIndex,如何精准计算每个人的利息呢?这就涉及到scaledBalance参数的应用,前面说到影响最终利息的三大要素本金,储蓄时间,利率,scaledBalance这个参数就是本金的变种,每个用户都会存储一份。接着上面的示例,假设现在的liquidityIndex已经从最初的1变成了1.01,那么是不是我存入10000立马就能取出10100出来呢,显然是太美好的想象,实际上每个用户存入资金的时候都会根据当前的liquidityIndex对本金进行换算,得到scaledBalance。比如此时的liquidityIndex为1.01,存入10000元,换算出的scaledBalance为10000/1.01=9900.99,真正计算本息的时候是用scaledBalance*liquidityIndex,所以存入立刻取出是不可能有任何利润的。
最后我们用示例总结下上面的内容:
场景:三个用户在不同时间存款
时间线
T0: liquidityIndex = 1.0, Alice 存入 10,000 USDC
T6: liquidityIndex = 1.025, Bob 存入 5,000 USDC
T12: liquidityIndex = 1.051, Charlie 存入 8,000 USDC
T18: liquidityIndex = 1.078, 查询所有用户余额
计算过程
Alice:
- scaledBalance = 10,000 ÷ 1.0 = 10,000
- 最终余额 = 10,000 × 1.078 = 10,780 USDC
- 利息收入 = 780 USDCBob:
- scaledBalance = 5,000 ÷ 1.025 = 4,878.05
- 最终余额 = 4,878.05 × 1.078 = 5,258.54 USDC
- 利息收入 = 258.54 USDCCharlie:
- scaledBalance = 8,000 ÷ 1.051 = 7,611.80
- 最终余额 = 7,611.80 × 1.078 = 8,205.52 USDC
- 利息收入 = 205.52 USD
借款
有了存款利率的原理做基础,理解借款利率的原理就很容易了,相应的借款最终利息的三要素借款金额,利率,时间,借款也有自己的变量存储随时间不断变大的累计利率variableBorrowIndex和经过转换后的借款金额scaledDebt,计算方式和存款的利率如出一辙。
总还款金额=variableBorrowIndex*scaledDebt