Compound V3(Comet)架构详解
目录
- 一、与 Compound V2 的根本区别
- 二、核心架构组件
- 三、参数管理:全部用 immutable
- 四、用户交互:供应与借贷
- 五、利率与利息机制概览
- 六、奖励系统
- 七、治理与参数更新流程
- 八、总结
- 九、动手练习项目:迷你隔离借贷市场 MiniComet
一、与 Compound V2 的根本区别
Compound V3(代号 Comet)彻底改变了借贷模型:
- 每个市场只有一种可借资产,叫基础资产(base asset)。USDC 市场只能借 USDC,ETH 市场只能借 ETH——想借不同资产要去不同的 Comet 部署;
- 抵押品不能赚取利息,它们纯粹用来担保借款;
- 这造就了隔离市场(isolated markets):风险被隔离在各自市场内,一个抵押品出问题不会污染整个协议。
对比 V2:V2 里你可以从一个市场借多种资产,抵押品也能赚息(生成 cToken)。V3 牺牲了灵活性换取风险隔离和 Gas 效率。
二、核心架构组件
2.1 Comet 主合约
Comet 是”Compound V3 的主借贷合约”。系统用代理模式:用户和代理交互,代理 delegatecall 到真正的实现。代理地址永久不变,治理可以把实现升级为新的 Comet 实例。
所有面向用户的逻辑都在 Comet 合约里,Comet 代理把功能委托给它。
2.2 继承链
| 合约 | 职责 |
|---|---|
| CometMath.sol | 安全类型转换工具(如 safe64,溢出则 revert) |
| CometStorage.sol | 集中定义所有存储变量;继承链里其他合约都不定义存储 |
| CometCore.sol | 处理借贷双方的利息累积追踪 |
| CometMainInterface.sol | 以抽象合约形式定义接口 |
| Comet.sol | 实现借、贷、还款、清算等公开函数 |
把所有存储集中在 CometStorage 一个合约里是关键设计——保证升级时存储布局可控(呼应 Module 6 的存储冲突知识)。
2.3 CometExt 扩展模式(绕过 24KB 限制)
以太坊合约字节码有 24KB 上限。Comet 逻辑太多装不下,于是用 fallback + 扩展 模式:
像 name() 这样的函数不在 Comet 里,而在 CometExt 里。调用时命中 Comet 的 fallback,再 delegatecall 到 CometExt。CometExt 保持和 Comet 相同的继承结构,以保证存储布局兼容(否则 delegatecall 会读错插槽——Module 6 第 4 篇的核心教训)。
三、参数管理:全部用 immutable
Compound V3 一个不寻常的设计:所有配置参数都是 immutable 变量,不是可变存储。改参数 = 部署一个全新 Comet 实例 + 把代理指向它。
理由很有说服力:
- immutable 比存储变量省 Gas 得多(读取不花 SLOAD);
- 核心合约不必塞满 setter 函数,更简洁安全;
- 实际上主网的利率曲线只改过三次(2023 年 5 月、7 月、12 月)——改动稀少,重新部署完全可接受。
这是典型的”低频更新、高频读取”场景下选 immutable 的工程决策。
3.1 配置合约族
| 合约 | 职责 |
|---|---|
| CometConfiguration.sol | 定义参数化 Comet 行为的结构体(利率曲线、清算阈值、抵押品规格、清算因子) |
| ConfiguratorStorage.sol | 用 mapping 存这些配置结构体,存在 Comet 之外 |
| Configurator.sol | 继承 ConfiguratorStorage,提供仅治理可调的 setter |
| CometFactory.sol | 逻辑极少,主要是 clone() 函数部署新 Comet 实例(虽叫 clone,但部署的是完整实例,不是 EIP-1167 代理) |
四、用户交互:供应与借贷
出借基础资产:用户存入基础资产(如 USDC)赚取利息,还累积 COMP 奖励。“Net Supply APR” = 出借利率 + COMP 奖励价值。例:出借 USDC 赚 6.47% 利息 + 4.63% COMP 价值 = 共 11.10%。
抵押借款:用户存入抵押品(ETH、wBTC),借出基础资产。抵押品必须满足治理设定的抵押率。例:存 0.06 ETH(值 $110)借出 $100 USDC。“Net Borrow APR” = 付出利息 − COMP 奖励。例:付 6.71% 利息,赚 2.58% COMP,净 4.13%。
利差:借贷双方利率不同。差额(如 “0.24% 的 USDC 利息流向协议”)补偿协议的运营成本,进入储备金。
五、利率与利息机制概览
- 利率按每秒计(不是每区块),详见下一篇《Interest Per Second》;
- 区分本金价值(Principal Value)和现值(Present Value),用利率指数转换,详见《利率指数》篇;
- CometCore 负责追踪和解释借贷双方的利息累积。
六、奖励系统
RewardsClaimer(架构图里的粉色块)负责分发 COMP。Comet 只追踪参与度,不直接发奖励。Rewards 合约读取 Comet 的状态,按治理设定的参数分发 COMP,速率可通过治理提案调整。
七、治理与参数更新流程
- 治理提案并投票修改参数(利率曲线、清算率、允许的抵押品);
- Configurator 的 setter 更新 ConfiguratorStorage 里的存储;
- Configurator 调自己的
deploy(),经 CometFactory; - 部署一个编码了新配置的新 Comet 实例;
- 治理执行交易,把代理的实现指针更新到新实例。
真实提案 #162 就是这样:先调 Configurator 的 setter 更新参数,最后一步部署新 Comet 实例。
八、总结
- V3 = 单一可借基础资产 + 抵押品不计息 + 隔离市场,牺牲灵活换风险隔离;
- Comet(代理 + 实现)是核心,存储集中在 CometStorage,逻辑超 24KB 用 CometExt fallback 扩展;
- 参数全用 immutable,改参数靠”重新部署 Comet + 切代理”;
- Configurator/Factory 负责生产新 Comet 实例;
- 奖励由独立 Rewards 合约读 Comet 状态分发。
九、动手练习项目:迷你隔离借贷市场 MiniComet
项目目标
实现一个高度简化但保留 V3 核心设计的隔离借贷市场:单一基础资产、抵押品不计息、参数 immutable、代理可升级。部署到 Sepolia。
合约要求
1. MiniCometStorage.sol:集中定义所有存储(userPrincipal、userCollateral、totalSupplyBase、totalBorrowBase 等),其他合约只继承不另加存储。
2. MiniComet.sol(实现,继承 Storage)
- 构造函数注入 immutable 参数:
baseToken、collateralToken、borrowCollateralFactor(如 0.8e18)、liquidateCollateralFactor; supply(uint amount):存入基础资产(出借);withdraw(uint amount):取出基础资产或借出(若取超过自己存的,变成借款,需有足够抵押);supplyCollateral(uint amount)/withdrawCollateral(uint amount):抵押品进出,抵押品不计息;isBorrowCollateralized(address) view:抵押是否足够;- 简化利息:先用固定利率,下一篇练习再接每秒利率。
3. MiniCometProxy.sol:ERC-1967 风格代理(复用 Module 6 成果),实现可升级。
测试要求(Foundry)
test_SupplyEarnsBase:供应基础资产后余额记录正确;test_BorrowAgainstCollateral:存抵押品后可借基础资产,借款记为负 principal;test_CannotBorrowWithoutCollateral:无足够抵押借款 revert;test_CollateralEarnsNoInterest:时间推进后抵押品数量不变(不计息);test_ImmutableParams:参数确为 immutable(无 setter,读取不消耗 SLOAD——可对比 Gas);test_ProxyUpgrade:升级实现后存储(用户头寸)保留;test_IsolatedMarket:只能借 baseToken,尝试借 collateralToken 无此功能。
Sepolia 部署与验证步骤
- 部署两个测试代币(USDC 当 base、WETH 当 collateral)、MiniComet 实现、Proxy;
- supply 一些 base,另一个账户 supplyCollateral 后 borrow;
- 在 Etherscan 上读各账户 principal、抵押状态;
- 部署新实现,通过代理升级,确认头寸不丢。
进阶挑战(可选)
- 把逻辑拆成 MiniComet + MiniCometExt,用 fallback 委托,亲手实现 24KB 绕过模式并验证存储布局一致;
- 写注释回答:为什么 V3 选”重新部署改参数”而不是加 setter?这在 Gas 和安全上各有什么取舍?