实现你的第一笔闪电贷合约

解释了实现第一笔闪电贷最基本的方法和原理

闪电贷(Flash loan)是 DeFi 中一个独特的产品,在传统金融活动中没有与之对应的事物。会编写和使用闪电贷也是一项很重要的技能。

概念

闪电贷是一种无抵押、借贷金额无上限(可以借光池中所有的钱)的贷款。它要求借贷人快借快还,快到还款和借款在同一个交易内(同一个以太坊 transaction)。

闪电贷要求每笔借款在归还时,除了归还本金,还要支付一定利息。该利息(或称手续费)由系统动态计算。

实现

很多人对理解闪电贷有一定的难度。因为这需要了解智能合约执行原理和以太坊状态变化的机制。我们通过自己编写一个闪电贷合约,来理解其背后的运行原理。

以使用 Aave 提供的闪电贷为例,编写一个你自己的合约非常简单,你只需要实现一个叫 executeOperation 的方法。

1. executeOperation

executeOperation 方法参数中 _reserve 是所借代币的合约地址,如果是 ETH 则是一个特殊的地址(在 Aave 中用 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 来表示 ETH),_amount 是借款的金额,_fee 是本次借款要偿还的利息。_params 暂时可忽略。

function executeOperation(

    address _reserve,

    uint256 _amount,

    uint256 _fee,

    bytes calldata _params

    )

    external

{

    require(_amount <= getBalanceInternal(address(this), _reserve), "借款失败");

    //

    // 用借来的 ETH 去赚取更多的 ETH

    //

    // 还款

    uint totalDebt = _amount.add(_fee);

    transferFundsBackToPoolInternal(_reserve, totalDebt);

}

当代码执行到 executeOperation 时,你已经拿到了借来的钱,你主要是写如何利用这些钱赚取更多钱的逻辑。例如你发现同一个交易对 A/ETH 在 DEX1(价格低) 和 DEX2(价格高) 的价格差较大,那么你的赚钱逻辑为:

  1. 已借得 100 ETH;

  2. 在价格低的 DEX1 中买入A;

  3. 在价格高的 DEX2 中卖出A;

  4. 卖得 110 ETH。

2. 开始借款

executeOperation 是借款成功后要执行的逻辑。而开始借款的逻辑需要用户自己触发(通过发送交易调用合约),或者直接写在合约的构造函数里。例如:

function flashloan() public onlyOwner {

    bytes memory data = "";

    uint amount = 100 ether;

    address asset = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); //借 ETH

    ILendingPool lendingPool = ILendingPool(addressesProvider.getLendingPool());

    lendingPool.flashLoan(address(this), asset, amount, data);

}

flashLoan() 是真正的借款函数,例子中是借入 100 ETH。闪电贷由此方法触发(开始),也由此方法结束。要完全理解它,我们需要看看 flashLoan() 的内部逻辑。我们摘取最重要的部分。

3. flashLoan() 内部逻辑

flashLoan() 中首先进行各项数据验证,然后便借款给你,紧接着调用你的 executeOperation 的赚钱逻辑,最后验证你是否归还了本金加利息。主要逻辑如下所示:

        //各种数据验证,池中是否还有足够的钱可以贷出?计算手续费等等

        //将借款转给你

        core.transferToUser(_reserve, userPayable, _amount);

        //执行你的合约的赚钱逻辑(步骤1中所写的函数)

        receiver.executeOperation(_reserve, _amount, amountFee, _params);

        //检查目前池中余额

        uint256 availableLiquidityAfter = _reserve == EthAddressLib.ethAddress()

            ? address(core).balance

            : IERC20(_reserve).balanceOf(address(core));

        //通过池中余额变化来确认你是否已经归还了借款+利息

        require(

            availableLiquidityAfter == availableLiquidityBefore.add(amountFee),

            "The actual balance of the protocol is inconsistent"

        );

如果 require() 验证失败,它将 revert 整个交易,让借款无效,从而保证借出方总是安全的。

结语

以上解释了实现第一笔闪电贷最基本的方法和原理。编译源码,以及部署到线上,大家可以参考 Aave 相关官方文档,这里就不一一介绍了。

编写闪电贷合约总体并不复杂。使用闪电贷风险也比较小。如果赚钱逻辑失败,变成了亏钱逻辑,不能完成还款,那么也不用担心借来的巨款(如 1万 ETH)无力偿还。整个交易将会执行失败,就如同借款从来没有发生过一样。

转自公众号”谈谈区块链“ 链接:https://mp.weixin.qq.com/s/6BpXMj9hRfnLheFFQsykWA

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

  • 发表于 2020-12-24 10:29
  • 阅读 ( 374 )
  • 学分 ( 24 )
  • 分类:DeFi

0 条评论

请先 登录 后评论
谈国鹏
谈国鹏

6 篇文章, 107 学分