20856 large

0 美元就能买到以太坊?分析 MakerDAO 的清算机制缺陷及改进思路

why_ly · 于 发布 · 46 次阅读

撰文:David Lei ,Fuxing Chen

2020年3月12日,由于COVID-2019的全球爆发,引发了加密货币市场的一系列黑天鹅事件,整个市场全线崩溃。同时,以太坊ETH的价格暴跌,MakerDAO的大量抵押债仓跌破清算门槛,引发了清算程序执行。

根据MakerDAO的系统设置,被清算的抵押物相比市场价存在折扣,因此能够吸引清算人参与其中,参与拍卖的清算人持续叫价,起拍价为0 DAI,最终获胜者至少可以获得3%的折扣。而实际情况里,往往抵押物的最终清算价差会大于3%,清算人的获益会更高。

也就是说,假设一共有市场价值1500 DAI的抵押物进行拍卖,对于清算人而言,最差情况下,参与者最高出价到1455 DAI就可以拍得这批抵押物(不计算其他费用)。而最好情况下,则有可能以0 DAI获得拍卖的抵押物。

只存在于理论里的0 DAI拍卖,在昨日实实在在的发生了。

根据媒体报道,由于以太坊网络gas费用剧增,导致MakerDAO的清算过程完全缺乏竞争,原本应该参与到清算过程中的清算机器人(Keeperbot)因为设置了较低的gas值,导致出价受阻,一位清算人(Keeper)在没有竞争者的情况下,以 0 DAI的出价赢得了拍卖。

笔者在此从MakerDAO的合约代码层面,分析0 DAI事件的根本原因。

对于MakerDAO系统而言,当产生清算时,意味着系统会有潜在的债务损失,因此,为了避免损失,MakerDAO通过一种拍卖机制来对CDP持有者进行抵押物的清算。

在拍卖开始之前,首先要确定的,是被清算的抵押物数量以及相应的债务,这依赖于一个MarkerDAO系统中事先预设的分割值lump。也就是说,待清算抵押债仓CDP内的抵押物数量会被分割成为m批,

m=⌊n/lump⌋+1

对于ETH-A,在当前的MakerDAO合约部署配置文件里,lump被设置为50:

"tokens": {
    "ETH": {
      "gem": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
      "pip": "0x81fe72b5a8d1a857d176c3e7d5bd2679a9b85763",
      "ilks": {
        "A": {
          "mat": "150",
          "line": "0",
          "dust": "20",
          "duty": "4",
          "chop": "13",
          "lump": "50",
          "beg": "3",
          "ttl": "600",
          "tau": "259200"
        }
      }
    },

所以实际被清算的数量lot (lot≤lump)被计算为

MIN(用户CDP抵押物总量, 50)

在确定了被清算的抵押物数量之后, 紧接着需要确定这笔抵押物所对应的的债务数量art。

MakerDAO的算法是根据lot在用户CDP中抵押的ETH-A总量确定其占比,然后该CDP内所有ETH-A所对应的总债务的同等占比值即为相应的债务值,在代码里表示为

mul(lot, art) / ink

但是art仅是单纯的抵押物与债务的对应值, 并没有考虑利息,所以, 如果这部分抵押物被清算,那同样也要归还相应的债务,因此实际这部分抵押物对应的债务为art * rate;

MakerDAO的清算罚金机制里,目前罚金的比例被配置为13%,所以实际要被拍卖的目标金额tab为

tab: rmul(mul(art, rate), ilks[ilk].chop)

综上, 发起一笔抵押物拍卖(flip.kick)时,抵押物的数量为lot, 预期拍卖的目标金额为tab。

MakerDAO将抵押物拍卖设计为二阶段拍卖,其中第一阶段是一个“试价”的过程,就是参与者正向加价,直到出价满足tab。基于此设计,MakerDAO将拍卖起始价格设置为0。理想情况下,参与者会衡量清算物lot的市场价值,以一个较为合理的价格进行叫价。

// --- CDP Liquidation ---
    function bite(bytes32 ilk, address urn) external returns (uint id) {
        (, uint rate, uint spot) = vat.ilks(ilk);
        (uint ink, uint art) = vat.urns(ilk, urn);

        require(live == 1, "Cat/not-live");
        require(spot > 0 && mul(ink, spot) < mul(art, rate), "Cat/not-unsafe");

        uint lot = min(ink, ilks[ilk].lump);
        art      = min(art, mul(lot, art) / ink);

        require(lot <= 2**255 && art <= 2**255, "Cat/overflow");
        vat.grab(ilk, urn, address(this), address(vow), -int(lot), -int(art));

        vow.fess(mul(art, rate));
        id = Kicker(ilks[ilk].flip).kick({ urn: urn
                                         , gal: address(vow)
                                         , tab: rmul(mul(art, rate), ilks[ilk].chop)
                                         , lot: lot
                                         , bid: 0
                                         });

        emit Bite(ilk, urn, lot, art, mul(art, rate), ilks[ilk].flip, id);
    }

    function cage() external note auth {
        live = 0;
    }
}

重点来了, 起拍价为0其实是做了一个假设:一定会有足够数量的Keeper参与到拍卖中。

很遗憾的是,当以太坊网络剧烈拥堵时,普通Keeper在面临的高昂的gas费时很可能没有动力参与到拍卖中去。另一方面,善良的Keeper bot也很可能因为其在gas升高时没有及时调整gas上限, 竞拍交易迟迟不被确认而无法维持拍卖系统的正常运作。

因此,恶意竞拍者就可以出价0 DAI而获胜。

让我们跟踪一下0 DAI是如何叫价成功的,下面是竞拍流程的代码:

function tend(uint id, uint lot, uint bid) external note {
        require(bids[id].guy != address(0), "Flipper/guy-not-set");
        require(bids[id].tic > now || bids[id].tic == 0, "Flipper/already-finished-tic");
        require(bids[id].end > now, "Flipper/already-finished-end");

        require(lot == bids[id].lot, "Flipper/lot-not-matching");
        require(bid <= bids[id].tab, "Flipper/higher-than-tab");
        require(bid >  bids[id].bid, "Flipper/bid-not-higher");
        require(mul(bid, ONE) >= mul(beg, bids[id].bid) || bid == bids[id].tab, "Flipper/insufficient-increase");

        vat.move(msg.sender, bids[id].guy, bids[id].bid);
        vat.move(msg.sender, bids[id].gal, bid - bids[id].bid);

        bids[id].guy = msg.sender;
        bids[id].bid = bid;
        bids[id].tic = add(uint48(now), ttl);
}

前三个require是检查时间和系统状态的,这都是可以通过的;

第四个require检测的是第一阶段的出价必须固定要竞拍的抵押物数量, 也就是上面发起拍卖时计算的lot;

第五个require检测的是第一阶段的出价最大只能到tab,相当于债务拍卖只卖出预期的债务数量;

第六个require检测的是当前出价必须大于上一次出价;

重点是第七个require,检测的是当前出价必须大于一定的增价幅度(beg,比如说5%)。但是上面笔者提到过,发起拍卖时bid的值为0,

bids[id].bid == 0

因此,如果恶意Keeper出价为0,即bid == 0,require表达式会变成

require(0 * ONE >= beg * 0)

攻击者因此毫无阻碍的以0 DAI叫价成功。

等到竞拍周期结束以后,如果没有其他人跟恶意Keeper竞价,恶意Keeper就可以0 DAI成交。

到此为止,问题产生的核心就从代码层面分析完了,MakerDAO系统拍卖机制的其他细节可以参考:
https://github.com/makerdao/dss

MakerDAO的清算拍卖设计的目的,是尽可能的以最少的抵押物回收最大的DAI,这一机制在正常情况下是可以成功运作的。但是当以太坊系统极其拥堵的时候,或者更极端一点来说,只要竞拍的参与度不足,就很容易被恶意Keeper通过极低报价获得拍卖物。

MakerDAO作为如今DeFi生态的核心项目之一,在极端的市场行情下出了这起严重事故,造成了400万美元的系统债务,在不得已的情况下,系统启动了债务拍卖,将释放MKR代币进行拍卖,以弥补整个系统的债务损失,而这些损失,需要全体MKR的持币者承担。

根据墨菲定律,当一个灾难具备理论上发生的可能性时,无论其概率有多小,最终都是有可能发生的,MakerDAO在清算机制上的设计过于简单,过于依赖链上操作,最终造成了这次的债务危机。

可惜了一直相信MakerDAO,相信DeFi的核心用户。DeFi的高速发展过程中留下了诸多隐患,从bZx闪电贷事件,到Curve合约攻击事件,再到MakerDAO的0 DAI清算危机,大家用自己的真金白银,为有漏洞的产品设计买了单,DeFi在其尚且年幼的阶段,就承载了过多的价值和风险,不禁令人为之惋惜和捏一把汗。

下一个爆雷的DeFi应用,会是哪一个?受到的损失,又会有多少?

MakerDAO社区目前已经紧急讨论了针对清算机制的改进措施,目前,社区提出了一个可能的改进方案——MakerDAO Keeper Pool,其要点主要有:

1. 启动基于Web的Keeper,让用户能够通过浏览器的界面操作Keeper参与清算,降低清算的参与难度;

2. 将Keeper的代码和模板开源,并且降低部署难度;

3. Non-custodial MakerDAO Keeper Pool,建立类似于第三方Keeper流动性池的设施,通过Keeper的收益分配,吸引外部资金注入。

笔者在此无意评价该方案的优劣,只是,由某种理念或优势成长起来的事物,最终往往被其理念/优势所困而无法获得持续性的发展,这种现象在自然界的发展过程中已经被无数次的证明。历史上,武装到牙齿的恐龙,曾经在地球盛极一时,可最终却因为身体过度特化,不适应环境的剧变而灭绝。

DeFi,受益于去中心化这一理念,诸多项目获得了资金和市场的广泛支持,最近一段时期,获得百万美元甚至千万美元级别融资的DeFi项目比比皆是。

然而,福兮祸之所伏,过于强调去中心化,恰好成为了MakerDAO清算危机的潜在原因。

我们不妨用另一种视角看待清算拍卖这一环节。

下图是淘宝法拍的界面,可以看到,在中心化的服务领域,拍卖系统已经发展得足够的完善。集中化的报价和处理系统,既能避免链上拥堵造成的毁灭性后果,又能够促进更多的用户参与到拍卖的过程中来,表面上中心化的淘宝拍卖,参与的人数和地域却是足够分布式。

如果一个清算拍卖系统,把报价这一环节放到链外,公开透明的集中处理,而只将最终的结果提交到链上进行执行,就能够彻底的避免MakerDAO类似的事件再次发生。

为了能够更加有效的开展服务,笔者认为,要不要在中心化和去中心化之中进行适当的trade-off,这是值得DeFi的从业人员进行仔细的思考和权衡的重大问题。

笔者所在的The Force Protocol项目,开发了去中心化稳定币QIAN,就针对MakerDAO设计当中诸多的不足之处进行了改进。

例如,在清算拍卖环节,QIAN系统就采用了上述的集中报价机制,测试环境下能够极大的提高清算流程的效率,近期QIAN稳定币的清算拍卖系统就将与用户见面。

此外,QIAN还有多个独有的技术特点与产品设计,欢迎感兴趣的朋友访问QIAN的Github代码库进行研究,以及到QIAN的官网试用产品:

QIAN代码库:
https://github.com/theforceprotocolgroup/QIANstablecoin

QIAN官网:
https://qian.theforceprotocol.com/#/home

技术和产品的进步永不停歇,DeFi近期经历的各种打击,正是整个生态走向成熟过程当中的历练。行业经过自我反思和纠错以后,DeFi会发展得更好。笔者相信DeFi光明的未来,并与团队为之而不懈努力。

  • 暂无回复。