以太坊合约之间的交互是通过互通消息实现的状态一致,且允许重入、动态调用,这一特点为实现闪电贷提供了基础。期间,合约之间的函数可以互相来回调用——调用过程中会发生控制权转移。如果 DeFi 项目平台合约有漏洞,套利者能够利用其合约的恶意代码调用相应函数进行资产盗取——利用合约之间的状态同步信息差,在一个流程未结束时双花资产(以太坊资产只是赋值),或者重复执行函数(本该不被允许的逻辑)进行盗取。$ l/ n, M( [2 L( `' r
重入攻击的前提是攻击者部署的合约存在恶意代码,但最核心的因素是:8 {, R. @6 |7 t t
" w# X* @& B# K( |3 |
以太坊合约调用时控制权存在转移,这为恶意合约提供了主动权;且流程在结束之前可以重入(重复调用),恶意合约可以利用漏洞反复调用函数实现资产盗取(如一笔取款流程未结束时反复提取很多次);加上以太坊账户资产是以数值余额的形式存在,因此存在反复盗取资产(双花)的可能,或者在流程结束之前恶意合约就可以修改相关账户资产余额数值实现盗取。Move 提出了闪电贷的新一种运行流程——烫手山芋模式,根本上弃用可重入。「烫手山芋(hot-potato)」模式是一种没有 key、store、copy 和 drop 能力的结构,是 Move 程序在交易执行期间仅使用一次的结构。由于没有 drop、key 或 store 能力,因此烫手山芋只能通过调用「销毁」函数来完结流程——这就如其名所示意的一样,这是一块烫手山芋,在流程中任何处置都是「烫手」的,只能交给销毁函数来完结。具体流程如下:- p+ D- P/ h: E4 M6 @
8 N5 s* n: C" x) Z& ]
闪电贷智能合约在工作时会创建了「烫手山芋」(hot-potato)的收据(receipt);套利者向闪电贷合约贷款时,闪电贷合约发送贷款资金和一个烫手山芋收据(receipt);套利者利用贷款资金进行套利操作;套利者还款时,调用还款函数(repay),将资金和收据(receipt)发给还款函数,收据被还款函数接收后销毁。闪电贷完成的前提的最后正确还款、流程结束,在流程结束之前恶意合约可以在以太坊系统实现重复调用、修改相应的资产账户赋值实现盗取。Move 系统闪电贷流程结束的前提除了正确归还资金之外,还需要将烫手山芋这个资源进行一次性回收销毁处理,这确保了闪电贷的原子性。
1 B2 m$ R) o" ^% ~- v5 j; t& t
风险提示:区块链商业模式落地不及预期;监管政策的不确定性。$ v4 Y; {7 c& \8 o3 b8 j
1.核心观点闪电贷作为以太坊 DeFi 生态最具特色的应用,其基础是以太坊使用的 Solidity 语言允许动态调用和重入。虽然这种动态调用是智能合约开放性、可组合性的重要体现,但其带来的控制权转移和对合约函数的重复调用带来了不小的安全隐患,行业内利用闪电贷攻击有漏洞的 DeFi 资金池事件时有发生。由于 Move 语言不允许动态调用和重入,它使用一种「烫手山芋」模式很简单地实现了闪电贷,因此完全可以避免以太坊那样的安全问题。4 @+ W3 i# i- K$ H
7 [ A, _4 X) t _+ S( e4 U! T
两种系统在生态应用的工作模式有着明显的区别,这种差别的根本在于 Move 底层语言的特点,我们在前一篇报告《Web3 底层语言:Move 弥补了 Solidity 哪些不足?》已有详述。本篇报告从闪电贷应用角度来比较一下两者实现应用的不同玩法。3 F9 Z% m& h' z, {3 s/ L+ G
2.以太坊闪电贷的基础:动态调用与可重入闪电贷(Flash Loan)是一种原生的 DeFi 新产物,可以理解为极速贷款。用户只需要在同一笔交易(区块)中完成借贷、套利、偿还并支付一笔手续费,由于是原子交易,那么借款人无需抵押任何资产即可实现借贷,提供了一种无本金套利方案。
我们在上一篇报告《Web3 底层语言:Move 弥补了 Solidity 哪些不足?》中提到的:8 p- c5 q* K; X* L" |
+ |$ n5 o) a w% B' E; D! `
「对于模块化和合约组合性方面,Solidity(如以太坊)上面的 Contract 合约通过 library(相当于静态库)进行消息的传递,从而实现 Contract 合约之间的调用、交互。而 Move 语言使用了模块 (module) 和脚本 (script) 的设计,前者类似于 Contract 合约,Move 语言的合约组合性则是模块之间的组合,通过传递资源(即前文提到的 resources)。关于组合性方面,Solidity 和 Move 的区别非常明显。」
% O) Z! V4 s3 e" p# V3 e8 m
以太坊合约之间的交互是通过互通消息实现的状态一致,且允许重入、动态调用,就是说合约之间的函数可以互相来回调用——调用过程中会发生控制权转移。这一特点为实现闪电贷提供了基础。( ~( y' _6 F- l
; `2 Z( M' Z4 u2 y" ]' Z( o
具体来说,在一个以太坊交易中,可以进行转账操作以及其他一些列合约操作,通过调用智能合约中的功能函数,执行多项复杂功能——也就是说,一笔基于以太坊的交易可以融合一系列复杂交易:将借款、套利、偿还等一系列交易操作融合到一起成为可能。Flash Loan 中所有操作都在一个区块时间中完成,按照现在的以太坊的出块速度,Merge 后也就是 12 秒——核心并非是 12 秒,而是这一系列的交易要能够最终盈利并偿还,如果没有做到这一点,这笔交易就不会被打包写入区块,相当于借款人借款、套利(失败)这些操作并不是有效交易,只是临时状态——即原子交易。因此,用户必须通过编程将需要执行的所有步骤形成一项智能合约交易并完成借贷、使用和偿还的三个步骤。
上述复杂的交易操作由几个合约之间的动态调用实现,且这种调用是可重入的(也就是可以反复调用)。
7 w8 \# o1 W4 \! t ^% B$ O; S3 D' X3 t
目前用户也可以通过如 FURUCOMBO 这一类第三方项目,对闪电贷完成更简易的插件性编程,无需实际编写代码完成智能合约的设计,最终实现闪电贷需要的全套操作。具体的套利流程如下图所示(利用 FURUCOMBO 平台,具体兑价均为示例),目前 Kyberswap 平台上的价格情况 1 sUSD =0.9927 DAI,而 Uniswap 上 1 DAI=1.2411 sUSD,用户发现这两个平台的 DAI-sUSD 交易对价格存在较大的套利空间,即可通过 FURUCOMBO 的界面,设计套利过程。包括:1、从 AAVE 借贷平台的闪电贷功能借出 100 DAI;2、通过 Uniswap 将 100 DAI 兑换成约 122 个 sUSD 代币;3、通过 Kyberswap 平台将 sUSD 代币兑换成约 122 DAI 代币;4、偿还从 AAVE 借出的 100 DAI 代币以及手续费 0.09 DAI;5、整个利用闪电贷的套利流程在一个以太坊交易内完成,并获利约 22 DAI。
如果在这一笔以太坊交易内借贷的资金没有得到偿还,那么整笔借贷交易不会被打包进入区块中,相当于借贷并没有实际发生,所以借贷方的资金不会受任何影响——中间的借贷和套利过程只是临时状态,并未被矿工打包确认。基于闪电贷的特性和时效要求,目前其最广泛的应用是套利交易。
- L. W, w* _0 X9 j