借贷协议的本质是一台把「价格波动」转化为「清算事件」的机器:只要抵押物价值相对于债务的比率跌破阈值,任何人都可以代为偿还债务并获取折扣抵押物。这台机器在平静市场里几乎隐形,在剧烈波动中却决定了协议是「无损出清」还是「留下坏账」。
本文从风险构成讲到清算工程:抵押率与健康因子的数学定义、拍卖与固定折扣两类清算机制的设计取舍、预言机操纵这一最致命的攻击面、坏账与保险基金的处置路径、隔离模式与额度上限的风险隔离手段,最后给出压力测试框架与经典事件复盘。
目录
- 1. DeFi 风险的构成
- 2. 抵押率与健康因子
- 3. 清算机制设计
- 4. 预言机与价格操纵风险
- 5. 坏账与保险基金
- 6. 隔离模式与额度上限
- 7. 风险参数治理
- 8. 压力测试与监控指标
- 9. 经典清算事件复盘
- 10. 工程落地建议
1. DeFi 风险的构成
1.1 五类风险
| 风险类型 | 来源 | 典型后果 |
|---|---|---|
| 市场风险 | 抵押物价格波动 | 抵押不足、被迫清算 |
| 流动性风险 | 清算时缺少接盘方 | 清算折价扩大、坏账 |
| 预言机风险 | 价格源被操纵或失效 | 错误清算、套利抽干 |
| 参数风险 | 阈值设置不当 | 正常波动触发大规模清算 |
| 合约风险 | 代码漏洞 | 资金被盗 |
真正致命的是这些风险的叠加:价格剧烈波动加链上拥堵加预言机延迟,会让清算机制在最需要它的时候失灵。
1.2 清算的目标函数
清算机制要同时优化三个互相冲突的目标:偿付性(清算后债务被完全覆盖,不留坏账)、用户保护(避免因短暂波动或预言机噪声触发不必要清算)、市场稳定(大额清算不应引发级联抛售)。阈值设得太紧,正常波动就触发清算;设得太松,坏账风险上升。
2. 抵押率与健康因子
2.1 核心公式
抵押率(LTV) = 债务价值 / 抵押物价值
清算阈值(LT) = 触发清算的 LTV 上限
健康因子(HF) = (抵押物价值 × 清算阈值) / 债务价值
当 HF < 1 时账户可被清算。清算阈值必须大于最大借款 LTV,两者之差就是安全缓冲:
最大 LTV = 0.80 借款时的上限
清算阈值 = 0.825 触发清算的线
清算罚金 = 0.05 清算人获得的折扣
缓冲(0.025)决定了价格需要下跌多少才会触发清算。缓冲过窄会让用户几乎没有反应时间,过宽则降低资本效率。
2.2 计算实现
function healthFactor(address user) public view returns (uint256) {
uint256 weightedThreshold;
uint256 totalDebtValue;
for (uint256 i = 0; i < reserves.length; ++i) {
uint256 price = oracle.getPrice(reserves[i]);
uint256 c = collateral[user][reserves[i]] * price / 1e18;
totalDebtValue += debt[user][reserves[i]] * price / 1e18;
weightedThreshold += c * liquidationThreshold[reserves[i]] / 1e4;
}
if (totalDebtValue == 0) return type(uint256).max;
return weightedThreshold * 1e18 / totalDebtValue;
}
注意加权:多资产抵押时,阈值按各资产的清算阈值加权求和,而非对所有抵押物用同一阈值。这个细节写错会导致系统性高估或低估风险。
2.3 健康因子的局限
健康因子是一个瞬时快照,它不反映价格的波动率、抵押物的流动性深度,也不反映相关性(多个抵押物同涨同跌时,分散抵押并不降低风险)。因此成熟协议会在 HF 之外叠加资产风险分级:稳定币、ETH、长尾资产分别配置不同的 LTV、LT 与额度上限。
3. 清算机制设计
3.1 三种主流机制
| 机制 | 定价方式 | 优点 | 缺点 |
|---|---|---|---|
| 固定折扣 | 预言机价 × (1 - 罚金) | 简单、确定 | 大额清算时接盘方不足 |
| 荷兰式拍卖 | 折扣随时间递减 | 价格发现、缓冲冲击 | 延迟清算、可能留下坏账 |
| 英式拍卖 | 竞价者出价 | 最优价格 | gas 高、延迟高 |
3.2 固定折扣清算
Aave 式设计:清算人偿还部分债务,按 预言机价 × (1 - 罚金) 获得抵押物。
function liquidate(address user, address collateralAsset, address debtAsset, uint256 debtToCover) external {
require(healthFactor(user) < 1e18, "HEALTHY");
uint256 maxClose = closeFactor[debtAsset]; // 如 0.5 表示最多清算一半债务
require(debtToCover <= debt[user][debtAsset] * maxClose / 1e4, "TOO_MUCH");
uint256 bonus = liquidationBonus[collateralAsset]; // 如 1.05e4 表示 5% 奖励
uint256 seize = debtToCover * oracle.getPrice(collateralAsset) / 1e18 * bonus / 1e4;
require(seize <= collateral[user][collateralAsset], "INSUFFICIENT_COLLATERAL");
IERC20(debtAsset).transferFrom(msg.sender, address(this), debtToCover);
debt[user][debtAsset] -= debtToCover;
collateral[user][collateralAsset] -= seize;
IERC20(collateralAsset).transfer(msg.sender, seize);
}
close factor(单次清算比例) 是关键参数:限制单次清算规模,防止在流动性稀薄的市场上一次砸盘。
3.3 荷兰式拍卖清算
折扣从 0 开始线性增长到最大罚金(如 15%),清算人在任意时刻可选择接受:
t=0 折扣 0% 无人有动力清算
t=T/2 折扣 7.5% 部分清算人进场
t=T 折扣 15% 任何清算人都有动力
这种设计把「清算时机」交给市场决定:有竞争力的清算人会早进场拿小折扣,缺乏竞争时折扣逐步扩大到足以吸引接盘方,从而在极端行情下仍能出清。
3.4 部分清算与级联风险
大额清算本身会砸低抵押物价格,触发更多清算,形成级联。缓解手段包括 close factor 限制(单次最多清算债务的一半)、分批清算(把大额头寸拆成多笔,给市场消化时间)、清算上限(按抵押物流动性设置单区块最大清算量)。
4. 预言机与价格操纵风险
4.1 价格源的选择
| 价格源 | 抗操纵性 | 延迟 | 适用 |
|---|---|---|---|
| Chainlink 聚合器 | 高 | 中(心跳 + 偏差触发) | 主流资产 |
| TWAP(30 分钟) | 高 | 高(滞后) | 大额清算定价 |
| 现货价(AMM) | 极低 | 低 | 绝不可单独使用 |
| 自建多源中位数 | 中 | 低 | 长尾资产 |
单一 AMM 现货价是最危险的配置:攻击者可用闪电贷瞬间扭曲池子价格,触发错误清算并以折扣价拿走抵押物。
4.2 经典攻击路径
闪电贷操纵清算攻击:
1. 攻击者发现某协议用单一 AMM 池的现货价作为抵押物价格
2. 闪电贷借入大量资金,在池中砸低该抵押物价格
3. 协议认为借款人抵押不足,触发清算
4. 攻击者以极低价格(预言机价 × (1-罚金))买走抵押物
5. 归还闪电贷,池子价格恢复,利润落袋
防护的核心是价格源的抗操纵性:使用聚合预言机(价格由多个独立节点与交易所数据聚合);对长尾资产使用 TWAP 或时间加权中位数抬高操纵成本;设置价格变化速率限制(如单次更新最大变动 10%),异常时暂停清算。
4.3 预言机失效处理
function getPrice(address asset) public view returns (uint256) {
(, int256 answer, , uint256 updatedAt, ) = feed[asset].latestRoundData();
require(answer > 0, "INVALID_PRICE");
require(block.timestamp - updatedAt <= staleThreshold, "STALE_PRICE");
return uint256(answer);
}
必须处理三种失效:价格为零或负、数据过期(stale)、价格异常跳变。失效时的正确行为通常是暂停清算与新借款,而非使用最后价格继续运行。
4.4 风险清单
| 风险 | 触发条件 | 缓解 |
|---|---|---|
| 现货价操纵 | 单一 AMM 价格源 | 换用聚合预言机 |
| 数据过期 | 喂送节点故障 | 陈旧检测 + 暂停 |
| 价格跳变 | 交易所异常成交 | 速率限制 + 多源校验 |
| 小市值操纵 | 抵押物市值过低 | 额度上限 + 资产下架 |
5. 坏账与保险基金
5.1 坏账的产生
当清算无法覆盖全部债务时,缺口就是坏账,即 max(0, 债务价值 - 可清算抵押物价值)。三种典型成因:清算不及时(价格跳空下跌,HF 从 1.05 直接跌破 0.9)、流动性不足(抵押物无人接盘,折扣扩大到 15% 也卖不掉)、预言机失灵(价格源暂停,协议在错误价格上清算或无法清算)。
5.2 保险基金机制
contract InsuranceFund {
uint256 public balance;
function accrueFromLiquidation(uint256 penalty) external { // 罚金一部分入基金
balance += penalty * reserveFactor / 1e4;
}
function coverBadDebt(uint256 shortfall) external returns (uint256 covered) {
covered = shortfall > balance ? balance : shortfall;
balance -= covered;
}
}
保险基金的规模应与其承担的风险成比例:可用「历史最大单日坏账」或「极端行情下的模拟坏账」作为目标规模。
5.3 坏账的最终归属
当保险基金也不足以覆盖时,处置方式按优先级:先消耗保险基金;再动用协议收入(暂停分红,用收入填补);仍不足则社会化损失(按比例分摊给存款人,严重损害信任);最后才考虑治理代币稀释(增发补偿,需治理投票)。Aave 的 Umbrella 类机制、Compound 的储备金机制都是这一思路的工程化实现。
6. 隔离模式与额度上限
6.1 隔离模式
隔离模式(Isolation Mode)限制新上架的长尾资产只能作为单一抵押物使用,且借款额度受限,从而防止「一个长尾资产被操纵导致整个协议受冲击」的传染。
struct ReserveConfig {
uint16 ltv; // 最大借款比例
uint16 liquidationThreshold; // 清算阈值
uint16 liquidationBonus; // 清算奖励
bool isolationMode; // 是否隔离
uint256 debtCeiling; // 隔离模式下的债务上限
uint256 supplyCap; // 供应上限
}
6.2 额度上限的作用
| 参数 | 作用 | 典型取值逻辑 |
|---|---|---|
| supply cap | 限制单一资产供应规模 | 按链上流动性深度设 |
| borrow cap | 限制单一资产借出规模 | 按市场深度设 |
| debt ceiling | 隔离资产的总债务上限 | 按可承受坏账设 |
| e-mode 类别 | 同类别资产提高资本效率 | 稳定币 / ETH 类 |
额度上限是「用资本效率换安全」的直接工具:上限越紧,极端行情下的最大损失越可控。
6.3 效率模式(E-Mode)
对高度相关的资产(如稳定币对稳定币、ETH 对 LST),可以提高 LTV 与降低清算阈值,因为相关性降低了同跌风险。风险在于相关性在极端行情中会失效(如 USDC 脱锚时,所有稳定币同时贬值)。
7. 风险参数治理
7.1 参数调整的流程
风险参数变更流程:
1. 风险团队提出参数调整(基于市场数据与模拟)
2. 公开论坛讨论 + 风险分析报告
3. 治理投票(或风险委员会快速通道)
4. Timelock 延迟执行(给用户调整头寸的时间)
5. 执行后监控指标变化
Timelock 至关重要:参数突然收紧会触发大规模清算,用户需要时间补充抵押或还款。
7.2 参数的联动
参数不能独立调整,必须联动考虑:提高 LTV 提升资本效率但清算缓冲变窄;提高清算罚金让清算人更积极但用户损失更大、清算更激烈;降低 close factor 让单次清算规模变小却降低清算效率、抬高坏账风险;提高 supply cap 扩大协议规模却增加单一资产敞口。
7.3 治理风险
治理层面有三类风险:治理攻击(攻击者借入治理代币通过恶意参数提案)、快速通道滥用(紧急通道被用于非紧急的参数调整)、参数滞后(市场已变化而参数未更新)。缓解手段包括治理时间锁、参数变更的上下限约束(如单次调整不超过 5%)、独立风险委员会的否决权。
8. 压力测试与监控指标
8.1 压力测试框架
测试场景设计:
1. 单资产价格下跌 30% / 50% / 80%
2. 稳定币脱锚至 0.95 / 0.90 / 0.80
3. 相关资产同时下跌(相关性 = 1)
4. 预言机延迟 1 小时 / 4 小时 / 停机
5. 链上拥堵,清算交易 10 个区块未确认
6. 组合场景:价格暴跌 + 拥堵 + 预言机延迟
每个场景应输出清算量、坏账规模、保险基金消耗、剩余偿付能力四项结果。
# 简化模拟:给定价格冲击,计算坏账规模
def simulate_bad_debt(positions, price_shock, lt, bonus):
total = 0
for p in positions:
collateral_value = p.collateral * price_shock
if collateral_value * lt / p.debt < 1: # HF < 1,触发清算
recoverable = collateral_value * (1 - bonus)
total += max(0, p.debt - recoverable)
return total
8.2 监控指标
| 指标 | 含义 | 告警阈值示例 |
|---|---|---|
| 协议总 HF 分布 | 接近清算线的头寸规模 | HF < 1.1 的头寸 > 总债务 10% |
| 各资产清算量 | 单日清算规模 | 超过历史 P99 |
| 预言机偏差 | 主源与备源价差 | > 2% |
| 预言机陈旧度 | 距上次更新时长 | > 心跳间隔 2 倍 |
| 保险基金覆盖率 | 基金 / 潜在坏账 | < 1.5 |
| 清算成功率 | 清算交易成功比例 | < 90% |
| 抵押物集中度 | 单一资产占总抵押比例 | > 40% |
8.3 清算盈利性与 gas 的关系
清算人只有在「折扣收益 > gas 成本 + 滑点」时才会行动。极端行情下 gas 飙升,小额头寸变得无利可图,无人清算,最终形成坏账。因此需要设置最小清算规模避免大量小额头寸在 gas 高企时无人问津,保留协议自有清算人(keeper)作为兜底,并监控 gas 与清算收益的比值以提前预警。
9. 经典清算事件复盘
9.1 事件模式归纳
| 事件类型 | 机制 | 教训 |
|---|---|---|
| 闪电贷价格操纵 | 单一 AMM 价格源被瞬时扭曲 | 必须用聚合预言机 |
| 级联清算 | 大额清算砸盘触发更多清算 | close factor + 分批清算 |
| 预言机停机 | 喂送中断,协议在旧价上运行 | 陈旧检测 + 暂停机制 |
| 长尾资产崩盘 | 抵押物流动性枯竭无人接盘 | 额度上限 + 隔离模式 |
| 参数突变 | 治理突然提高清算罚金 | Timelock + 变更上限 |
| 链上拥堵 | 清算交易无法及时上链 | 协议 keeper + 优先级费 |
9.2 复盘要点
每一次清算事件都应回答四个问题:触发条件是什么(价格波动幅度、预言机行为、gas 水平);清算机制是否按设计工作(清算人是否及时进场,折扣是否被吃满);坏账从何而来(价格跳空、流动性不足还是预言机失灵);哪个参数可以改善。把这些结论固化为压力测试场景,是风险管理的核心闭环。
10. 工程落地建议
10.1 设计原则
- 价格源优先:先解决预言机抗操纵性,再谈其他参数。
- 缓冲优先:清算阈值与最大 LTV 之间保留足够缓冲,宁可牺牲部分资本效率。
- 上限优先:新资产一律先上隔离模式加严格额度,再逐步放宽。
- 兜底优先:假设清算人会在最坏时刻缺席,准备协议自有 keeper。
- 透明优先:风险参数、坏账、保险基金余额全部公开可查。
10.2 上线清单
□ 预言机:多源聚合 + 陈旧检测 + 速率限制
□ 参数:LTV / LT / bonus / close factor / caps 全部设定并公开
□ 隔离:长尾资产启用隔离模式与债务上限
□ 清算:清算函数有权限校验、单次上限、事件完整
□ 坏账:保险基金机制与处置优先级明确
□ 监控:HF 分布、预言机偏差、清算成功率告警到位
□ 演练:压力测试覆盖极端场景,含拥堵与预言机停机
□ 治理:参数变更走 Timelock,单次变更幅度受限
10.3 速查表与一句话记忆
| 概念 | 关键点 | 工程要点 |
|---|---|---|
| 健康因子 | 加权阈值 / 债务价值 | HF < 1 触发清算 |
| 清算缓冲 | LT 与最大 LTV 之差 | 决定抗波动能力 |
| 固定折扣 | 预言机价 × (1 - 罚金) | 简单但依赖流动性 |
| 荷兰式拍卖 | 折扣随时间递减 | 极端行情下的价格发现 |
| close factor | 单次清算比例上限 | 防级联砸盘 |
| 预言机操纵 | 现货价被闪电贷扭曲 | 用聚合预言机 + TWAP |
| 坏账 | 抵押物不足以覆盖债务 | 保险基金 + 社会化损失 |
| 隔离模式 | 长尾资产单独额度 | 防止风险传染 |
一句话记忆:清算机制的安全性由预言机抗操纵性、清算缓冲宽度和清算人激励三者共同决定,缺一环就会在最坏时刻留下坏账。
延伸阅读
- 借贷协议的利率模型、抵押机制与清算基础
- 预言机价格喂送、聚合机制与失效处理
- 主流 DeFi 协议的风险参数与治理实践
- 清算竞拍与 MEV 在清算流程中的角色
- 治理代币激励与协议储备金设计
- Web3 区块链专题 — 区块链 Web3 专题
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。