# Aave v3源代码解析 **Published by:** [egret](https://paragraph.com/@egret/) **Published on:** 2022-09-28 **URL:** https://paragraph.com/@egret/aave-v3 ## Content aave是一个分布式的借贷协议,提供固定利率、浮动利率的抵押借款,更创新性地推出了无抵押的闪电贷功能,衍生出了很多的Defi应用场景。 我们从aave的核心智能合约代码库aave-v3-core来解析一下这些功能是如何实现的。代码梗概IPool定义了aave借贷池的接口,下面是借贷池的核心方法。 supply(提供流动性): 用户向aave协议的某个资产储备(reserve)存入token提供流动性,得到对应的aToken作为存储凭证,比如存入USDC,将得到aUSDC。 setUserUseReserveAsCollateral: 用户更新某种资产的抵押逻辑。 borrow(借款): 用户基于在平台的抵押物价值或他人授信额度(通过debt token表示)借出对应的资产。 withdraw: 用户提现。 repay: 用户偿还借款。 flashLoan: 用户进行无抵押借款,并在同一区块偿还借款和手续费。 liquidationCall: 清算不健康的借款。逻辑详解这一部分我们来分析各个核心方法的内部逻辑 supply更新资产状态,包括liquidityIndex、variableBorrowIndex、lastUpdateTimestamp,累计资产总量检查资产储备中资产量是否达到上限更新资产相关利率,包含LiquidityRate(流动性利率)、StableBorrowRate(固定借款利率)、VariableBorrowRate(动态借款利率)转入用户的资产token到对应的aToken地址铸造aToken到用户地址setUserUseReserveAsCollateral检查用户存款状态和对应资产状态设置资产为抵押物检查用户在当前资产是否处于隔离模式设置资产为抵押物取消资产为抵押物取消资产为抵押物检查取消后用户在当前资产的healthFactor和LTV是否符合要求borrow更新资产状态检查是否满足借贷条件资产是否Active,是否Paused,是否Frozen,是否borrowingEnabled预言机是否设置了允许借贷计息模式检查借款总额是否超过借款上限,借款总额=固定利率总借款+动态利率总借款+当前请求借款资产隔离(isolation)模式:检查资产是否是可借款状态(borrowableInIsolation),隔离模式总债务是否小于隔离模式总债务上限用户EModeCategory不为空:检查资产的EModeCategory是否和用户的一致计算总抵押物价值,检查是否大于0当前LTV是否大于0healthFactor(用户总抵押物/总债务)是否大于阈值(1)需要的抵押物(用户总债务+需要借款金额)/所有资产平均LTV,是否小于用户当前的总抵押物价值固定利率借款:借款金额是否小于当前资产剩余可借金额稳定利率借款:mint稳定债务token到用户地址动态利率借款:mint动态债务token到用户地址更新资产相关利率转出资产token到用户地址withdraw更新资产状态检查用户持有的aToken是否足够覆盖请求提现的金额更新资产相关利率销毁用户持有的aToken转出资产token到用户的地址repay更新资产状态检查是否满足还款条件(对应利率模式的债务大于0)销毁对应债务的debtToken(StableDebtToken、VariableDebtToken)更新资产相关利率使用aToken还款:销毁对应的aToken使用原始资产还款:将资产token转到对应的aToken合约地址flashLoan检查请求借款的每个资产的状态设置IFlashLoanReceiver对象(如果要使用闪电贷功能,调用方需要实现IFlashLoanReceiver接口)计算当前闪电贷请求借款的所有资产的费用将用户请求借款的资产转到用户地址回调用户自定义的智能合约逻辑如果调用者选择在同一区块还款(interestRateMode == InterestRateMode.NONE),处理还款逻辑计算给aave协议的费用计算给流动性池的费用更新资产状态更新资产相关利率将本金和所有费用转到资产对应的atoken地址如果调用者选择不返还资产,将执行一次借款逻辑,生成一笔债务,并向调用者发放debtToken( opens a debt position)liquidationCall更新债务资产状态计算用户的healthFactor计算用户总债务、动态利率债务、可清算债务额(healthFactor>0.95时为50%,小于等于0.95时为100%)检查清算调用是否满足条件抵押物和债务资产是否为active和paused的预言机是否设置为允许清算healthFactor是否小于1清算阈值是否大于0,用户是否允许抵押用户是否有债务计算可被清算的抵押物actualCollateralToLiquidate:实际被清算抵押物,当目标清算抵押物价值小于债务价值时为全部抵押物,如果抵押物大于债务价值时,为债务值加清算奖励(bonus),如果有平台手续费,需减去手续费actualDebtToLiquidate:实际被清算债务,当目标清算抵押物价值小于债务价值时为全部抵押物价值减去清算奖励,如果抵押物大于债务价值,为清算债务值liquidationProtocolFeeAmount:付给aave协议的费用消除债务,销毁用户债务token,优先销毁动态利率债务,再销毁固定利率债务更新债务资产利率如果用户设置债务资产为隔离模式,更新隔离债务如果清算者接受aToken,清算用户的aToken,将用户作为抵押物的aToken转到清算者地址如果清算者不接受aToken,销毁aToken,将抵押资产原始token转到清算者地址划转清算费用到aave清算费用地址从清算者地址转出债务资产token(actualDebtToLiquidate)到对应aToken地址核心机制核心模块 上一部分我们分析了各个核心业务方法的内部逻辑,对支撑这些功能的基础实体模块也有了一个初步了解,下图是aave的核心模块和相互之间的关系。aave协议核心模块reserve对应着aave支持的每一种资产,每个reserve又会衍生出来三种token:aToken、stableDebtToken、variableDebtToken,分别用来记录用户在该资产提供的流动性、稳定利率债务和动态利率债务。基于这几个token,可以算出用户的healthFactor,用户的借款、提现、清算动作能否执行都要基于healthFactor去做判断,是用户在与协议交互过程中的关键风控变量。 流动性的利息如何计算 在aave协议中,主要通过liquidityIndex变量来实现流动性计息。 首先我们来看一下它的计算方式: liquidityIndex = cumulatedLiquidityInterest * lastLiquidityIndex cumulatedLiquidityInterest = currentLiquidityRate * durationSinceLastUpdate / secondsPerYear + 1 具体aave又是如何通过liquidityIndex来实现计息的呢? 当用户提供数量为amount1的流动性时,aave会为用户铸造对应的aToken,具体的铸造数量为:amount1 / currentLiquidityIndex 当过了一段时间,用户去提取amount2数量的资产时,aave会销毁对应的aToken,并将资产转给用户,具体销毁的aToken数量为:amount2 / currentLiquidityIndex 单独观察这两个式子,可能无法理解具体的计息逻辑,这里我们设提供流动性时的liquidityIndex为oldLiquidityIndex,经过的时间为t0,基于上面两个式子可以得出,经过t0时间以后,aToken的价值为: amount1 * currentLiquidityIndex / oldLiquidityIndex = amount1 * (currentLiquidityRate * t0 / secondsPerYear + 1) * oldLiquidityIndex / oldLiquidityIndex = amount1 * (currentLiquidityRate * t0 / secondsPerYear + 1) 这就是我们一般意义上的利息计算公式,当跨越多个时间段或利率变化多次时,我们只需再乘几次(currentLiquidityRate * t / secondsPerYear + 1),该机制依旧有效。 ## Publication Information - [egret](https://paragraph.com/@egret/): Publication homepage - [All Posts](https://paragraph.com/@egret/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@egret): Subscribe to updates