在实践中理解闪电贷的实现过程,以及如何自己实现执行一笔闪电贷。

原文标题:《如何使用 Aave 进行闪电贷
撰文:QuickNode
翻译:登链社区

Aave,以前称为 ETHLender,现在是 DeFi 领域的前沿应用。Aave 是该领域中第一个提出 闪电贷 概念的人。在闪电贷之前,你必须用一个超额抵押的资产来借贷另一个资产。例如,如果我想借一个 DAI),我将不得不存入另一个超过该价值的加密货币。换句话说,你必须有钱才能借到钱。闪电贷打破了这种想法。他们为一个新的贷款系统打开了大门,并且做到了这一点,允许用户在不提供任何东西作为抵押的情况下借款。

在本教程中,你将了解到闪电贷是如何实现的,以及如何自己实现执行一笔闪电贷。

关于 Aave

摘自 Aave 官网:Aave 是一个去中心化的非托管流动性市场协议,用户可以作为存款人或借款人参与。储户向市场提供流动性,以赚取被动收入,而借款人能够以过度抵押(永久)或不足抵押(单块流动性)的方式借款。

这个定义完全正确的,但如果你不熟悉 DeFi 行业的行话,你可能并不理解它的含义。你可以把 Aave 看成是一个去中心化的伪银行。Aave 没有一个验证所有交易的中央银行,而是利用智能合约,以自动化的方式完成所有这些工作。存款人将他们的代币放入 Aave,并开始为他们的存款赚取利息。另一方面,借款人会做相反的事情。他们从 Aave 中取出钱,并开始对所借的金额计息。不过他们必须超额抵押才能借到钱。

对于那些不想把钱存入 Aave,而只想借钱的人来说,还有一种方法。这就是我们前面提到的闪电贷。

关于闪电贷(Flash Loan)

之前提到的闪电贷是一种在区块链上借入资产的新方式。最初由 Aave 实现,其他趋势性的 DeFi 协议,如 dYdX 迅速跟进,增加了这个新功能。所有以太坊交易的一个特性,使闪电贷成为可能。而这个关键特性就是 原子性

一个交易的操作系列是不可分割和不可消减的,它就是原子的。简单来说就是:要么所有执行,要么什么都没有发生。没有中间状态 ! 闪电贷利用原子性,允许用户在不提交抵押品的情况下先进行借款。首先,每当你在闪电贷中借入一项资产时,你必须支付贷款金额的 0.09% 的费用。其次,你必须在借贷的同一交易中偿还贷款。虽然这种能力很好,但它的用途却有些局限。闪电贷主要用于资产间 套利

Remix 设置

为了简单起见,我们将使用 Remix IDE。Remix 是一个基于浏览器的 IDE。也被称为集成开发环境。Remix 具有编写、调试、部署和操作以太坊智能合约的能力。浏览器中加载 Remix 后,你会看到这个菜单:

技术详解如何使用 Aave 进行闪电贷

这里不会对 IDE 进行深入的研究(你可以阅读 跟我学 Solidity :开发环境),因为本教程的重点是闪电贷。不过,你需要了解一下上图的四个部分:主面板、侧边面板、图标面板和终端面板。

在我们开始编写智能合约之前,我们要下载一个浏览器插件,现在最流行的是 MetaMask,使我们能够与以太坊区块链对接。

如何安装 MetaMask:

  1. 你将开始从 网站 上下载扩展程序。
  2. 点击你新安装的扩展程序,并同意条款和条件。
  3. 创建一个安全的密码!
  4. 备份助记词,它应该物理存在,不应该保存在你的电脑上的任何地方。

如果上述四个步骤都完成了,你就可以开始编写你的第一个智能合约了 !

智能合约

智能合约允许我们通过执行确定性的程序来读写区块链的数据。我们使用一种名为 Solidity 的编程语言编写以太坊智能合约。Solidity 文件以 .sol 扩展名结尾。

欢迎订阅 全面掌握 Solidity 智能合约开发

你可以在第一次启动 Remix 时删除工作区中可能存在的任何文件。然后创建几个文件:

  1. FlashLoan.sol
  2. FlashLoanReceiverBase.sol
  3. ILendingPoolAddressesProvider.sol
  4. IFlashLoanReceiver.sol
  5. ILendingPool.sol
  6. Withdrawable.sol

下面的代码片断是 FlashLoan.sol 的实现。

这个闪电贷将借入 1 DAI)。

pragma solidity ^0.6.6;
import "./FlashLoanReceiverBase.sol";
import "./ILendingPoolAddressesProvider.sol";
import "./ILendingPool.sol";

contract FlashloanV1 is FlashLoanReceiverBaseV1 {

    constructor(address\_addressProvider) FlashLoanReceiverBaseV1(\_addressProvider) public{}

 /**
   Flash loan 1000000000000000000 wei (1 ether) worth of `\_asset`
 */
 function flashloan(address\_asset) public onlyOwner {
        bytes memory data = "";
        uint amount = 1 ether;
        ILendingPoolV1 lendingPool = ILendingPoolV1(addressesProvider.getLendingPool());
        lendingPool.flashLoan(address(this),\_asset, amount, data);
    }


    /**
  This function is called after your contract has received the flash loaned amount
     */
    function executeOperation(
        address\_reserve,
        uint256\_amount,
        uint256\_fee,
        bytes calldata\_params
    )
        external
        override
    {
        require(\_amount <= getBalanceInternal(address(this),\_reserve), "Invalid balance, was the flashLoan successful?");
       //
        // Your logic goes here.
        // !! Ensure that *this contract* has enough of `\_reserve` funds to payback the `\_fee` !!
        //

        uint totalDebt =\_amount.add(\_fee);
        transferFundsBackToPoolInternal(\_reserve, totalDebt);
    }

}

总而言之,我们首先要导入执行闪电贷所需的依赖。其中一些依赖关系被称为抽象合约)。一个抽象合约至少有个函数没有实现。你可以把它想象成一个房子的图纸。一个建筑商使用这个图纸来建造房子。然而,在我们的比喻中,图纸是一个抽象合约,你是建造者,而房子是派生合约。

在我们的案例中,闪电贷合约使用的是一个名为 FlashLoanReceiverBaseV1 的抽象合约,它提供了必要的实现细节,如闪电贷的偿还。

现在来逐行解读代码:

#1 首先,我们必须定义 solidity 编译器的版本。在这个例子中,它是 0.6.6。

#2-4 为智能合约导入依赖项 #6 FlashLoanV1 合约是继承自 FlashLoanReceiverBaseV1 合约。

#8 传递了 Aave 的一个借贷池提供者的地址。在这个例子中,我们提供的是 DAI 借贷池的地址。

#13 定义了一个叫做 flashLoan 的函数。参数是想要闪电贷的资产地址。在这种情况下,该资产是 DAI。

#14 由于这里不需要任何闪电贷的数据,所以我们传递一个空字符串。

#15. 定义我们想要借出的 DAI 的数量(以 10^18 的 Wei 为单位)。

#16. 通过 Aave 提供的 ILendingPoolV1 初始化 LendingPool 接口,这样我们就可以调用 flashLoan 函数。#17. 最后,调用 flashLoan 函数。该函数需要 4 个主要参数。首先,传递将接收贷款的地址。在我们的例子中,它是当前合约。其次,我们传递资产的地址。在我们的例子中,它是 Kovan 网络中 DAI 的地址。第三,传递资产的数量,在我们的案例中,它是 1 个 ether 单位(或 10^18 的 wei 单位)的数量。第四,传递额外的空数据。

#24-31. 接下来第二个函数 executeOperation。这就是我们利用闪电贷的地方。它在 flashLoan 函数成功执行后被内部调用。它需要 4 个主要参数,分别是:

1). 必须偿还贷款的储备资产地址。2). 资产的数额 3). 协议书所收取的费用 4). 额外的参数,由函数内部使用。

#33. 检查我们是否收到了适当的贷款金额,否则它将抛出一个错误信息。

#34. 在这里,可以根据你自己的使用场景,定制自己的实现逻辑(例如去 DEX 中套利)。

#40. 我们通过使用 SafeMaths 库提供的 add 函数,将费用和贷款金额加在一起。

#41. 最后,把总的债务或贷款金额还给贷款人。

部署合约

  1. 首先,打开你的 MetaMask,将你的网络设置为 Kovan 测试网络

技术详解如何使用 Aave 进行闪电贷 Kovan 测试网络

  1. 使用这个 gist 代码来定义 flashloan 智能合约的依赖关系。点击每个链接并将代码粘贴到你之前创建的相应的 Solidity 文件中:
  • ILendingPool
  • IFlashLoanReceiver
  • ILendingPoolAddressesProvider
  • FlashLoanReceiverBase
  • Withdrawable

技术详解如何使用 Aave 进行闪电贷 Solidity 文件

  1. 切换到 Solidity Compiler 标签。将编译器设置为 0.6.6 并点击 compile FlashLoan.sol

技术详解如何使用 Aave 进行闪电贷

  1. 你应该看到一些警告,但没有错误信息。

  2. 现在,我们已经准备好将合约部署到 Kovan 网络。切换到 Deploy & Run Transctions 标签。把部署环境(ENVIRONMENT),从 JavaScript VM 改为 Injected Web3。这应该会打开 MetaMask 询问你的权限。

技术详解如何使用 Aave 进行闪电贷 部署环境

  1. 确保合约选择的是 FlashLoan.sol。在部署按钮旁边的文本字段中提供 LendingPool 的地址。在我们的例子中,它将是 0x506B0B2CF20FAA8f38a4E2B524EE43e1f4458Cc5。然后点击 Deploy(部署),它应该会打开 MetaMask。

注意。所有已部署的合约地址列表可在 这里 找到。在那里,你可以找到 Aave 支持的各种借贷池的地址。虽然每个代币的地址都不同,但程序是相同的。

技术详解如何使用 Aave 进行闪电贷

  1. 点击 确认 (Confirm)。这样做后,你应该看到 MetaMask 发出的成功通知。之后侧边栏应该有一个 「已部署的合约(Deployed Contracts)」。

为闪电贷准备资金

技术详解如何使用 Aave 进行闪电贷

在新的 已部署合约 标签下,可以复制已部署合约的地址。我们稍后会回到这一步;与此同时,我们需要给闪电贷合约添加一些 DAI。这是因为闪电贷需要合约中的资金才能成功执行。为此,你可以跳转到 水龙头链接,获得一些 DAI 代币(请确保连接到右上角有小 KAave v2 市场)。点击 Faucet,粘贴你的 MetaMask 钱包地址,然后等待确认。

技术详解如何使用 Aave 进行闪电贷

获得确认后,我们将把 DAI 代币添加到 MetaMask 中。为此,打开你的 MetaMask。点击底部的 Add Token。在 代币合约地址(Token Contract Address) 栏输入 0xF795577d9AC8bD7D90Ee22b6C1703490b6512FD。这是 Kovan 的 DAI 的合约地址。点击 下一步 后,它应该显示你先前从水龙头(Faucet)得到的 DAI。

技术详解如何使用 Aave 进行闪电贷

接下来,点击 DAI 代币。点击 发送,它应该打开一个类似于下图的窗口:

技术详解如何使用 Aave 进行闪电贷

输入我们的闪电贷的合约地址,之前已经复制了该地址。输入我们要发送的金额。在我们的案例中,发送 10DAI。然后点击 下一步。点击 确认! 你现在已经成功地给你的闪电贷合约发送了 10DAI。

执行闪电贷

回到 Remix,在部署的闪电贷合约下,还有一个 flashloan 函数。这个函数需要一个我们想使用的资产的合约地址。在我们的例子中,它是 Kovan 测试网的 DAI 合约,是 0xF795577d9AC8bD7D90Ee22b6C1703490b6512FD。正确填写该字段后,你现在可以点击 交易(transact) 按钮,如下图所示:

技术详解如何使用 Aave 进行闪电贷

点击按钮后,MetaMask 会弹出交易确认。确认交易后,你应该收到一条成功信息。在 Remix 的终端,你应该看到一个 URL。点击后会跳转到 Etherscan。

技术详解如何使用 Aave 进行闪电贷

代币转移(Tokens Transferred) 下,你应该看到三个不同的转账:

技术详解如何使用 Aave 进行闪电贷

红色的箭头强调了从 LendingPool 转移 1 个 DAI 到我们的合约。橙色的箭头表示将 1 个 DAI 连同费用一起返还给 Landing pool。蓝色的箭头表示产生利息的 DAI。

小结

我们成功地编写了闪电贷的智能合约, 它能够从资金池中借入 DAI,支付闪电贷费用,然后在一次交易中偿还所借金额。不需要没有任何抵押物就借到了钱 !

来源链接:learnblockchain.cn