compound v2 v3 对比

  • ezio
  • 更新于 2022-09-09 11:19
  • 阅读 6438

compoundV3 完全新的优化版 的独立资金借贷池。主要分析其新特性,并对比 v2 v3 的区别

新特性简介

全新的模型,丰富扩展性,更少清算风险,更低清算罚款,省gas

模型变更

compound v2 模型 —— 混合资金池子

各种资产都有自己的 ctoken

compoundv2.png

compound v3 模型 —— 主资金+抵押品池

只有base 资产有 ctoken v3

compoundv3.png

v2 v3 对比变更

1 模型变更

  • v2 指定的资产 都可以当作抵押品 和 借出品(一种资产一个market,多对多借贷),是一整个的大资金混合池,可交叉借贷 和 贷出来的资产再次抵押借贷(加杠杆)。按ctoken 计算清算
  • v3 单个comet主池子(多对一借贷)。一种资产为base asset(基础资产),可存入 可借出,其他指定资产为 collateral asset (抵押资产,最多支持 15种)只能存入 不能借出,按整体 base资产的 ctokenv3 做清算

2 费率变更

  • v2 根据 市场利用率 计算(borrows / (cash + borrows - reserves)),supply 计算获得利息 和 borrow 计算归还利息(根据区块),可以通过exchangeRate一起算出,所有supply assets 都可以盈利

  • v3 资金利用率(totalBorrow/ totalSupply)有转折值 kink,利用率低于 kink 利率直线上升(根据时间),支持单独配置提供和借出kink

3 ctoken 变更

  • v2 supply 提供supply asset 对应的ctoken 作为可挖矿存储凭证(每个资产1个ctoken),v3提供 baseasset 的 ctoken v3(所有资产仅提供一种 ctoken,目前为 cUSDC v3 提案升级了一次),

  • v2 可激励 comp 平台币(按区块 supply和borrow),v3 最细开启激励平台币,只对borrow 进行激励

4 清算 变更

  • v2 清算叫 liquidiation,原本的清算机器人是检测所有的质押,然后指定一种 ctoken,针对ctoken 进行清算,(有大量的开源清算机器人,拼算力和速度 )

  • v3 清算叫 absorb,全新设计了一套清算引擎(撸代码中),分池子检测market,针对 全部资产(基础 资产 + 抵押品)进行清算,ctoken v3 只有 cusdc v3

  • v3 拆分了清算步骤,清算的抵押品 需要先将抵押品的归属权变更为 合约持有,记录gas消耗情况 和 清算数量+次数,然后可选的合约上 按照既定折扣购买抵押品(目前不限制购买人,任何人都能买可出售的抵押品)。

5 治理

  • v2 的治理 是通过dao 对整个 混合大资金池进行参数修改,风险较高

  • v3 治理 通过dao 对单个comet 资金池进行修改,且每个参数都提到了单独的合约 configer 中,操作起来更清晰,一旦出错 只是单个资金池出错

6 规模

  • v2 存款不限量, v3 现处于试运行阶段,对存入的整体池子抵押品总量有限额(2100个wbtc,27000个weth,其余资产见下方)
依次为:资产,预言机,代币精度,借贷因子,抵押品清算因子(计算是否能清算),清算折扣(被1减得到discount),可supply上限

---- comp
0xc00e94Cb662C3520282E6f5717214004A7f26888,0xdbd020CAeF83eFd542f4De03e3cF0C28A4428bd5,18,650000000000000000,700000000000000000,930000000000000000,200000000000000000000000,
 ---- wbtc
0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599,0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c,8,700000000000000000,770000000000000000,950000000000000000,210000000000,
 --- weth
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2,0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419,18,825000000000000000,895000000000000000,950000000000000000,27000000000000000000000,
 --- uni
0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984,0x553303d460EE0afB37EdFf9bE42922D8FF63220e,18,750000000000000000,810000000000000000,930000000000000000,1250000000000000000000000,
 --- link
0x514910771AF9Ca656af840dff83E8264EcF986CA,0x2c1d072e956AFFC0D435Cb7AC38EF18d24d9127c,18,790000000000000000,850000000000000000,930000000000000000,1250000000000000000000000

7 预言机模式变更

  • v2 获取chainlink 价格后,需要跟 uniswap v2 的池子做一次价格验证,偏差在允许范围内才是有效价格

  • v3 直接读取 chainlink 价格获取,不再依赖 twap,主要是预防 the merge 之后 防止价格操控 (关于twap 的不足说明可见 euler 的 提案),base 和 collateral 都有对usd的chainlink 预言机

8 代码更友好

  • v2 完整跑起来很费劲(最简化部署可见其他大佬的文档)

  • v3 有各种 官方周边仓库,(快速部署,各类操作,清算)不管干啥 快速上手

v3 详细介绍

费率

usdc 池子 kink supply 和 borrow 都为 0.8,资金利用率过高会导致利息剧增(按时间)

borrow 和 supply 可以配置成不同的,已经解耦,现在配置的完全一样是 80%

资金利用率计算

都有单独方法获取: Utilization = TotalBorrows / TotalSupply

借款利率

官方文档有误差实际去掉了 reserveRate相关内容,具体公式见下面

资金利用率 kink <= 0.8时 借款利率

BorrowRate = InterestRateBase + InterestRateSlopeLow * Utilization

kink > 0.8 借款利率

BorrowRate = InterestRateBase + InterestRateSlopeLow Kink + InterestRateSlopeHigh (Utilization - Kink)

存款利率

官方文档有错误实际这个没用,用的还是借款利率相同算法

资金利用率 kink <= 0.8时 存款利率 SupplyRate = (InterestRateBase + InterestRateSlopeLow Utilization) Utilization (1 - ReserveRate) kink > 0.8 存款利率 SupplyRate = (InterestRateBase + InterestRateSlopeLow Kink + InterestRateSlopeHigh (Utilization - Kink)) Utilization (1 - ReserveRate)*

基础池子 详细参数配置

"rates": { "supplyKink": 0.8, "supplySlopeLow": 0.0325, "supplySlopeHigh": 0.4, "supplyBase": 0, "borrowKink": 0.8, "borrowSlopeLow": 0.035, "borrowSlopeHigh": 0.25, "borrowBase": 0.015 },

备注: 其实代码跟公式对不上,没有 reserverate,而且两者 公式一模一样(借款利率)

compoundv3getrate.png

清算

查询可以直接查 isLiquidatable(account)

具体执行需要有2步操作:执行清算 和 购买抵押品, 第一步将抵押品交给协议,会记录liquidator 的记录,官方说后续给补偿; 对清算人来说关键抢的是第二步,按照reserves 的限额值 抢购打折抵押品(真正获利)

官方给出了一个使用uniswap V3 的 flason swap 的清算合约和检测,清算的例子

执行具体步骤

  1. quoteCollateral 获取报价,collateral 达到清算价位。
  2. 使用 flashswap 功能从给定的 Uniswap 池中借用base 资产。
  3. 调用absorb 方法 将抵押品归属权交给 合约
  4. 确实下是否 reserve < target reserve 否则不能购买抵押品
  5. 调用 buycollateral 购买打折的 collateral。
  6. 用 Uniswap 池将collateral 交换为base 资产。
  7. 偿还闪贷 手续费。
  8. 将利润(base token 的折扣)发送给清算人。

部分核心代码: 获取抵押品报价

 /**
     * @notice Gets the quote for a collateral asset in exchange for an amount of base asset
     * @param asset The collateral asset to get the quote for
     * @param baseAmount The amount of the base asset to get the quote for
     * @return The quote in terms of the collateral asset
     */
    function quoteCollateral(address asset, uint baseAmount) override public view returns (uint) {
        AssetInfo memory assetInfo = getAssetInfoByAddress(asset);
        uint256 assetPrice = getPrice(assetInfo.priceFeed);
        // Store front discount is derived from the collateral asset's liquidationFactor and storeFrontPriceFactor
        // discount = storeFrontPriceFactor * (1e18 - liquidationFactor)
        uint256 discountFactor = mulFactor(storeFrontPriceFactor, FACTOR_SCALE - assetInfo.liquidationFactor);
        uint256 assetPriceDiscounted = mulFactor(assetPrice, FACTOR_SCALE - discountFactor);
        uint256 basePrice = getPrice(baseTokenPriceFeed);
        // 主要是这里 可以看到 base 和collateral 都是通过本方法获取,清算的时候一起给回了reserve,但只有 collateral 可以购买
        // # of collateral assets
        // = (TotalValueOfBaseAmount / DiscountedPriceOfCollateralAsset) * assetScale
        // = ((basePrice * baseAmount / baseScale) / assetPriceDiscounted) * assetScale
        return basePrice * baseAmount * assetInfo.scale / assetPriceDiscounted / baseScale;
    }

清算时合约内部逻辑(将抵押品交给合约)

/**
     * @notice Absorb a list of underwater accounts onto the protocol balance sheet  清算入口合约(只会把抵押品给到合约)
     * @param absorber The recipient of the incentive paid to the caller of absorb
     * @param accounts The list of underwater accounts to absorb
     */
    function absorb(address absorber, address[] calldata accounts) override external {
        if (isAbsorbPaused()) revert Paused();
        uint startGas = gasleft();
        // 这里只是把抵押品给回了当前合约
        accrueInternal();
        for (uint i = 0; i &lt; accounts.length; ) {
            absorbInternal(absorber, accounts[i]);
            unchecked { i++; }
        }
        uint gasUsed = startGas - gasleft();

        // 这里记录了清算的消耗情况
        // Note: liquidator points are an imperfect tool for governance,
        //  to be used while evaluating strategies for incentivizing absorption.
        // Using gas price instead of base fee would more accurately reflect spend,
        //  but is also subject to abuse if refunds were to be given automatically.
        LiquidatorPoints memory points = liquidatorPoints[absorber];
        points.numAbsorbs++;
        points.numAbsorbed += safe64(accounts.length);
        points.approxSpend += safe128(gasUsed * block.basefee);
        liquidatorPoints[absorber] = points;
    }

购买抵押品

/**
     * @notice Buy collateral from the protocol using base tokens, increasing protocol reserves
       A minimum collateral amount should be specified to indicate the maximum slippage acceptable for the buyer.
     * @param asset The asset to buy
     * @param minAmount The minimum amount of collateral tokens that should be received by the buyer
     * @param baseAmount The amount of base tokens used to buy the collateral
     * @param recipient The recipient address
     */
    function buyCollateral(address asset, uint minAmount, uint baseAmount, address recipient) override external {
        if (isBuyPaused()) revert Paused();
        // targetreserve 之上,不允许购买抵押品
        int reserves = getReserves();
        if (reserves >= 0 && uint(reserves) >= targetReserves) revert NotForSale();

        // Note: Re-entrancy can skip the reserves check above on a second buyCollateral call.
        doTransferIn(baseToken, msg.sender, baseAmount);

        uint collateralAmount = quoteCollateral(asset, baseAmount);
        if (collateralAmount &lt; minAmount) revert TooMuchSlippage();

        // Note: Pre-transfer hook can re-enter buyCollateral with a stale collateral ERC20 balance.
        //       This is a problem if quoteCollateral derives its discount from the collateral ERC20 balance.
        withdrawCollateral(address(this), recipient, asset, safe128(collateralAmount));

        emit BuyCollateral(msg.sender, asset, baseAmount, collateralAmount);
    }

账户管理

借助 user nonce 模型,可以允许 其他账户 管理自己账户的 抵押品资产。 意义不明

社区治理

简化治理,治理系统更改,治理通过单个合约(配置器)进行(之前是统一的管理地址)

与v2 相同,社区投票,投票通过后执行 timelock,将提案 queue 上去,等待指定周期后 exec 即可。具体执行见v2就行。

预言机模式

完全依赖 chainklink 价格,每30分钟更新一次价格,通过configor 读取assetinfo 获取到地址(包含 basetoken 和 collateral 各类资产的对 usd价格),

compoundtulp.png

不适用 twap 的价格模式应该跟 the merge 有关。具体见 euler 的提案

核心合约-- 快速部署 3个代理 1个helper(bulker) "comet": "0xc3d688B66703497DAA19211EEdff47f25384cdc3", "configurator": "0x316f9708bB98af7dA9c68C1C3b5e79039cD336E3", "rewards": "0x1B0e765F6224C21223AeA2af16c1C46E38885a40", "bulker": "0x74a81F84268744a40FEBc48f8b812a1f188D80C3"

官方给的 uml 图

主逻辑调用和交互流程图

comentuml.svg

社区治理的调用流程图

gover.svg

代码小工具 SPEC 快速同步线上各种参数 spider 将合约同步到其他网络

个人观点

好处:

  • 风险低,没有交叉,仅单一资金借出,
  • 可扩展性高,后续可以提供
  • 可以通过设置变更 挖矿的币种和速率,通过rewardspeed 和 rewardtoken 调控平台币产出 (可变更为 其他币种产出但没必要)
  • 代码更清晰

    不足:

  • 不允许交叉借贷,只允许借出 base 资产
  • 仅适合 稳定价值的币种,对浮动较大币种 完全不合适

参考文档

compound v2 检测与清算机器人-- How to Build a Compound Liquidation Bot – bwd (baowebdev.com) compound v3 透明公正高利用率-- Compound III is Live. Transparent, fair, autonomous interest… | by Robert Leshner | Compound | Aug, 2022 | Medium 官方文档-- Compound III Documentation v3 的简单清算-- comet/contracts/liquidator at main · compound-finance/comet (github.com) compound v3 的改动-- 今日上线的 Compound III 都有哪些改动? | DeFi之道 (defidaonews.com)

点赞 7
收藏 3
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

3 条评论

请先 登录 后评论
ezio
ezio
0x1452...2E63
江湖只有他的大名,没有他的介绍。