背景
在 2026 年 5 月 29 日,AAVE V3 执行了提案 #442 更新了 Pool 和 PoolConfigurator 合约的代码。
主要更新内容涉及以下几个方面:
- Isolation Mode(孤立模式):将 Isolation Mode 合并到 E-Mode,不在单独维护。同时移除相关的变量与操作函数。
- PriceOracleSentinel(价格哨兵):作为为 L2 Sequencer 宕机场景设计的安全组件,在主网上它永远返回"允许操作",属于零作用的冗余调用。在本次更新中被移除。
- hasNoCollateralLeft 精度修复:清算情况统一采用 scale 值来进行判断。
- dropReserve() 函数:移除代币函数,但是从未在以太坊主网使用过。在本次更新中被移除。
更新内容
接下来对更新内容进行详细介绍
Isolation Mode
AAVE V3 的 Isolation Mode(隔离模式) 是 V3 版本引入的风险管理功能,主要用于安全引入新资产、波动性较大或风险较高的资产作为抵押品,同时限制其对整个协议的系统性风险。
当一个资产被设置为 Isolated Collateral Asset(隔离抵押资产) 时,它将受到以下约束:
- 只能作为唯一抵押品:用户一旦启用该资产作为抵押品,就不能同时启用其他资产作为抵押品。其他资产仍可 Supply 赚取利息,但不能用于借贷了。
- 借贷限制:只能借出特定的币种(比如稳定币)。
- 债务上限:整个协议针对该隔离资产有全局债务上限(控制风险敞口),达到上限后就无法再借更多。
举例:假设将 PEPE 设为 Isolation Mode 抵押品,债务上限为 100 万 USD。用户 Alice 存入 PEPE 后只能借 USDC/USDT 等白名单资产。且当全池 PEPE 孤立债务触及上限后,协议不再接受任何以 PEPE 作为抵押品的新借款。
在新版本中,移除了 Isolation Mode 模块:
- 删除
IsolationModeLogic库及全部调用点、 - 删除
dropReserve/resetIsolationModeTotalDebt两个管理函数、 - 废弃
ReserveData.isolationModeTotalDebt存储字段、 - 废弃
ReserveConfigurationMap中 4 个相关位域。 - 原有的 Isolation Mode 模块功能整合到 E-Mode 中进行实现,在 eMode Category 新增了
isolated标志用来表示该类资产是隔离资产。
本次更新被移除的变量

E-Mode
E-Mode(Efficiency Mode)是 AAVE V3 的资产分类系统,将相关性高的资产(如稳定币之间、ETH 及其 LSD 衍生品之间)归入同一 Category,赋予高 LTV(最高 97%)以提升资金效率。每个 Category 通过 collateralBitmap、borrowableBitmap、ltvzeroBitmap 三张位图精细控制资产权限。
举例:假设稳定币 Category 的 id = 1,将 USDC/USDT/DAI 纳入
collateralBitmap和borrowableBitmap,LTV 设为 97%。用户存入 USDC 后最高可借出其价值的 97% 的 DAI。
E-Mode 整合 Isolation Mode
为什么 E-Mode 可以整合实现 Isolation Mode 的功能?
两者独立运行但有功能重叠:
- Isolation Mode:为新资产设置债务上限,追踪全局孤立债务,超出上限则拒绝借款;
- E-Mode:为同类资产设置高 LTV Category,通过三张 bitmap 控制抵押品/可借款/零 LTV 范围;
- 重叠范围:两者都在回答"用户用资产 X 做抵押时,能借什么、能借多少"。区别是 Isolation Mode 通过全局债务上限进行约束,而 E-Mode 通过 bitmap + LTV 限制进行约束。
这是 E-Mode 整合 Isolation Mode 功能的核心机制:
- 首先在
EModeCategory和EModeCategoryBaseConfiguration中新增bool isolated字段,将其内化成 E-Mode 的一种类型。 - 当某个 Category 被标记为 isolated 时,仅
collateralBitmap中的资产可作抵押品,其余资产即使有余额也自动适用 LTV=0。 - 同时配套新增
configureEModeCategoryIsolated和getIsEModeCategoryIsolated两个管理/查询函数。
PriceOracleSentinel
PriceOracleSentinel 是 AAVE 部署在 L2 网络(Arbitrum、Optimism 等)上的安全组件:当 L2 Sequencer 宕机时,冻结借款和清算操作,防止攻击者利用价格同步滞后套利或恶意清算。
举例:假设 Arbitrum Sequencer 停机 30 分钟,ETH 价格已从 3000 跌至 2500,但 Arbitrum Oracle 仍显示 $3000。Sentinel 检测到停机后拒绝借款交易,阻止攻击者以虚高估值借走 USDC。
由于主网(Ethereum)无 Sequencer 问题,PriceOracleSentinel 不产生实质保护,新版将其从所有执行路径中剔除:
- 删除接口文件
IPriceOracleSentinel.sol; - 从 4 个参数结构体中移除
priceOracleSentinel字段; Pool.sol和FlashLoanLogic.sol中不再获取和传入。

hasNoCollateralLeft
在协议对仓位进行清算后,需要回答两个问题:
- 被清算的抵押品是否被完全消耗:决定是否清除该资产在用户配置中的 collateral 标记;
- 用户全部抵押品是否清零:决定是否将未还债务记为坏账(deficit)。
在旧版本中这两个值分别通过 underlying 和 USD 的数值来判断,随后在 transfer scale 代币(AToken)时会发生 celi rounding(向上取整,保护协议利益),导致判断的与实际不一致。而新版就统一采用 scale 值来进行判断,避免了不一致的情况。
旧版本处理流程
- 问题 1 用的是 underlying amount 等值比较:
actualCollateralToLiquidate + liquidationProtocolFeeAmount == borrowerCollateralBalance。 - 问题 2 用的是 Base Currency 等值比较:
totalCollateralInBaseCurrency == collateralToLiquidateInBaseCurrency。其中collateralToLiquidateInBaseCurrency来自_calculateAvailableCollateralToLiquidate,计算公式为(collateralAmount * price) / unit。
两组判断的共同问题是:它们都发生在链上实际转账之前,而实际转账内部使用 rayDivCeil(向上取整)将 underlying amount 折算为 scaled amount。ceil rounding 可能导致实际消耗的 scaled amount 略大于预估 underlying 对应的 scaled 份额,造成预估值与链上实际消耗不一致。
举例:假设流动性指数 1.3 RAY,借款人 scaled balance = 1×10¹⁸,对应 underlying = 1.3 ETH。ETH 价格 $3,000。清算人所得 0.7 ETH,协议费 0.6 ETH,合计 1.3 ETH(恰好等于借款人余额)。
推导过程:
getATokenBurnScaledAmount 和 getATokenTransferScaledAmount 的公式都使用 rayDivCeil 进行向上取整:scaled = ⌈ underlying × 10^27 / liquidityIndex ⌉
分别计算两笔 scaled:
- 清算人:
⌈ 0.7/1.3 × 10^18 ⌉=⌈ 538,461,538,461,538,461.53... ⌉=538,461,538,461,538,462 - 协议费:
⌈ 0.6/1.3 × 10^18 ⌉=⌈ 461,538,461,538,461,538.46... ⌉=461,538,461,538,461,539 - 两笔之和:
1,000,000,000,000,000,001 - 借款人余额:
1,000,000,000,000,000,000,差额:+1← 各自 ceil 各多出不到 1 单位,合计溢出 1
这导致旧版本的判断全部通过,但转账时会发生 revert。
新版本处理流程
新版不再基于 underlying 和 USD 进行判断,而是将两者换算成链上实际消耗的 scaled amount 后进行判断:
- 将清算人所得和协议费两部分各自用
rayDivCeil换算成 scaled amount,然后加和,得到链上实际会消耗的 scaled 总量; - 如果总值超过借款人实际 scaled balance,则取实际值;
reserveFullyConsumed:实际 scaled 消耗 == 借款人全部 scaled balance。从 scaled 维度判断"储备是否耗尽";consumedInBaseCurrency:根据实际 scaled 消耗计算 underlying 数量,从而计算出美元价值。最后根据美元价值判断"价值是否等于全部抵押品";- 最终条件:
reserveFullyConsumed || hasNoCollateralLeft,任一维度判定清零即执行清零处理。
推导过程:
- 计算 scaled 消耗:
538,461,538,461,538,462 + 461,538,461,538,461,539 = 1,000,000,000,000,000,001 - 截断为实际余额:
1,000,000,000,000,000,001 > 1,000,000,000,000,000,000→ 截断为1,000,000,000,000,000,000 - scaled 判断:
1,000,000,000,000,000,000 == 1,000,000,000,000,000,000→reserveFullyConsumed = true - 基于 scaled 数量反推 USD 价值进行判断:
(1,000,000,000,000,000,000 × 1.3/1 × 3000×10^8) / 10^18 = 390,000,000,000。390,000,000,000 == 390,000,000,000→hasNoCollateralLeft = true reserveFullyConsumed || hasNoCollateralLeft→true→ 正确清零,且转账成功。
dropReserve
dropReserve() 是一个用来移除资产的函数,但是在 Ethereum 的 AAVE 上从来没有调用过,所以这次把他移除了。