AAVE-v3
AAVE v3.3.0解读
一. 概念基础
1.1 什么是Isolation Mode
1.1.1 什么是隔离资产(Isolated Assets)?
在AAVE V3中,“隔离资产”不是指某一种特定的代币(如ETH或USDC),而是指一种特殊的风险配置模式。
简单来说,任何一个常规的资产(如ETH、WBTC、USDC)都可以被协议管理员设置为在“隔离模式”下使用。 当一种资产被标记为“隔离资产”时,它只能被用作独立的、与其他资产风险隔离的抵押品。
1.1.2 核心特性
- “Isolated assets have limited borrowing power” (隔离资产的借贷能力有限)
- 为了防止高风险资产崩溃时拖累整个协议,隔离资产有一个预设的、较低的贷款价值比(LTV)。例如,普通模式的ETH LTV可能为80%,而隔离模式的某个高风险代币的LTV可能只有30%或更低。
- 这意味着,你存入价值100美元的隔离资产,最多只能借出30美元(或其他限额)的其他资产,借款能力被严格限制。
- “and other assets cannot be used as collateral.” (其他资产不能作为抵押品)
- 这是隔离模式最关键的风险隔离设计。你只能使用你指定的那一种(或几种)隔离资产作为抵押品。
- 你账户里的其他非隔离资产(如普通的USDC、ETH存款)不能被计入抵押品价值,也不能被用于清算。 它们就像被放在一个完全独立的“保险箱”里,不受隔离仓风险的影响。
1.1.3 为什么要设计“隔离模式”?
这是AAVE V3一个重大的创新,主要目的是:
- 安全地引入高风险资产:允许用户使用波动性大、流动性相对较差(长尾资产)的代币作为抵押品,而不会将这些高风险传染给协议的核心、稳定的资产池。如果这个隔离资产价格暴跌,其风险被限制在“隔离仓”内。
- 保护用户其他资产:对于借款人来说,这提供了更好的风险管理。你可以用一个高风险资产去尝试高杠杆操作,即使这个仓位被清算,你其他的存款和投资仍然是安全的,不会被波及。
- 提高资本效率:对于保守用户,他们可以放心地将稳定币存入主池赚取利息,而无需担心这些存款会因为别人炒作某个小币种而被清算。
1.1.4 与普通(交叉抵押)模式的区别
| 特性 | 普通(交叉抵押)模式 | 隔离模式 |
|---|---|---|
| 抵押品 | 所有被启用作抵押的资产都可以共同作为抵押池。 | 仅限于指定的一种或几种隔离资产。 |
| 风险 | 所有抵押资产暴露在风险中,一个资产暴跌可能引发连锁清算。 | 风险被隔离。只有隔离仓内的资产有风险。 |
| 借贷能力 | 基于所有抵押资产的总价值乘以各自的LTV计算,通常较高。 | 受到严格限制,只有隔离资产的较低LTV。 |
| 目的 | 适用于主流、低风险资产,追求资本效率和便利性。 | 适用于尝试高风险资产或进行特定策略,同时保护主账户资产。 |
1.2 什么是 E Mode
E-Mode是AAVE V3引入的“效率模式”(Efficiency Mode)
| 特性 | 效率模式 (E-Mode) | 隔离模式 (Isolation Mode) |
|---|---|---|
| 设计目标 | 提升资本效率,最大化借款能力。 | 隔离风险,防止高风险资产波及系统。 |
| 适用资产 | 价格高度相关的资产,如稳定币之间(USDC/USDT)或同类资产(ETH与stETH)。 | 新上线的、波动性高、风险较高的资产(如某些长尾代币)。 |
| 核心机制 | 大幅提高贷款价值比(LTV),允许借出更多资金。 | 严格限制LTV和借贷上限,只能借入指定的稳定币。 |
| 风险逻辑 | 因资产价格高度相关,抵押品和债务价值同向波动,清算风险被认为相对可控。 | 将高风险资产的债务限制在一个“围栏”内,防止其崩溃时拖累用户的其他资产或整个协议。 |
1.2.1 E-Mode 如何运作
你可以把E-Mode理解为一个可开关的“高效借贷档位”。当你开启一个特定的E-Mode类别(例如“稳定币E-Mode”)后:
- 更高的借款能力:你在此模式下的抵押品会获得一个远高于普通模式的LTV(例如,稳定币的LTV可能从80%提升至90%以上)。
- 借贷限制:你只能借入同一E-Mode类别内的资产。例如,在“稳定币E-Mode”下,你抵押USDC只能借出USDT、DAI等其他稳定币,而不能去借ETH。
1.3 APR 和 APY
这是一个非常核心的金融概念。简单来说:
-
APR(年化利率) 告诉你借钱的成本或不考虑复利的收益。
-
APY(年化收益率) 告诉你考虑复利后的实际收益。
-
特性 APR (年化利率) APY (年化收益率) 中文全称 年化百分比利率 年化百分比收益率 核心含义 借款的名义成本或贷款的简单利率。 存款或投资的实际收益,考虑了复利。 是否包含复利 不包含。只基于本金计算。 包含。利滚利,收益基于本金+已产生的利息。 计算复杂度 简单,线性计算。 复杂,指数计算。 主要应用场景 贷款(如信用卡、房贷、车贷),用于比较借款成本。 存款/投资(如储蓄账户、定期存款、加密货币质押),用于比较真实收益。 数值比较 对于同一产品,APY 通常高于或等于 APR。 复利越频繁(每天、每月),APY 比 APR 高出越多。
apr-apy
1.4 Market forces
1.4.1 borrow,supply interest rate和 utilization rate 和 protocol fee rate 的关系
market-forces
1.4.2 利用率 Utilization rate
utilization-rate
1.4.3 借款利率 borrow interest rate 和 利用率 utilization rate 的关系
interest-rate-model
有一个理想利用率阈值,如果超过这个阈值(例如图中的百分之80),借款利率会迅速上升。
1.5 Reserve (储备)
DataTypes.ReserveData 是 Aave V3 配置层的核心结构体。它完整定义了协议中某个储备资产(如 USDC、WETH)的所有关键状态和参数。
struct ReserveConfigurationMap { //bit 0-15: LTV //bit 16-31: Liq. threshold //bit 32-47: Liq. bonus //bit 48-55: Decimals //bit 56: reserve is active //bit 57: reserve is frozen //bit 58: borrowing is enabled //bit 59: DEPRECATED: stable rate borrowing enabled //bit 60: asset is paused //bit 61: borrowing in isolation mode is enabled //bit 62: siloed borrowing enabled //bit 63: flashloaning enabled //bit 64-79: reserve factor //bit 80-115: borrow cap in whole tokens, borrowCap == 0 => no cap //bit 116-151: supply cap in whole tokens, supplyCap == 0 => no cap //bit 152-167: liquidation protocol fee //bit 168-175: DEPRECATED: eMode category //bit 176-211: unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled //bit 212-251: debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals //bit 252: virtual accounting is enabled for the reserve //bit 253-255 unused uint256 data; }
| 字段 | 数据类型 | 核心意义与作用 |
|---|---|---|
| 核心会计与状态 | ||
| | 储备资产配置位图。使用位操作存储所有风险参数(如LTV、清算阈值、是否冻结、是否作为抵押品等)。 |
| | 流动性指数。核心复利因子,用于计算存款人的应计利息()。以 (1e27) 为单位,随时间单调递增。 |
| | 可变借款指数。用于计算浮动利率借款人的应计债务()。同样以 为单位。 |
| | 最后更新时间戳。记录此储备数据最近一次被更新的时间点,是计算两次操作之间应计利息的基础。 |
| | 虚拟底层资产余额。协议内部会计账本记录的理论资产总量,是计算利息和健康的基准。其关系为:。 |
| | 应计至国库的金额。累积但尚未划转给国库的协议收入(利差),以该储备资产的单位计价。 |
| 代币地址与ID | ||
| | aToken 合约地址。用户存款时收到的生息代币凭证。 |
| | 可变债务代币地址。用户进行浮动利率借款时产生的债务代币。 |
| | 稳定债务代币地址(已弃用)。自 V3.2.0 移除稳定利率后,此字段仅为保持存储槽兼容而保留。 |
| | 利率策略合约地址。指向计算该资产存款和借款利率的动态逻辑合约。 |
| | 储备资产ID。在协议内部活跃储备列表中的唯一位置索引。 |
| 利率 | ||
| | 当前流动性利率。基于资金池利用率和利率策略实时更新的年化存款利率,以 为单位。 |
| | 当前可变借款利率。实时更新的年化浮动借款利率,以 为单位。 |
1.6 aToken 和 Variable Debt Tokens
- AToken and debt token
区分Rebase Token(变基代币)和Non-Rebase Token(非变基代币)主要看代币的数量是否会自动变化。
| 特性 | aTokens | Variable Debt Tokens |
|---|---|---|
| 代表内容 | 你存入的资产及累积的利息。 | 你可变的浮动利率债务。 |
| 本质 | 生息存款凭证。 | 计息债务凭证。 |
| 代币数量 | 随时间增加,余额自动增长以体现利息收入。 | 随时间增加,余额自动增长以体现应付利息。 |
| 价值基础 | 与底层资产 1:1 锚定(1 aUSDC ≈ 1 USDC)。 | 与借入的债务 1:1 锚定。 |
| 主要功能 | 1. 实时赚取利息; 2. 可随时赎回或转账; 3. 可作为抵押品。 | 1. 实时计算应付利息; 2. 需偿还债务以销毁。 |
| Rebasing机制 | 余额自动增加(利息以代币形式发放)。 | 余额自动增加(应付利息以债务形式累积)。 |
1.7 计算借款复利 cumulative interest Rates
1.7.1 正常计算
AAVE-v3-计算借款利率
// Code 1 contract Bank { // user => debt mapping(address => uint256) public debts; // user => timestamp of last borrow mapping(address => uint256) public timestamps; // timestamp => rates (1 = 1e18) mapping(uint256 => uint256) public rates; function calculateDebt(address user) external view returns (uint256) { uint256 debt = debts[user]; uint256 k = timestamps[user]; uint256 n = block.timestamp; for (uint256 t = k; t < n; t++) { debt = debt * rates[t] / 1e18; } return debt; } }
1.7.2 优化公式来节省gas
计算借款利率2
计算借款利率3
// Code 2 contract Bank { // user => debt mapping(address => uint256) public debts; // R(n-1) uint256 public cumulativeRates = 1e18; // R(k-1) // user => cumulative rate when user borrowed mapping(address => uint256) public userCumulativeRates; function calculateDebt(address user) external view returns (uint256) { return debts[user] * cumulativeRates / userCumulativeRates[user]; } }
1.7.3 借取款量发生变化
AAVE-v3-计算借款利率4
// Code 3 contract Bank { // user => debt mapping(address => uint256) public debts; // R(n-1) uint256 public cumulativeRates = 1e18; function calculateDebt(address user) external view returns (uint256) { return debts[user] * cumulativeRates / 1e18; } function updateCumulativeRates() public {} function borrow(uint256 amount) external { updateCumulativeRates(); debts[msg.sender] += amount * 1e18 / cumulativeRates; } function repay(uint256 amount) external { updateCumulativeRates(); debts[msg.sender] -= amount * 1e18 / cumulativeRates; } }
1.8 Liquidity/Borrow Index(流动性/借款索引) 与 Scaled Balance/Debt(缩放余额/债务))
1.8.1 核心关系:全局基准与个人份额
| 概念 | 性质 | 作用 | 类比 |
|---|---|---|---|
| Liquidity/Borrow Index | 全局变量,每个借贷市场只有一个,随时间不断增长。 | 记录资金池总资产/总债务的复利增长基准线。 | 基金的总净值。 |
| Scaled Balance/Debt | 用户变量,在发生交互时才更新,通常保持不变。 | 记录用户存入或借出的本金,按存入时的索引进行“缩放”后的值。 | 你持有的基金份额。 |
| 用户实际权益/债务 | 计算结果 | 用户在任意时刻实际拥有或欠款的价值。 | 你的基金份额 × 当前基金净值。 |
1.8.2 核心公式
计算用户 Scaled Balance/Debt (存入/借款时) Scaled Balance = Underlying Amount Deposited / Liquidity Index at that time Scaled Debt = Underlying Amount Borrowed / Borrow Index at that time 计算用户实际权益/债务 (查询/赎回/还款时) User's Actual Balance = User's Scaled Balance × Current Liquidity Index User's Actual Debt = User's Scaled Debt × Current Borrow Index
- scaledBalance/Debt:这是系统为用户存储的核心内部记账值。在用户存入资产时确定,后续只有在用户发生新的存取款或借款时才会按比例更新。
- liquidityIndex(流动性指数):这是一个全局变量,代表资产池自创建以来,单位本金累计产生的复利。它随着时间推移和利息累积而不断单调递增。
代码:
mintScaleToken
这个函数在存款或借款时被调用,核心是增加用户的缩放代币余额。
function _mintScaled( address caller, address onBehalfOf, uint256 amount, uint256 index ) internal returns (bool) { //Scaled Balance 变化量 uint256 amountScaled = amount.rayDiv(index); require(amountScaled != 0, Errors.INVALID_MINT_AMOUNT); uint256 scaledBalance = super.balanceOf(onBehalfOf); uint256 balanceIncrease = scaledBalance.rayMul(index) - scaledBalance.rayMul(_userState[onBehalfOf].additionalData); //每次函数结束时都会用最新的 index 更新它,为下一次计算利息提供基准。 _userState[onBehalfOf].additionalData = index.toUint128(); _mint(onBehalfOf, amountScaled.toUint128()); uint256 amountToMint = amount + balanceIncrease; emit Transfer(address(0), onBehalfOf, amountToMint); emit Mint(caller, onBehalfOf, amountToMint, balanceIncrease, index); return (scaledBalance == 0); }
: 它代表从上一次用户交互到此刻,用户因指数增长而自动产生的应计利息(以实际代币计价)。balanceIncrease
:用户当前的Scaled Balance按最新指数折算成的最新总权益。scaledBalance.rayMul(index)
:用户当前的Scaled Balance按上次记录的指数折算成的上次权益。scaledBalance.rayMul(_userState[user].additionalData)- 两者之差
,就是在这段时间内新产生的利息。最新权益 - 上次权益
1.8.3 举例说明:
- 存入时刻:你存入1000 USDC,此时流动性索引为
。1.0- 协议为你计算:
Scaled Balance = 1000 / 1.0 = 1000 - 你获得1000个aToken(代表你的缩放余额),同时全局索引开始增长。
- 协议为你计算:
- 持有期间:你的
保持为1000不变,但池子的流动性索引因利息累积增长到Scaled Balance
。1.05 - 赎回时刻:你想取回资金。
- 协议读取你当前的
(1000)和当前的Scaled Balance
(1.05)。Liquidity Index - 计算你的实际权益:
。1000 × 1.05 = 1050 USDC - 你赎回1050 USDC,其中50 USDC是自动累积的利息。
- 协议读取你当前的
1.8.4 设计优点
这种将“不断增长的全局指数”与“相对稳定的个人缩放值”分离的设计,主要有两大精妙之处:
- 极致优化Gas成本:绝大多数时候,只有全局的
需要随着每个区块更新(增长)。所有用户的Index
都无需变动。仅在用户与协议交互时,才进行一次性的利息结算(用新旧索引差值计算)。这避免了传统模式中需要为每个用户每个区块更新余额的巨大Gas消耗。Scaled Balance - 确保公平与精确:所有利息分配都通过公开透明的链上数学公式完成。无论用户何时进出,其应得的利息都能通过索引的差值被精确计算,确保了绝对的公平性。
1.9 Reserve Factor(储备金因子,协议费用)
vars.currentLiquidityRate = vars .currentVariableBorrowRate .rayMul(vars.supplyUsageRatio) .percentMul(PercentageMath.PERCENTAGE_FACTOR - params.reserveFactor);
-
公式:流动性存款利率 = R_variable * U_supply * (1 - reserveFactor)
-
:协议费用率,从借款利息中扣除一部分作为协议收入,剩余部分才分配给存款人。因此存款利率总是低于借款利率。reserveFactor
1.10 MAX LTV 最大贷款价值比
借款上线:你最多能借出的资产价值占抵押品价值的最大百分比。超过此线则无法新增借款。
ltv
1.11 Liquidation threshold
当你的借款价值占抵押品价值的比例超过此线,头寸进入可被清算状态。
“清算阈值 > 最大LTV”的核心原因
这个设计主要基于两个关键考虑:
- 为清算人提供激励:清算发生时,清算人需要垫资偿还你的部分债务,并从你的抵押品中获取一部分作为奖励(包含清算激励)。如果清算触发线(清算阈值)和借款上线(Max LTV)设得太近甚至相同,清算人就没有足够的利润空间来覆盖其交易成本和风险,可能导致无人愿意清算,使协议暴露在风险中。
- 避免过度频繁清算:如果刚超过借款上限就立即清算,市场微小的波动就会引发大量清算事件,不仅损害用户体验,还可能在市场剧烈波动时加剧“毒性清算螺旋”。
liquidation-threshold
1.12 Health-factor
health-factor
二. 合约代码
2.1 代码框架
arc
2.2 Supply
2.2.1 调用逻辑图
supply代码流程图
1. reserve.updateState(reserveCache)
- 作用:更新储备金的状态,这是利息计算的触发点。它通过计算自上次交互以来经过的区块数量,调用
函数,将累积的利息更新到流动性索引(_cumulateToLiquidityIndex
)和借款索引(liquidityIndex
)中。这确保了在存款操作前,所有未计算的复利都已精确计入池子总账中。variableBorrowIndex
2. ValidationLogic.validateSupply(...)
- 作用:执行一系列安全检查,确保存款操作合法。主要包括:
:检查存款金额是否大于零。validateAmount
:检查目标市场是否处于激活(Active)状态,未被冻结(Frozen)或暂停(Paused)。validateSupply
:检查此次存款后,该资产的总供应量是否会超过协议设定的供应上限(Supply Cap),这是风险控制的重要一环。validateSupplyCap
3. reserve.updateInterestRatesAndVirtualBalance(...)
- 作用:在存款资产入账后,更新资金池的利率。它根据存款后的新资金利用率,通过利率策略合约计算出新的浮动借款利率。同时,它会更新储备金的
和liquidityAdded
等“虚拟余额”,这些变量主要用于管理跨链流动性,是AAVE V3的核心特性之一。liquidityTaken
4. 资产转移与记账
:将用户的资产从其地址安全地转移到该储备金对应的IERC20(params.asset).safeTransferFrom
合约地址。aToken
:这是关键记账步骤。IAToken(reserveCache.aTokenAddress).mint
合约的aToken
函数会:mint- 根据当前最新的
(由nextLiquidityIndex
计算得出),将用户存入的原始资产金额折算为updateState
。公式为:scaledBalance
。scaledBalance = amount / nextLiquidityIndex - 将折算后的
记在用户名下,并给用户铸造相应数量的scaledBalance
凭证。aToken - 返回一个布尔值
,标识此用户是否是首次供应该资产。isFirstSupply
- 根据当前最新的
5. 抵押品自动配置
- 如果
为真,且通过isFirstSupply
检查(用户未将此资产在其他市场设置为抵押品、且该资产本身可被用作抵押品),则会自动将该用户的此资产配置为抵押品(validateAutomaticUseAsCollateral
),从而可能提升其借款能力。userConfig.setUsingAsCollateral
2.2.2 计算流动性存款利率
利率计算的核心是 “资金利用率” ,它衡量了池子中存款被借出的比例。
1. 借款利率计算(分段线性模型)
借款利率随利用率上升而增加,在“最优利用率”处拐折,加速上升以抑制过度借贷。
U = 总债务 / (可用流动性 + 总债务) // 借款资金利用率 U_optimal = 最优利用率(例如80%) R_base = 基础可变借款利率 R_slope1 = 最优利用率以下的斜率 R_slope2 = 最优利用率以上的斜率 如果 U <= U_optimal: 可变借款利率 = R_base + (U / U_optimal) * R_slope1 如果 U > U_optimal: 可变借款利率 = R_base + R_slope1 + [(U - U_optimal) / (1 - U_optimal)] * R_slope2
2. 存款利率计算(派生模型)
存款利率源于借款利息,在扣除协议费用后分配给存款人。
R_variable = 计算出的可变借款利率 U_supply = 总债务 / (可用流动性 + 总债务 + 未备份资产) // 供应利用率 reserveFactor = 储备金因子(协议费用率,例如10%) 流动性存款利率 = R_variable * U_supply * (1 - reserveFactor)
- 公式本质:存款利率 = 借款利率 × 供应利用率 × (1 - 储备金因子)
:协议费用率,从借款利息中扣除一部分作为协议收入,剩余部分才分配给存款人。因此存款利率总是低于借款利率。reserveFactor
总结
在AAVE V3.3中:
- 计算起点:由市场供需决定的资金利用率。
- 即时价格:利用率通过分段函数模型产生借款利率,再派生出发放给存款人的存款利率。
- 长期记录:这两个利率每秒都在影响并累积到流动性索引和借款索引中。
- 用户收益/债务:你的存款最终收益(
增值)和借款总债务,都通过aToken
这个公式由索引精确决定。你的缩放余额 * 当前索引
2.3 Borrow
2.3.1 borrow代码调用流程图
AAVE-v3-Borrow
2.3.2 函数解释
- 入口函数:
Pool.borrow()- 位置:
protocol/pool/Pool.sol - 作用:这是用户发起借款调用的主要入口。它首先进行基础参数验证(如资产是否激活、金额有效性、利率模式),然后区分是普通借款还是闪电贷,并路由到对应的执行函数。
- 位置:
- 核心逻辑:
_executeBorrow()- 位置:
protocol/libraries/logic/BorrowLogic.sol - 作用:这是借款业务逻辑的核心,其执行严格依赖更新后的状态,主要步骤包括:
- 验证健康因子:调用
(内部会调用_validateBorrow
)计算用户新增此笔债务后的预估健康因子,必须大于1(可配置的阈值),否则交易回滚。这是风险控制的核心。ValidationLogic.validateBorrow - 更新利率与指数:调用
更新资产的_updateInterestRates
和currentVariableBorrowRate
。这是Scaled Balance系统计息的关键。variableBorrowIndex - 计算与铸造债务:
- 计算实际收到的金额(可能扣除手续费)。
- 将实际借款金额按最新
折算为Scaled Debt:variableBorrowIndex
。amountScaled = amount.rayDiv(index) - 调用
,最终会触发你之前分析的variableDebtToken.mint()
函数,将_mintScaled
记入用户地址,作为其浮动债务的Scaled Balance。amountScaled
- 转移资产:将底层代币从储备池转移给用户。
- 更新状态:更新用户的隔离模式债务(如适用)和整体的健康因子。
- 验证健康因子:调用
- 位置:
- 状态更新:
与_updateInterestRates()_mintScaled- 这是连接“全局利率”与“个人债务”的桥梁。
会调用_updateInterestRates
,根据最新的资金利用率,计算出新的interestRateStrategy.calculateInterestRates()
和currentVariableBorrowRate
,并更新currentLiquidityRate
。variableBorrowIndex- 随后,
利用这个刚更新过的、最新的_mintScaled
,将用户的借款金额“定格”为Scaled Debt。同时,它也会结算用户已有旧债务自上次操作以来新产生的利息(通过index
计算),并更新用户个人的balanceIncrease
索引快照。additionalData
- 最终检查:
收尾_executeBorrow- 确保资产转账成功。
- 通过检查
中的ReserveData
(虚拟总账)来确认协议内部会计的一致性。virtualUnderlyingBalance - 发出包含所有关键信息的
事件。Borrow
2.4 Repay
2.4.1 repay 流程图
AAVE-v3-repay
2.4.2 关键步骤详解
根据上面的流程图,以下是各核心环节的详细说明:
- 入口函数:
Pool.repay()- 位置:
protocol/pool/Pool.sol - 作用:用户或第三方(如清算人)调用此函数来偿还债务。它进行基础验证后,会调用
。注意,在v3.2+版本,由于稳定利率被移除,RepayLogic.executeRepay
参数通常固定为浮动利率(2)。interestRateMode
- 位置:
- 核心逻辑:
_executeRepay()- 位置:
protocol/libraries/logic/RepayLogic.sol - 作用:这是还款业务逻辑的核心。其目标是精确减少用户的Scaled Debt并处理相关利息。关键步骤包括:
- 验证与获取债务:确认用户在该资产上有未偿债务,并获取其当前的可变债务代币余额(Scaled Balance形式)。
- 更新利率与指数:调用
更新资产的_updateInterestRates
等。这是结算截至还款时刻所有应计利息的基础。variableBorrowIndex - 计算实际还款上限:用户的实际债务总额 =
。如果传入的scaledBalance * variableBorrowIndex
为amount
,则表示用户想偿还全部债务;否则,还款金额不能超过实际债务总额。type(uint256).max - 销毁Scaled债务(核心):
- 将实际还款金额按最新
折算为应销毁的Scaled Debt:variableBorrowIndex
。amountScaled = amount.rayDiv(index) - 调用
,最终触发variableDebtToken.burn()
函数。该函数会:_burnScaled- 结算用户旧债务到此刻新产生的利息(
)。balanceIncrease - 比较
(还款额) 与amount
(新利息)。balanceIncrease - 如果
,则超额部分用于销毁本金,发出amount > balanceIncrease
事件。Burn - 如果
,则还款额连新利息都未覆盖,用户的净债务反而增加,会发出amount <= balanceIncrease
事件。这是会计一致性的关键体现。Mint
- 结算用户旧债务到此刻新产生的利息(
- 将实际还款金额按最新
- 接收资产:将还款的底层代币从调用者地址转移至储备池。
- 更新状态:减少用户在隔离模式下的债务(如适用),并调用
更新相关状态。最后,重新计算并更新用户的健康因子(通常会因债务减少而改善)。_updateIsolatedDebtIfIsolated
- 位置:
- 最终检查与事件
- 验证资产转账成功。
- 检查用户的债务余额是否如预期减少(或清零)。
- 发出
事件,包含借款人、还款人、资产、金额、是否全额清偿等关键信息。Repay
2.5 Withdraw
2.5.1 withdraw代码调用流程图
AAVE-v3-withdraw
2.5.2 关键函数
- 入口函数:
Pool.withdraw()- 位置:
protocol/pool/Pool.sol - 作用:用户调用此函数从资金池提取自己存入的资产。它进行基础验证后,会调用
。注意:用户可以为第三方提取(通过WithdrawLogic.executeWithdraw
参数),但只能提取自己名下的资产。to
- 位置:
- 核心逻辑:
_executeWithdraw()- 位置:
protocol/libraries/logic/WithdrawLogic.sol - 作用:这是提现业务逻辑的核心,在允许用户取出资产的同时,确保协议和用户账户的安全性。关键步骤包括:
- 获取用户存款余额:通过
获取用户当前的Scaled Balance。AToken.balanceOf(user) - 更新利率与指数:调用
更新资产的_updateInterestRates
和liquidityIndex
。这确保了用户能提取截至当前区块所产生的全部利息。currentLiquidityRate - 计算实际可提取金额(核心限制逻辑):
- 基于用户余额:计算用户的实际存款总额 =
。如果传入的scaledBalance * liquidityIndex
为amount
,则表示用户想提取全部存款;否则,提现金额不能超过实际存款总额。type(uint256).max - 基于池流动性:即使有存款,提现金额也不能超过储备池的可用流动性。可用流动性 =
。虚拟余额(virtualUnderlyingBalance) - 总债务 - 赤字(deficit) - 最终可提取金额 =
。min(用户请求金额, 用户存款总额, 池可用流动性)
- 基于用户余额:计算用户的实际存款总额 =
- 销毁aToken(核心):
- 将实际提现金额按最新
折算为应销毁的Scaled aToken:liquidityIndex
。amountScaled = amount.rayDiv(index) - 调用
,最终会触发AToken.burn()
函数(与你之前分析的债务代币销毁逻辑类似)。该函数会:_burnScaled- 结算用户存款到此刻新产生的利息(
)。balanceIncrease - 从用户的aToken余额中销毁对应的
。amountScaled
- 结算用户存款到此刻新产生的利息(
- 将实际提现金额按最新
- 转移资产:将底层代币从储备池转移给接收地址(
)。to - 安全验证与状态更新:
- 健康因子检查:这是提现的关键风控。减少抵押品(提现)可能会降低用户的健康因子。协议会验证提现后用户的健康因子仍高于清算阈值(通常为1),否则交易回滚。这是防止用户无意中将自己置于清算风险的重要保护。
- 更新用户的隔离模式债务状态(如适用)。
- 更新储备池的
(减少取出的部分)。virtualUnderlyingBalance
- 获取用户存款余额:通过
- 位置:
- 最终检查与事件
- 验证资产转账成功。
- 检查实际提取金额大于0(防止边缘情况下的零值操作)。
- 发出
事件,包含用户、接收者、资产、金额等关键信息。Withdraw
2.6 Liquidation
2.6.1 close factor
AAVE的Close Factor(关闭因子)是指在一次清算交易中,允许清算人替借款人偿还的最大债务比例,而不是全部清算
核心定义
- 目的: 防止借款人因市场微小波动而被“全额清算”,增加系统的抗风险能力,并为借款人提供缓冲。
- 默认值: 在AAVE V2和V3中,Close Factor的默认值是 50%。这意味着在一次清算交易中,清算人最多只能偿还借款人某一笔特定债务的50%。
- 关键限制: 这不是针对借款人总债务的比例,而是针对触发清算的每一笔单独的债务资产。
- 满足三个条件才能使用部分清算:如下图
close-factor
举例说明(多债务场景)
假设借款人仓位:
- 抵押品: 价值 $200 的ETH。
- 债务1: 100 USDC (稳定币)
- 债务2: 50 DAI (另一种稳定币)
- 总债务: $150 (100 USDC + 50 DAI)
- 健康因子暴跌后降至0.95,进入可清算状态。
清算过程(Close Factor = 50%):
- 清算人不能直接清算“总债务的50%”(即$75)。
- 清算人必须选择针对哪一笔具体的债务进行清算。
- 选择A:清算USDC债务。
- 可清算的最大USDC债务额度 = 100 USDC * 50% = 50 USDC。
- 清算人偿还50 USDC,并获得相应折扣的ETH抵押品。
- 清算后:债务1变为 50 USDC,债务2仍为 50 DAI,总债务变为$100。
- 选择B:清算DAI债务。
- 可清算的最大DAI债务额度 = 50 DAI * 50% = 25 DAI。
- 清算人偿还25 DAI,并获得相应折扣的ETH抵押品。
- 清算后:债务1仍为 100 USDC,债务2变为 25 DAI,总债务变为$125。
- 选择A:清算USDC债务。
- 在偿还了部分债务后,借款人的健康因子会提升。如果健康因子恢复到1以上,清算就会停止。剩余的债务(包括未被清算的那一笔)仍然由借款人持有,需要继续管理或偿还。
2.6.2 计算清算的抵押物包含了(奖励和协议费用)
liquidation
collateralAmount = debtToCover * 债务资产价格(debt price) * (1 + 清算奖励率) / 抵押品资产价格(collateral price)。
2.6.3 liquidate流程图
AAVE-v3-liquidate
2.6.4 关键步骤详解
根据上面的流程图,以下是各核心环节的详细说明:
-
入口函数:
Pool.liquidationCall()- 位置:
protocol/pool/Pool.sol - 作用:清算人调用此函数来清算一个不健康的仓位。它进行基础验证后,会调用
。LiquidationLogic.executeLiquidationCall
- 位置:
-
核心逻辑:
_executeLiquidationCall()-
位置:
protocol/libraries/logic/LiquidationLogic.sol -
作用:这是清算业务逻辑的核心,其目标是以有序的方式减少协议的风险敞口。关键步骤包括:
-
验证健康因子:使用预言机价格计算用户的当前健康因子(Health Factor)。只有当
(或更严格的可配置阈值)时,清算才能进行。这是清算触发的最根本条件。HF < 1 -
计算可清算额度:
- 理论最大债务清算额:根据协议参数(
,通常为50%),计算单次清算可覆盖的债务上限(CloseFactor
)。这防止了仓位被一次性完全清算,给了用户补救时间。debtToCover - 实际债务清算额:取
。min(清算人指定的debtToCover, 用户总债务, 基于抵押品价值计算的最大允许值)
- 理论最大债务清算额:根据协议参数(
-
计算抵押品奖励:
-
这是清算人的盈利来源。根据公式计算清算人应获得的抵押品数量:
。collateralAmount = debtToCover * 债务资产价格 * (1 + 清算奖励率) / 抵押品资产价格 -
清算奖励率(Liquidation Bonus) 是一个关键参数,存储在抵押品资产的
中。它激励清算人参与风险处置。RserveConfiguration
-
-
执行资产交换(核心操作):
- 偿还债务:调用
函数(即还款逻辑),使用清算人的资金偿还用户的指定债务。这会销毁用户的相应_repay
。variableDebtToken - 获取抵押品:调用
函数(即提现逻辑),但接收者(_withdraw
)是清算人,将计算好的抵押品从用户的抵押品余额中扣除并转移给清算人。这本质上是将用户的抵押品to
转移给了清算人。aToken
- 偿还债务:调用
-
更新状态:更新用户的隔离模式债务状态(如果涉及),并重新计算其健康因子。
-
-
-
最终验证与事件
- 健康因子改善验证:必须确保清算操作后,被清算用户的健康因子有所提高。这是清算操作有效的根本证明。
- 隔离模式规则验证:如果债务资产处于隔离模式,则验证清算人获得的抵押品只能是该债务资产本身,防止风险扩散。
- 发出
事件,包含清算人、被清算人、债务资产、清偿金额、抵押品资产、获得抵押品数量以及是否全额清算等关键信息。LiquidationCall
2.7 FlashLoan
2.7.1 代码流程
AAVE-v3-flashLoan
2.7.2 关键步骤详解
-
根据上面的流程图,以下是各核心环节的详细说明:
-
- 入口函数:
Pool.flashLoanSimple()- 位置:
protocol/pool/Pool.sol - 作用:用户(通常是另一个智能合约)调用此函数发起单资产的闪电贷。它进行基础验证后,会调用
。与多资产闪电贷(FlashLoanLogic.executeFlashLoanSimple
)相比,此函数参数更简洁。flashLoan
- 位置:
- 核心逻辑:
_executeFlashLoan()- 位置:
protocol/libraries/logic/FlashLoanLogic.sol - 作用:这是闪电贷业务逻辑的核心,严格遵守“先发放,后验证”的模式。关键步骤包括:
- 计算可贷额度与费用:
- 检查请求金额不超过该资产的可用流动性。可用流动性基于
、总债务等计算得出。virtualUnderlyingBalance - 计算闪电贷费用(Premium):
。premium = amount * flashLoanPremiumTotal / 10000
是存储在储备配置中的基数(如5表示0.05%),一部分给协议,一部分给流动性提供者。flashLoanPremiumTotal
- 检查请求金额不超过该资产的可用流动性。可用流动性基于
- 转移资产:将
数量的底层资产直接转移给接收者合约(amount
)。这是贷款发放。receiver - 触发回调:调用接收者合约的
函数。这是闪电贷的核心:接收者合约在此函数中自由使用这笔资金(例如进行套利、交换、清算),但必须确保在函数结束前准备好归还资金。executeOperation - 验证归还与收费:
- 在回调结束后,计算合约当前该资产的余额。
- 验证余额至少达到了
。这确保了本金和费用已被归还。初始余额 + premium - 如果验证通过,将
部分作为费用收取(更新premium
和accruedToTreasury
,将费用分配给协议和流动性提供者)。liquidityIndex
- 计算可贷额度与费用:
- 位置:
- 最终验证与事件
- 验证资产余额恢复(这是最根本的安全检查)。
- 发出
事件,包含接收者地址、资产、金额、费用以及借款模式(简易模式)等关键信息。FlashLoan
- 入口函数:
三. 应用
3.1 多头杠杆交易
在AAVE V3上进行多头杠杆交易,核心是通过存入资产作为抵押品,借出更多资金并重复投入,以放大对同一资产或相关资产的价格上涨收益。
long
3.2 做空策略
在AAVE上进行做空(Short)策略,核心逻辑是:预期某个代币价格将下跌,通过AAVE借入该代币并立即卖出,等待其价格下跌后,用更少的钱买回并归还,赚取差价。 这与做多相反,是一种从资产价格下跌中获利的策略。
做空
3.3 Max Leverage (最大杠杆)
最大杠杆
Max LTV:指某一抵押品能借出的其他资产的最大价值比例。例如,如果ETH的Max LTV为80%,那么存入价值800的其他资产
最大杠杆倍数 = 1 / (1 - Max LTV)
这个公式的推导逻辑是:在循环借贷策略中,你初始的1单位本金,通过“抵押→借款→再抵押”的循环,最终持有的总资产价值可以达到这个倍数。
理解最大杠杆时,必须纠正几个关键误解:
- 是理论极限,而非安全目标:达到最大杠杆意味着你的抵押率刚好等于Max LTV,此时健康因子为1,处于立刻被清算的边缘。任何微小的不利价格波动或利息累积都会触发清算。
- 实际安全杠杆远低于此:任何理性的杠杆操作者都会在健康因子低于1.5甚至2.0时就保持高度警惕,留出充足的安全缓冲。
- 依赖特定的风险参数:Max LTV由AAVE社区治理决定,可能因市场风险变化而调整。例如,在极端市场波动时,治理可能临时调低某资产的Max LTV以保护协议,这会导致使用该抵押品的所有杠杆头寸面临更高的清算风险。
评论区
发表评论
请先 登录 后再发表评论
评论
还没有评论,来做第一个评论者吧!