深度研究丨有效市场下的闪电攻击
FlashLoan(闪电贷)跟当初的 MakerDAO 一样诞生很早,发力较晚,而一旦发力所带来的一连串连锁创新将引领整个 DeFi 行业迈向新的发展台阶。短短的一两年内,链上金融体系已经初步具备了现代金融框架,不仅可以自成闭环,同时在不断试探外部金融世界,正是这种永葆活力的崭新远景赋予了区块链世界永无止境的探索动力,不再停留在自我怀疑的困境中,如同当年的互联网一样,一切都在发展规律的冥冥护佑下不断蝶变。
(一)FlashLoan 原理
简单来讲,FlashLoan 可以让用户在一笔交易里原子性的完成从借款、一系列的资金利用、还款等操作,做到零成本贷款,仅从目前我们的认知来看,主要用途用于交易套利(如 DEX 和保证金交易平台),但随着 DeFi 的不断复杂和完善,不排除其他潜在用途出现。FlashLoan 是一种新的开放式借贷协议,任何借贷平台都可以选择支持 FlashLoan,从而给自己带来更多的想象空间和流动性。协议首先需要实现 FlashLender,由 FlashLender 帮助用户在一笔交易里完成如下操作:
- Borrow from any Lending platform
- executeArbitrage callback
- Profit
- Repay the entire amount borrowed, otherwise to Step 5
- the entire transaction revert, nothing happened
(a) FlashLender
帮助 Arbitrage 合约完成借款操作并调用其 callback
(b) Arbitrage
响应用户请求,调用 FlashLender 合约进行借贷操作,获取资金后调用 TradeExecutor 合约执行特别定义的资金操作
(c) TradeExecutor
往往需要配合一些 wrapper 合约对特定 DeFi 平台进行 API 调用并完成资金操作
(d) ExchangeWrapper (such as KyberWrapper, 0xWrapper, etc al)
这是一类针对 DEX 的 wrapper 合约,利用 DEX 的开发 API 操作,包含将 ETH 等在 DEX 上兑换成其他币种的逻辑,一般包含 getExchangeCost、getMaxMakerAmount、transferTakerFee、parseOrder、parseSignature 等类似方法。例如定义 0x 上的买单:
0xWrapperContract.methods.getTokens(orderAddresses, orderValues);
并由 TradeExecutor 合约 trade() 方法对其进行使用。
所以从以上看来完成一个 FlashLoan 协议的开发和支持是很简单的事情。然而正是这种简单让平台方对本应该配套的风险控制疏忽大意。在 MOV 的设计准则里一直有这么一句话:每多加一项单独的服务需要配套双倍的风控措施,而每叠加一项组合式的服务却需要配套十倍的风险管理。
(二)闪电攻击
目前 FlashLoan 引起了两起确确实实的金融套利攻击(我们并不认为这是黑客攻击),都是利用了 DEX 交易市场进行最终套利,而且表现出聚集性,前后周期非常短,(这群)攻击者显然已经非常熟悉整个 DeFi 市场数据和运作机制,而且展现了对 FlashLoan 的灵活运用,我们有理由相信,在接下来的几个月里还将会发生更加惊心动魄的攻击。先来看第一起攻击:
第一步(囤粮) :利用 FlashLoan 从 dydx 借出 10000 ETH
第二步(囤兵) :用其中 5500 ETH 从 Compound 借出 112 BTC
第三步(诈降) :去 bZx(“不自信”)做保证金交易,用 1300 ETH 开 5 倍杠杆,将借出来的 ETH 换来约 51 BTC,由于 bZx 使用的是 Kyber Network,而 Kyber Network 最终还是用了 Uniswap,这个过程大幅度拉高了 UniSwap 中 BTC/ETH 的价格,此时套利机会出现
第四步(总攻) :将 112 BTC 在 Uniswap 中卖掉,换取更多的 ETH,产生利润
第五步(止战) :归还 dydx 借款
逻辑很清晰了,问题根本在于 bZx 的保证金交易大幅度拉升 BTC/ETH 价格导致套利机会出现,而最最根本的问题却是 bZx 竟然没有爆仓:当 Uniswap 中 BTC/ETH 的兑换价从 39 被操纵拉高到 108 时,bZx 上的抵押品应该是不足的,会被爆仓,但 bZx 智能合约却没有要求增加保证金,也没有进行清算。因此本质上是将 bZx 资金池里(大家的)ETH 通过 Uniswap 转移到了从 Compound 借出的 BTC 身上,bZx 储户承担最后的亏损。同时 Uniswap 来回走了两遍,即第一遍用 bZx 杠杆借出的 5637 ETH 换了 51 BTC,第二遍反向,用 Compound 借出的 112 BTC 换了 6871 ETH,所以最后会导致 Uniswap 上 BTC/ETH 均价在 (6871-5637)/(112-51)=20,是低于正常价格 39,因此在第二遍砸盘中,会有一部分 BTC 属于亏损出货,大概 60 BTC 差不多属于对折出售,而亏损的钱被 Uniswap 的做市商赚走了。所以这次攻击,是攻击者充分利用 Uniswap 滑点保护缺陷和 bZx 保证金杠杆交易合约缺陷完成的。
注:关于 bZx 合约缺陷。在其合约代码中有一个 require 调用来检查该头寸是否健康(healthy position),然而由于低级的代码错误(或者风控意识欠缺),仅在 loadDataBytes.length == 0 && sentAmounts [6] == sentAmounts [1] 的情况下,就可以绕过完整性检查(sanity check),最终跳过清算 bZxOracle :: shoudLiquidate。虽然在第一次攻击后,项目方紧急修补了自身合约缺陷,但紧接着的第二次攻击,则充分利用了 bZx 严重依赖链上预言机获取定价的风险缺陷:
第一步(打入敌人内部):从 bZx 本身通过 FlashLoan 借出 7500 ETH
第二步(牺牲小我):用 540 ETH 在 Kyber 上购买了 92419.7 sUSD,导致 WETH/sUSD 价格瞬间拉低,做多了 sUSD,Kyber 使用了 Uniswap,因此影响到了 Uniswap 上的兑换率,攻击者很聪明,转而用18次小额(20 ETH)继续砸盘拉高 sUSD,最终导致 Uniswap 中 sUSD/WETH 为 1:157,大大偏离正常价格
第三步(援军包围):从 Synthetix 借走所有的 sUSD,然后砸向 bZx,由于 bZx 严重依赖 Uniswap 报价 sUSD,导致攻击者的 sUSD 在 bZx 上价值远高正常价值,兑换出了大量的 ETH,完成套利
第四步(把叛徒还回):向 bZx 归还 7500 ETH
这是一次非常经典的预言机攻击,全程干净利落。我们认为攻击者对 sUSD 的市场行为和套利空间了若指掌,所以一针见血的选择了 sUSD 和 Synthetix 作为援军,而援军表现的也是十分给力,不仅给出了全部家底,而且成功让 bZx 死心塌地相信 Uniswap 的报价,也没有给 sUSD 在其平台的兑换过多的风控限制。
第二次攻击的影响和意义要超越第一次,这给目前所有 DeFi 产品在预言机喂价机制上开始做出改变和风控管理,才能获取真正的公平市场价值(FMV,fair market value)。预言机大致分为五种:
(1)链下中心化预言机:从单一链下金融系统获取 FMV
(2)链下去中心化预言机:从多个链下金融系统获取 FMV,而且由多方分别掌握,并通过数学公式整合多个价格
(3)链上中心化预言机:往往是单一的 DEX
(4)链上去中心化预言机:由生态治理者参与喂价共治
(5)常量预言机:一般用于稳定币喂价,比如美元稳定币只接受现实世界美元价格
下面是几个主要 DeFi 之前的预言机选择:
在经过闪电洗礼后,所有的 DeFi 都需要重新思考预言机建设。从另一方面看,小型或者劣质 DeFi 因为没有能力和资金去维持运转综合性的商业成熟预言机(自建或者合作),会在闪电攻击的威胁下不断走向死亡,完成 DeFi 生态的优胜劣汰。但从风险管理的角度,重视健壮预言机的建设只能属于缓解措施,并不能从根本上克服闪电威胁,比如给预言机采取如下措施:
- 不要把市价中位数当成喂价,一笔大交易就可以轻松改变市价中位数。
- 充分利用区块,FlashLoan 只能影响到单个区块的世界(状态),可以考虑利用前后多个区块状态信息进行喂价,比如用时间加权平均价格(TWAP)或成交量加权平均价格(VWAP)计算上一批 N 个区块的加权平均数。
- 发力建设和依赖外部预言机。
- 智能合约系统在每次获取喂价时都要增加风险检查(汇率变化范围,多个来源对比校验)的代码。
- 即便没有闪电攻击,攻击者依然可以用较少成本影响到 Uniswap 在短时间(一个区块)内的价格(比如在流动性池大小为 1000 ETH 时,用 0.025 ETH 成本就可以在一个区块中产生 1% 幅度的价格操纵)。所以对于其他依赖方来说,不能依赖 Uniswap 在短时间内的价格波动,也不能依赖在短时间内的喂价输出。
(三)继续攻击
这一切并没有结束。
DDEX 拥有 ETH/DAI 保证金交易市场(提供杠杆多头和空头头寸),其喂价系统先检查 Eth2Dai,如果价差太大则从 Uniswap 读取。
function peek()
public
view
returns (uint256 _price)
{
uint256 eth2daiPrice = getEth2DaiPrice();
if (eth2daiPrice > 0) {
_price = makerDaoPrice.mul(ONE).div(eth2daiPrice);
return _price;
}
uint256 uniswapPrice = getUniswapPrice();
if (uniswapPrice > 0) {
_price = makerDaoPrice.mul(ONE).div(uniswapPrice);
return _price;
}
return _price;
}
第一步:从 dYdX 闪电贷出一笔 ETH
第二步:用一部分 ETH 吃掉 Eth2Dai 所有 DAI/ETH 卖单,拉大价差,让 DDEX 拒绝 Eth2Dai,选择 Uniswap
第三步:在 Uniswap 上用 ETH 做多 DAI,使 DAI/ETH 兑换率大幅度降低
第四步:在 DDEX 上抵押手里的 DAI 杠杆换取远远高于抵押价值的 ETH
第五步:向 dYdX 还款,剩下的即为利润
在这次攻击中,充分利用了 DAI 交易市场的特性:DAI 正逐渐普及到主流币种交易对以及保证金交易中,所以也相应获得了攫取大资金财富的地位。同样,在各种各样其他交易平台上,出于急功近利的目的,不假思索随意上币随意开通杠杆市场,势必给予 FlashLoan 攻击小币种交易对进而攫取主流资产的机会。而在去中心化金融这个世界里,攻击可以在一瞬间覆盖所有金融系统,引发可怕的连锁灾难,即便是自身风控做得再好的头部 DeFi 项目也会因此受到影响,“劣币驱逐良币”再次上演。
尤其是除了以太坊之外,越来越多的公链生态走向 DeFi 战略,即便官方自身推出的 DeFi 服务风控再好,但我们没法要求生态所有的开发者都能够意识到风险,比如出于成本考虑,很多刚起步的 DeFi 项目都会依赖官方 DEX 的喂价,而闪电攻击的存在可以轻而易举吃掉 DEX 的所有挂单,进而影响喂价输出,一点带动全面,将放射状袭击到其他生态 DeFi,即便在某个 DeFi 上获利不足以覆盖攻击成本,但所有被牵扯的 DeFi 获利加到一起也足以攫取利润,或者叫做闪电攻击攫取长尾利润,而这在除以太坊外其他公链 DeFi 系统上将更为常见和有效。
我们前面也讲过,目前我们只看到了闪电攻击对交易市场的影响,但一定还会存在其他领域的灾难,只要有币的地方理论上就有闪电攻击。随着治理开始走向 DeFi 系统,升级成所谓的 DAO,这也给了 FlashLoan 攫取政治权益的机会(借出大量的治理 token 参与投票进而操纵整个系统),所以最近也经常看到很多带有治理机制的头部 DeFi 在重新修改治理合约和风控机制。
在去年 12 月,Augur 白皮书作者 Micah Zoltu 指出 MakerDAO 存在治理漏洞:攻击者只需动用 40000 枚 MKR(约 2000 万美元)就可以在短短 15 秒内盗取 Maker DAO 的所有抵押资产。包括 DAI、SAI 以及来自 Compound、Uniswap 等集成 Maker 的系统的大量资产(超过 3.4 亿美元)。这在当时,大家也就随便一听,虽然有漏洞但是几乎没有哪个攻击者可以拥有数千万美元的 MKR,即便有也是可以追踪到的。但如今闪电攻击改变了游戏规则,尤其是随着 MKR 不断涌向流动性市场(不再单纯被基金会锁定),从流动性市场集齐攻击成本的可能性在不断增加。攻击者可以从支持 MKR 的多个 DEX 市场(如 Kyber、Switcheo、Uniswap)分批购买不同额度的 MKR,另外也可以借助预言机攻击,恶意拉低其他支持 MKR 交易借贷的平台的喂价,然后以低成本获取更多的 MKR,或者将这两种方式组合到一起,最终如果能够成功占领治理合约,所获的的利润将远远超越这几千万美元的资产,也是十分可怕的。我们也看到 MakerDAO 采取了相应的风控措施,比如增加投票生效延迟,只要延迟到两个块以上,就能让闪电攻击化为乌有。
是否会加剧借贷市场的挤兑风险概率。即连续大规模贷款导致流动性枯竭,贷款方失败的影响可以控制,但对于需要提现的存款方当发现无法提现时,恐慌的市场情绪可能会带来严重的挤兑风险,对整个系统的破坏是根本性的,我们从以太坊数据分析平台 Alethio 提供的图可以知道这种流动性枯竭危机即便在 Compound 上依然是常见的。所以一方面攻击者在完成闪电攻击套利,另一方面也加剧了借贷平台流动性枯竭引发的挤兑风险。
另外,FlashLoan 如同一个暗池一样,可以让攻击者肆意发挥而无法追踪,完成攻击后也留不下任何污点。而在这之前大额攻击者的地址可以不断对其进行跟踪分析甚至请求中心化交易所锁定禁止套现。而传统大额攻击本身存在风险,只有全部算对的情况下才能获利,一旦中途出现意外,很有可能搭上自己的资产,而 FlashLoan 要么成,要么什么都没发生过,大家也永远不会知道哪个地址在蠢蠢欲动。
最后,我们还需要持续关注 FlashLoan 通过对不断壮大的 DeFi 资产侵略战争性的操纵进而对主流市场行情的影响,比如影响到中心化交易所 ETH 的价格等等,避免由一场“闪电战”席卷欧洲带来的世界大战。
(四)有效市场与 FlashLoan 套利存在性
1970年美国金融学家法玛提出“有效市场假设”:在有效市场的假设下,股价能够充分反映所有信息,因此不合理的价格将被很快消除。在有效市场上,所有信息都会很快被市场参与者领悟并立刻反映到市场价格之中,从而使得该组信息所进行的交易不存在非正常报酬,而只能赚取风险调整的平均市场报酬率。在现实金融世界中,只要证劵的市场价格能充分及时地反映了全部有价值的信息,市场价格代表着证劵的真实价值,这样的市场被称为“有效市场”。而在新兴的去中心化金融世界里,有效市场也无处不在,比如套利的存在和抢先交易(Front Running),而这也正是 FlashLoan 存在即合理的本质,并将伴随着有效市场而无处不在。套利机会在金融市场中以各种形式存在,套利也正逐渐成为 DeFi 金融体系赖以生存的重要活力和风险控制措施,很多交易所之间有着套利机会,套利有助于减少资产在不同市场中的价格差异,还有助于提高流动性。比如 Uniswap 正是通过套利行为的存在实现了恒定乘积的做市算法,交易者可以利用其他加密货币交易所的兑换率来纠正 Uniswap 上可能出现的价格偏差,但同时也不得不面对套利带来的负面影响,一切都是正反面的合理存在博弈。
我们可以先来看几种常见的 FlashLoan 和平套利法。
交易所套利。例如 DForce 创始人提到,利用成为 Uniswap 流动性提供者可以大幅度降低手续费的机制完成套利。
第一步:通过 FlashLoan 从 dYdX 借出大额 ETH原本正常交易手续费是 0.3%,但现在只需要 0.05%,因为成为 DAI 流动性提供商可以获得 82% 的手续费返佣。第二步:将 ETH 抵押到 MakerDAO 借出 DAI
第三步:用借出 DAI 到 Uniswap 提供 DAI 流动性
第四步:在 Uniswap 执行所有 DAI 相关交易
第五步:归还贷款
自动化零成本再融资。将原本抵押在 MakerDAO 中的 ETH 取出来,到 Compound 上再抵押,以获取更高的市场利率。原本用户需要一定的资金去向 MakerDAO 赎回资产,虽然有着利率的诱惑,但增加了用户的操作和成本,也降低了积极性,我们可以借助 FlashLoan 打造一种崭新的有效市场工具产品。
第一步:通过 FlashLoan 借出足额 DAI,关闭 CDP至此我们完成了自动化零成本再融资。第二步:取出的 ETH 一部分在 Uniswap 上换取 DAI,用于最后的等额还款,剩下的 ETH 存入 Compound
第三步:还款
清算套利。在稳定金融系统里,经常要面临被清算,而一旦无力追加抵押,清算将会导致高达百分之十几的清算费用。同上,通过 FlashLoan 借出需要归还的资产,关闭抵押合约拿回抵押资产,随后再完成代币兑换,还回 FlashLoan 借出资金即可,及时避免了被清算。这也启示我们这种实时性的工具是可以配合稳定系统本身清算机制成为一种优良的风控辅助措施的,尤其是在官方清算体系和市场套利清算者不多的情况下,借助 FlashLoan 的自动化工具将市场下跌带来的清算风险迅速化解,对用户对系统本身都是 win-win。
抢先交易。跟 FlashLoan 一样,抢先交易即是一种需要防备的攻击,也是一种合理存在的套利行为。简单来讲,抢先交易是指在得知对手方交易意图后,抢先完成自己的交易,比如 Tom 计划买入大量 ETH,Jerry 知道了 Tom 的意图,就可以抢先在 Tom 之前以当前价格买入 ETH,然后转手以更高价格卖掉,赚取差额。这在现实金融世界里是违法的,因为利用的是非公开信息,但在去中心化金融世界里,一切信息都是公开合法的,所以我们将抢先交易归为有效市场,并尊重这种行为的存在,当然也会采取一定的措施,让充分市场竞争逐步消除抢先交易带来的短期市场不平衡现象。在这里我们也想强调一种跟链上金融风控体系息息相关的而往往被忽略的概念—— 链上原子时间与可预测的未来。在现实世界中,不存在原子性的时间,也不存在可以预测的未来,但是在区块链世界,区块是原子时间,而未来也可以被编排(orchestration)。交易被广播到网络,进入 mempool,任何人都可以去监听,所以对于交易者、机器人、矿工来说,是可以在一定程度上准确预测交易组合产生的世界状态更新,也就可以通过抢先交易完成博弈和无风险盈利。FlashLoan 恰恰也是利用了原子性的区块时间概念,在充分评估将要发生的区块里所包含的不利信息(交易),在确定没有阻碍(或者竞争)时,构造了一笔准确刻画未来的交易完成无风险套利。随着抢先交易和 FlashLoan 带来的新有效市场的形成,自然也会出现竞争对手开始在原子时间里跟攻击者对抗未来,或许会造成攻击者失败,也或许是与攻击者共存,借着攻击者的攻击过程喝一口“肉汤”,比如用于对抗闪电攻击的机器人可以在检测到即将要包含到区块中的交易存在一笔路径清晰的闪电攻击,就可以去其要拉盘的 DEX 上挂高点埋伏,等待被闪电攻击以远高于市场价格成交。
闪电做市。DeFi 生态依赖做市商,而做市商依赖原始资本。在刚起步的公链 DeFi 生态中,是否存在将 FlashLoan 结合到做市商机制的可能性,进而带动零成本闪电做市的市场。这里有一个粗糙的想法:
(1)用户 A 在某公链官方 DEX 上发起 40 ETH 兑换 1 BTC 的交易,但无做市商及时响应(2)闪电机器人捕捉到该笔交易,立即从公链借贷市场通过 FlashLoan 借出 1 BTC,并与用户 A 订单进行撮合,换得 40 ETH(为了简化计算,这里暂不出现利润部分)
(3)机器人不断寻找当前其他交易市场中 ETH/BTC 订单,如果存在可以将 40 ETH 换得至少 1 BTC的对手方,则执行兑换并还款操作,完成闪电做市,如果未找到匹配订单,则做市失败,并无损失
此外,或许也可以成为 DEX 或者借贷平台刷量的工具而存在。
(五)MOV 的可组合性与叠加风险控制
MOV 是一种融合 DEX、借贷、稳定金融系统、金融衍生品市场的综合性组合金融体系,我们称之为 S.O.L.D 金融体系(StableCoin,Oracle,Lending,DEX)。可组合性使得我们尊重套利的存在,同时也配套了十倍的风险管理机制,一般来讲风险管理分四个方面:套利漏洞、审计漏洞、风险预测以及风险控制。假如一个 DeFi 生态中拥有 n 个不同应用,则相对应的风险复杂度为 2 的 n 次方(C(n,0)+C(n,1)+C(n,2)+......+C(n,n)=2^n)。尤其对于 FlashLoan 等创新 DeFi 出现,我们希望可以将有利的一面为我所用,成为弯道超车的利器,另一方面,将通过自身强大的风控体系将不利的一面牢牢关在笼子里。在这里也借着 FlashLoan 事件简单提几点 MOV 在控制叠加风险上的原则和措施。
在现实金融世界里,金融危机的发生大多与肆无忌惮无处不在的杠杆有关,例如 2008 年的次贷危机,一个优良的链上金融体系也应该对杠杆设计心存敬畏,DeFi 并不等于“狂加杠杆”。 想象一下,尤其是有了 FlashLoan,无限借贷+无限杠杆,将是多么可怕的核武器。在 MOV 的生态建设上将牢牢贯彻稳定金融的使命,对自身以及生态参与者在杠杆产品的设计上会给予充分的风险警示和风险评估,对于高度风险的 DeFi 项目将会限制其对重要 DeFi 系统或者其他 DeFi 体系的无缝连接,避免因其自身风险带来的一系列组合风险。这也是 MOV 跟以太坊 DeFi 体系不同的地方之一,MOV 会存在一个十分负责的强有力中央风控指导体系。
另外就是在预言机建设上,从一开始生态蓝图架构之初,我们就十分重视生态预言机系统的风控问题,不仅选择自研体系,包括外部世界输入(QKL123.com)以及链上预言机,同时也十分重视跟顶级预言机提供商(如 ChainLink)合作共建,避免单点遏制,同时也会把这种预言机体系在 MOV 生态开放,供其他小项目方无成本对接,避免因遭受预言机攻击带来的损失。
叠加风险的控制问题一定程度上就是资产的选择问题,在最近发布的《MOV 稳定金融体系》白皮书中,我们给出了资产组合(portfolio)的选择原则和关联度风险评估机制,在 FlashLoan 给予的启示里,资产应该更加谨慎的进入到不同的 DeFi 系统里,比如对于生态至关重要的 MOV 稳定币资产或者权益资产,就不太适合过早进入大流动性市场和杠杆交易市场。MOV 生态治理(包括风险权益)的一个重要法则就是慎用治理,这也把以 FlashLoan 为代表的新型攻击产物在未来可能产生的系统性破坏降到最低。
其次还有链上信誉体系等辅助手段,尤其是在特定应用防闪电攻击时,可以要求参与地址拥有一定的资产 Merkle 证明或者信誉凭证。
在生态设计过程中,我们便评估了 Uniswap 的风险(滑点)问题,因此 MOV DEX 将优先推出订单簿撮合以及做市 DEX。请期待即将上线的 MOV !