Aave V2 逻辑整理

  • nilliol
  • 更新于 2024-06-30 22:07
  • 阅读 1033

Aave就相当于去中心化交易所中的一个银行,在其中用户可以进行一系列的资金操作,下面从其两个主要的功能阐述:借贷、存款。借贷在Aave中借贷有两种方式:借款(有抵押物的)、闪电贷(无抵押物的)。闪电贷AaveV2的闪电贷感觉没有什么特别的地方,就是在一个区块交易内完成借出和还入两个

Aave 就相当于去中心化交易所中的一个银行,在其中用户可以进行一系列的资金操作,下面基于行为的角度对其两个功能进行阐述:借贷、存款。

借贷

在 Aave 中借贷有两种方式:借款(有抵押物的)、闪电贷(无抵押物的)。

闪电贷

Aave V2 的闪电贷感觉没有什么特别的地方,就是在一个区块交易内完成借出和还入两个操作。

  function flashLoan(
    address receiverAddress, // 借款受益人地址
    address[] calldata assets, // 借款代币地址(数组)
    uint256[] calldata amounts, // 借款数量(数组)
    uint256[] calldata modes, // 借款模式(数组)
    address onBehalfOf, // 还款人地址
    bytes calldata params, // 入参编码
    uint16 referralCode // 推荐码
  ) external override whenNotPaused {

查看 Aave V2 的代码(参考上述的函数头),我们可以知道,Aave V2 允许一次性借出多种贷款(assets是个数组),并且允许选择模式(由modes决定,不同资产可以选择不同模式),有:闪电贷模式(0,正常闪电贷)、借款模式(1,普通的借款,采用稳定利率;2,普通的借款,采用浮动利率)。

对于每一笔贷款(无论哪种模式) Aave V2 都会先转出借款费用、计算手续费,然后再根据模式进行判断:

  • 闪电贷:从贷款者处(receiverAddress)转账还款(借款+手续费
  • 借款模式:执行借款的函数逻辑

总的来说,Aave V2 在闪电贷种添加了一个转入正常借贷的机会,可以将闪电贷、正常借贷合并在一笔交易中。

借款

关于借款,就开始麻烦起来了,借款可以分为三个部分:借款(借钱这件事)、还款(还钱这件事)、清算(清算合约中不良借款这件事)

清算

我们首先来看看清算这件事。由于区块链中没办法轻易的溯源到账户拥有者本人,所以对于合约中每一笔借款都不能有坏账(借出款的价值大于抵押物的价值)这件事发生合约就会不被信任了。

我们知道合约对于借款策略采用的是超额抵押借贷(如抵押 100$价值的抵押物,借贷的钱不能到达 100$ 那么多,可能只有 50$),所以可以设定一个阈值(抵押物价值/所欠金额),到达一定比值后资产就会被清算(合约自动卖出抵押物,借款人就不用还款了)。

那么这个清算阈值是怎么确定的呢?Aave V2 定义了一个健康系数(HealthFactor),当其小于 1 时,该笔交易就可以清算。那么这个HealthFactor如何定量呢?

$$ HealthFactor = \frac{TotalCollateralInETH * LiquidationThreshold}{TotalDebtInETH} $$

首先分母TotalDebtInETH表示:总共的债务量(借款 + 利息,但在实际中只会计算债务量,因为 Aave V2 采用的是利滚利模型)。分子TotalCollateralInETH表示:借款人抵押物的总价值(以ETH为单位)。分子LiquidationThreshold表示:该种资产设定的阈值(一个百分比,例如75%)。

分子两者相乘,得到当前抵押物能借出金额上限,分母表示当前借出的债务。分子受市场波动影响,抵押物价值下降,HealthFactor就有可能逼近 1 了,而TotalDebtInETH由于债务利率的存在,会不断的上涨,也会让HealthFactor逐渐的逼近 1 。

清算具体会发生什么呢?当用户抵押了价值 200 $的抵押物,借出了 100 USDT,此时清算阈值是 75%,那么抵押物的价值如果下跌,最多跌倒133.3(用 100 / 0.75 得到,并且忽略利息对健康系数分母的影响),一旦跌倒这个价格之下,那么清算开始发生。

此时有一个清算人负责清算该资产,它可以清算该笔资产的一部分(用户自己决定,但有上限,由 Aave V2 决定,其不允许一次性清算完全部抵押资产),Aave V2 将对抵押物折价卖出,清算人付出借出债务的代币(0%~Aave V2 规定的上限 50%),以当前折扣价买入被清算的抵押物((市场价/代还款)*(1+奖励比例),其中奖励比例就是清算人比起在正常市场中购买代币,在 Aave V2 清算中能额外获得的利润)。此时借款人的健康系数受到影响,变得健康:以上清算行为相当于 Aave V2 自动帮借款人卖出一部分抵押物,来偿还借款(略低于市场价,但高于阈值 * 市场价,因此可以提高健康系数)。

如何发起清算呢?合约由于不能说根据触发条件自动执行函数,所以需要外部的套利者不断的巡视整个市场,发现这些可以清算的交易,对于到达清算线的交易,所有人都可以对其进行清算。清算过后:套利者获得一定利润(通过奖励比例),合约避免了坏账的诞生,维护了市场的稳定。

借款

Aave V2 对于借款人的债务进行了token化,即债务就是一个个的代币。首先有一个问题:债务是token那么转移token是不是就不用还钱了。理论是这样的,但是 Aave V2 将transfer函数重载了,调用后就会revert,所以是没办法转移债务的。

然后就是如何借款了。在 Aave V2 中借款有两种:稳定利率债务、可变利率债务。前者利率固定,借钱时利率是多少,后面利滚利时利息就一直是多少(也有可能调整,如借钱时固定利率和当前利率差距过大);后者利率不固定,随着市场波动,借钱的人多(资金池使用率高),利率就高,人少,利率就低。

当我们想统计t时刻债务总量即:$D^{asset}_t = SD_t(稳定利率债务) + VD_t(浮动利率债务)$,而借款关系到存款利率问题(借款为合约赚取收入,收入分配给存款用户,实现银行的基本功能)。

浮动利率债务

浮动利率虽然浮动(会因为资金池利用率而改变,利用率高,浮动利率就该,反之变低),但是其计算实现反而更加简单。Aave V2 对于每一笔可变债务都首先放缩到0时刻(创世时间)然后利用一个变量存储累计可变债务指数,从而统计出用户当前总可变债务(仅浮动利率债务部分)。

首先理解这个放缩(scaled),它将当前借出的债务换算到创世时间时(即假设你这笔债务在创世时间时借出),假设现在是 $t_1$ 时刻,从 $t_0$ 时刻(创世时间)到当前的累计可变债务 $VN_t^{asset}$ 为 200%(假设创世初借款100,现在 $t_1$ 就需要还200了),那么用户借出 1000 $ 相当于创世初时借了 500 $。上述这个 1000 到 500 的过程就是放缩。

然后就是这个累计可变债务指数 $VN_t^{asset}$ 又是如何确定的呢?白皮书中的定义是:

$$ V N_t = (1 + \frac{V Rt}{ T{year}} )^{ ∆T} *V I_{t−1} $$

下面介绍公式中的每个变量的定义,首先是 $VRt$ 表示的是:当前浮动利率(这种当前利率放到最后阐述,先默认已知),即当前所有浮动债务所需要每秒支付利息的利率,这个利率是年华利率。$T{year}$ 表示:一年的秒数(固定值),配合其分子进行除法运算,即可得到每秒的利率。$\Delta T$ 表示:前后两次操作发生之间的间隔时间,这个操作包含借出、存入、取出、偿还、交换、清算。$VI_{t-1}$ 表达的含义应该与 $VN_t^{asset}$ 一样(我认为的),因为两者白皮书上定义公式一致:

$$ V I_t = (1 + \frac{V Rt}{ T{year}} )^{ ∆T} *V I_{t−1} $$

而其初始值应该为 1 ,然后随着用户不断的操作使得这个变量单调递增。每当我们借出一笔价值为 m 的债务,然后合约进行放缩得到债务值$\frac{m}{VN_t} $ ,然后加上过去放缩到创世时间的债务(这种方式方便合约计算债务,只需要改变这个累计值,不然浮动利率不断变动,每次操作都要遍历所有债务计算新的债务,又或者记录每次利率变化,gas消耗太大):

$$ ScVB{t}(x) =ScVB{t-1}(x) + \frac{m}{VN_t}
$$

当我们想知道当前债务到底是多少时,也很容易计算(其中 $x$ 指某个用户,$VN_t$ 在白皮书中为 $D_t$,查了下资料说可能是白皮书排版错误,$D_t$ 表示放缩后总债务,包含了浮动和固定的):

$$ V D(x) = ScV B(x) * VN_t $$

对于开头的 $SD_t$ (浮动利率债务)的计算就是所有用户的 $VD(x)$ 的总和了。

稳定利率债务

对于稳定利率,其计算方法就不一样了。首先需要明确,稳定利率债务不是说借贷利率恒定不变(非硬编码在合约中),而是在计算复利(利滚利)时,利率固定下来,不会因为资金利用率(合约中资金使用程度)而改变,当然当前稳定利率还是会不断改变的。

那么借出一笔稳定利率的债务是怎么进行的呢?在 Aave V2 中记录的是用户的平均稳定借款利率和稳定借款债务,通过两者即可计算当前债务量。

为什么要计算平均稳定借款利率呢?如果使用平均稳定借款利率,那么统计债务的时候就需要遍历每一笔稳定利率借款,而且每一笔债务都需要单独的存储,这都会需要大量的gas,而采用平均稳定利率,那么对于每个用户想要得到当前时刻的债务 $SD_t(x)$,需要存储的就变为,用户所有债务的平均稳定利率 $\overline{SR_t}$ 和稳定利率债务总量 $SB(x)$:

$$ SD_t(x) = SB(x) * (1 + \frac{\overline{SRt}}{T{year}})^{\Delta T} $$

上述公式另外几个变量的含义都比较清楚,与浮动利率中的一致。那么上面的平均稳定利率这些变量是怎么确定的呢?首先是平均稳定利率 $\overline{SR_t}$ ,作为平均的利率,肯定是稳定利率平均而来,其公式为:

$$ \overline{SR_t} = \frac{SDt * \overline{SR{t−1}} + SB_{new} * SR_t}{SDt + SB{new}} $$

上述公式表示,当用户借出一笔新的资金 $SB_{new}$ ,在此时,资金池的稳定利率为 $SR_t$ ,而用户此前的稳定利率债务为 $SDt$ (不包含 $SB{new}$,并且个人觉得使用 $SD{t-1}$更加符合含义)此前的平均稳定利率为 $\overline{SR{t−1}} $。在初始和还清债务时,用户的 $SDt$ 和 $\overline{SR{t−1}} $ 均为 0 。如此,如果用户不断借钱,那么这个平均稳定利率就会不断靠近当前稳定利率。

在上面的几个公式中 $SD_t$ 和 $SB(x)$ 不断交替出现,其含义十分相似,都表示用户的稳定利率的债务,但还是有一些区别。对于 $SB(x)$ 其表示的存储于合约上的债务,即用户当前拥有的债务 token,而$SD_t(x)$ 更多的表示实际需要还给合约的欠款,从$SB(x)$ 到 $SD_t(x)$ 需要经过开头的那个公式。

还款

浮动利率还款

在前面我们知道,统计用户的浮动利率债务的时候用的是放缩后的债务 token,而还款也是一样,扣除的是放缩后的债务 token,以此保持浮动利率债务的统计。那么还款后应该扣除多少放缩后的债务 token 呢?这个逻辑和借款的逻辑相反,用户还款 $m$ 根据从创世到现在的累计可变债务 $VN_t^{asset}$ 即可得到新的债务:$ScVBt(x) = ScVB{t-1}(x) - \frac{m}{VN_t}$。

稳定利率还款

稳定利率和浮动利率不同,没有这个放缩的过程,所以是计算当前实际欠款 $SD_t(x)$(利用借款中其定义公式),然后减去还款数额,并且重新计算平均稳定利率(分母不能为 0 所以分条件):

$$ \overline{SR_t} =\left { \begin{array}{} &0 &, if \space SDt − SB(x) = 0,\ &\frac{SDt * \overline{SR{t−1}} − SB(x) * SR(x)}{SD_t−SB_x} &,if \space SD_t − SB_x > 0 \end{array}\right. $$

存款

Aave V2中对于用户的存款也是采用放缩和 token 的方法存储用户的存款额度。首先是用户查看当前存款额度$aB_t(x)$(能取出多少钱):

$$ aB_t(x) = ScB_t(x) * NI_t $$

其中 $ScB_t(x)$ 正是用户放缩后的存款额度(同样是放缩到创世时间),而后面的 $NI_t$ 正是累计流动性指数,和借款里的累计类似,这是一个全局的变量(所有的存款共用):

$$ LI_t = (LRt * \Delta T{year} + 1 ) LI_{t-1} \ LI_0 = 1 10^{27} = 1 \space ray $$

上面阐述了这个累计指数的初始值和后续的变化方法,而其中的 $LR_t$ 是指当前的流动性(一个随着每次资金池操作而改变的值)。在上面我们看到了这个累计流动性指数也是和可变债务指数一样,在不断的单调递增,利用放缩到创世初的存储金额两者结合计算当前存款。

当用户新存入一笔存款 m 也是放缩到创世初,然后两个相加,取款类似(具体是按照取款额度还是放缩后的代币额度需要后续看源码):

$$ ScBt(x) = ScB{t-1}(x) + \frac{m}{NI_t} $$

利率变化

在上述的各种操作,我们可以知道 Aave V2 其实挺像一个银行了,利用用户的存款进行出借,赚取借贷的利息,然后将利息作为存款的利息发放给存款用户,实现存款获得利息,借款付出利息(虽然是超额抵押借贷)。

但还有一个问题,上述的三个实时利率(当前稳定利率、当前浮动利率、当前流动性率)都是如何确定的呢?首先明确影响这些利率的因素:资金池使用率(使用率越高,借贷的利率理所当然的会更高,反之降低)。

基本上说所有的操作都会影响这个,然后影响其他:借款拉高、还款降低、存款拉低、取回拉高。同时借贷的利息越多,用户存款所得到的利息才会高(存款利息的来源就是借贷的利息)。

首先明确借款的当前利率如何确定:

$$ #R^{asset}_t = \left { \begin{align*}

&#R^{asset}_{base} + \frac{U^{asset}t}{U^{asset}{optimal}}

  • #R^{asset}_{slope1} , if \space U^{asset}t < U^{asset}{optimal} \ &#R^{asset}{base} + #R^{asset}{slope1} + \frac{U^{asset}t −U{optimal}}{1−U{optimal}} * #R^{asset}{slope2}, if \space U^{asset}{t} ≥ U{optimal}

\end{align*} \right. $$

我们知道借款分为浮动和稳定,而上述公式同时适用于两种,将其中的 $#$ 替换成为VS即表示浮动和稳定两种。上面的式子表达的意思是:利率从 $#R^{asset}_{base}$ (由管理员设置)开始起步计算(相当于起步价),根据当前的资金使用率 $U^{asset}t $ (总债务/总储蓄)判断,如果小于最佳借款使用率 $U^{asset}{optimal}$(由管理员设置),基础利率加上对应比例slope1(由管理员设置)的利率($\frac{U^{asset}t}{U^{asset}{optimal}} #R^{asset}{slope1}$)。超过最佳借款使用率 $U^{asset}{optimal}$ 就在基础利率和slope1利率的和上,根据超过对应比例的slope2(由管理员设置)的利率($\frac{U^{asset}t −U{optimal}}{1−U_{optimal}} #R^{asset}_{slope2}$)递增。

而存款利率(即流动性利率),理所当然的根据债务所产生的利息决定:

$$ LR_t = \overline{R_t} * U_t $$

其中 $U_t$ 是资金池的使用率,$\overline{R_t}$ 是总体借款利率,总体借款利率通过计算浮动债务和稳定债务的得到:

$$ \overline{R_t} =\left { \begin{align} &0, if \space D_t = 0 \ &\frac{V D_t V R_t+SD_t \overline{SR_t}}{D_t} , if \space D_t > 0 \end{align}\right. $$

参考文章

AAVE v2 - white paper

AAVE V2 学习笔记

Dapp-Learning: AAVE

  • 原创
  • 学分: 59
  • 分类: DeFi
  • 标签: Aave 
点赞 2
收藏 2
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
nilliol
nilliol
0xbe3e...29A9
web3 的学习者,寻找实习机会中。 博客地址:https://llwh2333.github.io