用 Python 开发 DeFi 去中心化借贷应用

picture.image

介绍

传统的金融科技世界充满了使用户能够制作复杂算法交易模型和系统的工具。而去中心化金融 (DeFi) 也同样为用户和开发人员提供了相同的工具,围绕底层金融协议和工具具有更高的透明度和灵活性,从而催生了 DeFi 量化交易和应用开发。DeFi 开发人员和 DeFi quants 甚至可以利用这些工具的衍生品,并将它们组合成新的服务,以建立在传统金融科技世界中没有的创新金融头寸。DeFi 开发人员的基本工具之一是能够以非托管方式借出和借入加密货币资产。使用 DeFi 借贷协议的一些巨大优势是:

  • 无摩擦卖空
  • 无需平仓即可获得流动性
  • 从您存入的抵押品中获得收益
  • 在传统金融世界中不能完成的事情,比如闪电贷。

由于出色的开发体验,金融科技世界的很大一部分人都在使用 Python。通过智能合约,您可以使用您熟悉的完全相同的 Python 工具。您无需了解 Solidity 或如何编写智能合约即可参与定量 DeFi 或建立自己的加密货币对冲基金。然而,如果你决定学习 Solidity,你的 DeFi 实力将成倍增加,因为你将能够参与去中心化的量化金融并更有效地集中资源。

在本教程中,我们将学习如何:

  • 将抵押品存入 Aave 借贷池
  • 获取我们的抵押品和另一种资产之间的对话率
  • 使用该抵押品借入不同的资产(贷款)
  • 偿还贷款

学习如何做到这一点将使我们能够利用 DeFi 生态系统中的交易,而这些交易在传统金融科技世界中远不那么容易接近,有时甚至是不可能的。

Web3.py 和 Brownie 介绍

和大多数系统一样,区块链世界目前有两个 Pythonic 接口:web3.py 和 brownie。Web3.py 是与区块链交互的原始和最精细的方式(除非自己编写自己的 web3.py 包!)。Brownie 是一个建立在 web3.py 之上的框架,抽象了很多区块链上交易的难点。在本教程中,我们将向您展示如何编写这些脚本并使用 Brownie 进行链上交互。Brownie 让我们的工作变得更轻松,如果您已经熟悉 web3.py,您也可以将 web3.py 与 Brownie 一起使用。如果您更喜欢原始的 web3.py,我们也在 web3.py 存储库中完成了所有示例。

设置

首先,让我们克隆 repo。


      1. `git clone https://github.com/PatrickAlphaC/aave_brownie_py`
2. `cd aave_brownie_py`


    

你会看到一个这样的目录。

picture.image

如果您对路径文件不太熟悉,也可以随时阅读README以获取一些有用的提示。

1、安装

首先要安装 Python,并安装Nodejs 以更快地运行我们的测试和开发,但我们现在可以跳过这一步。

安装 Python 后,让我们运行:


      1. `pip install -r requirements.txt`


    

这样将安装 eth-browniepython-dotenveth-browniebrownie 包,附带 web3.py

如果遇到问题,您可以使用 pipx 安装 eth-brownie


      1. `pip install --user pipx`
2. `pipx ensurepath`
3. `# restart your terminal`
4. `pipx install eth-brownie`


    

如果你可以运行 brownie--version 并得到下面类似的结果,你就会知道你做对了:


      1. `Brownie
  v1.
 14.6
 - 
 Python
  development framework 
 for
 Ethereum`


    

2、获取 ETH 钱包和设置环境变量

你需要一个以太坊钱包,可以下载使用 MetaMask 。一旦你有了 MetaMask,你将需要 2 个环境变量, WEB3\_INFURA\_PROJECT\_IDPRIVATE\_KEY

您的 WEB3\_INFURA\_PROJECT\_ID 将是您在 Infura 中的项目 ID。Infura 是一个节点基础设施解决方案,用于连接到以太坊区块链并与之交互。


      1. `# DO NOT SEND THESE TO GIT/GITHUB`
2. `export WEB3_INFURA_PROJECT_ID=<PROJECT_ID>`
3. `export PRIVATE_KEY=<PRIVATE_KEY>`


    

您可以将它们添加到标有 .env 的文件中,然后运行 source.env 将环境变量添加到您的 shell/terminal。请注意,如果您关闭了 shell/terminal,则下次打开 shell/terminal备份时,您必须在 .env 文件所在的位置运行 source .env。

3、获取一些测试网 ETH

对于那些要运行本地链的人,您可以跳过此步骤。如果您不明白我所说的“本地链”是什么意思,请继续阅读并按照以下步骤操作。

使用此水龙头链接前往 Kovan 水龙头。如果以下步骤不起作用,您可以随时访问 Chainlink 文档 LINK Token Contract 页面以查找最新的水龙头。输入您的新钱包地址,并获得一些测试网 ETH。您应该会在 MetaMask 中看到您的余额更新。

picture.image

我们将在 Kovan 测试网上运行。测试网是对与真实区块链交互的模拟。

4、将您的 ETH 换成 WETH

如果您从 2 ETH 开始,执行此步骤后您将拥有大约 0.99ish ETH 和 1 WETH 的余额。让我们继续。

为了与 Aave 协议交互,我们将把我们的 ETH 换成 ERC20 版本的 ETH,称为 WETH(也称为wrapped ETH)。它使我们更容易与 AAVE 协议交互。ERC20 是以太坊上的通用代币标准。


      1. `brownie run scripts/get\_weth.py --network kovan`


    

对于那些想要在主网(本地)上运行的人,只需删除命令的 --network kovan 部分。

您应该会看到您的 MetaMask 余额减少。这是因为我们正在将 ETH 换成 WETH。为了查看我们的新余额,进入 MetaMask,然后点击添加令牌。然后,在自定义令牌下输入地址 0xd0a1e359811322d97991e03f863a0c30c2cf029c 。这是 Kovan 测试网上 Wrapped Ether 代币的合约地址。

你会注意到现在总共不到 2 个 ETH (1 + 0.99 != 2)。这是因为每次在区块链上进行交易时,都需要支付一点 gasgas 是一种向矿工和验证者支付少量交易费用的方式。随着您了解更多,您会发现有两种 gas

1、 TransactionGas 2、 OracleGas

在本教程中,我们只需要关注 transaction gas

这就是你在测试网上的第一笔交易!

5、放下抵押品,借用LINK,然后归还借入的金额,一个脚本搞定


      1. `brownie run scripts/aave\_borrow.py --network kovan`


    

或者,运行主网分支脚本:


      1. `brownie run scripts/aave\_borrow.py --network mainnet-fork`


    

你应该得到这样的输出:


      1. `Brownie v1.14.6- Python development framework forEthereum`
2. `AaveBrowniePyProjectis the active project.`
3. `Running'scripts/aave_borrow.py::main'...`
4. `Approving ERC20...`
5. `Transaction sent: 0x04b86b3c11d8b45ad410ecb580becb8f1ef57fb1f72d3ac3944365317b99ca21`
6. `Gas price: 2.0 gwei Gas limit: 50695Nonce: 3`
7. `IERC20.approve confirmed - Block: 25241881Gas used: 46087(90.91%)`
8. `IERC20.approve confirmed - Block: 25241881Gas used: 46087(90.91%)`
9. `Approved!`
10. `Depositing...`
11. `Transaction sent: 0xade4ab7c979e96dcb8ca6ebfda4206f8927d12fc078b32c59a723c3ae4883bca`
12. `Gas price: 2.0 gwei Gas limit: 253974Nonce: 4`
13. `ILendingPool.deposit confirmed - Block: 25241883Gas used: 212742(83.77%)`
14. `Deposited!`
15. `You have 0.100000012276459112 worth of ETH deposited.`
16. `You have 0 worth of ETH borrowed.`
17. `You can borrow 0.08000000982116729 worth of ETH.`
18. `LETS BORROW IT ALL`
19. `The DAI/ETH price is0.0003642722357682`
20. `We are going to borrow 208.6351960638322 DAI`
21. `Transaction sent: 0x07b07852de7ac7cf492b34e0c929c65f38f1f83bf5953c14011ba9f659475247`
22. `Gas price: 2.0 gwei Gas limit: 392549Nonce: 5`
23. `ILendingPool.borrow confirmed - Block: 25241886Gas used: 351754(89.61%)`
24. `ILendingPool.borrow confirmed - Block: 25241886Gas used: 351754(89.61%)`
25. `Congratulations! We have just borrowed 208.6351960638322`
26. `You have 0.100000036829377336 worth of ETH deposited.`
27. `You have 0.076000009330108915 worth of ETH borrowed.`
28. `You can borrow 0.004000020133392954 worth of ETH.`
29. `Approving ERC20...`
30. `Transaction sent: 0xede77fa7f91db8cda493a9aad092b4771c3dcf16718b086da64fe1b3b20dda9f`
31. `Gas price: 2.0 gwei Gas limit: 50798Nonce: 6`
32. `IERC20.approve confirmed - Block: 25241888Gas used: 46180(90.91%)`
33. `IERC20.approve confirmed - Block: 25241888Gas used: 46180(90.91%)`
34. `Approved!`
35. `Transaction sent: 0xfda598cede32c2af0b8309b330bb93d08a8ccb2787adedef0de485220ee7d88a`
36. `Gas price: 2.0 gwei Gas limit: 242655Nonce: 7`
37. `ILendingPool.repay confirmed - Block: 25241889Gas used: 187617(77.32%)`
38. `ILendingPool.repay confirmed - Block: 25241889Gas used: 187617(77.32%)`
39. `Repaid!`


    

这个脚本生成了很多结果!让我们分解一下刚刚发生的事情……

获取WETH

所以我们在这里做的第一件事就是用一些 ETH 交换 WETH。我们使用 ./scripts/get\_weth.py 脚本中的 get\_weth 函数完成了此操作。


      1. `def get_weth(account=None):`
2. `"""`
3. `Mints WETH by depositing ETH.`
4. `"""`
5. `account = (`
6. `account if account else accounts.add(config["wallets"]["from_key"])`
7. `) # add your keystore ID as an argument to this call`
8. `weth = interface.WethInterface(`
9. `config["networks"][network.show_active()]["weth_token"]`
10. `)`
11. `tx = weth.deposit({"from": account, "value": 1000000000000000000})`
12. `print("Received 1 WETH")`
13. `return tx`


    

为了在以太坊上进行交易或调用,如果您想修改区块链的状态,您必须始终 from 一个帐户。我们正在修改区块链的状态,因为我们将修改我们的 ETH 和 WETH 余额。

我们使用从配置中获得的 account ,位于 brownie-config.yaml 。我们在底部附近看到它使用我们的 PRIVATE\_KEY 环境变量。


      1. `wallets:`
2. `from_key: ${PRIVATE_KEY}`
3. `from_mnemonic: ${MNEMONIC}`


    

现在不用担心 MNEMONIC。

我们将该帐户添加到我们的Brownie accounts列表中:


      1. `accounts.add(config[ "wallets" ][ "from\_key" ])`


    

现在,我们有了一个可以在脚本中使用的帐户。

接下来,我们需要获取 WETH 合约对象,以便与它进行交互。我们想将 ETH 存入合约,所以它会为我们铸造相同数量的 WETH。我们可以随时使用此合约将 WETH 转换回 ETH。所有 ERC20 代币(如 LINK、WETH、AAVE 等)本身都是链上合约。要与合约交互,我们需要两个东西。

  • 合约ABI/接口
  • 合约地址

我们的 interfaces 文件夹中有接口。我们也有 ABI。编译后的项目将合约放入 build 文件夹中。如果我们查看 build 下的 interfaces 文件夹,我们可以看到一个名为 WethInterface.json 的文件。在该文件夹中,有一个名为 abi 的密钥。我们可以使用该接口,因为它可以编译为 ABI。

ABI 代表 APP 二进制接口,是程序了解如何与合约交互的标准方式,包括 Python。

我们可以通过创建一个像这样的 weth 变量来将地址和 ABI 添加到一个对象中以供我们交互:


      1. `weth = interface.WethInterface(`
2. `config["networks"][network.show_active()]["weth_token"]`
3. `)`


    

我们再一次从配置文件中获取了 weth_token 地址。你会注意到不同的代币有不同的地址,这取决于你正在处理的链。如果我们要 print(type(weth)) ,我们会得到:


      1. `<class
 'brownie.network.contract.Contract'
 >`


    

Contract 对象就像一个类,它代表链上的合约。然后我们可以在链上调用该合约的函数。

然后,我们调用合约上的存款函数:


      1. `tx = weth.deposit({
 "from"
 : account, 
 "value"
 : 
 1000000000000000000
 })`


    

Solidity 合约 weth 具有 deposit 存款功能。事实上,我们可以看到链上的代码。此链接指向区块浏览器 Etherscan。这是一种区块链可视化的方法。

picture.image

我们可以看到下面的代码部分,其中包含合约中的所有代码。您有时会遇到没有代码部分的合约。这是因为他们尚未通过区块浏览器进行验证。如果我们转到 WriteContract 部分,我们可以看到相同的 deposit 存款功能。

picture.image

所以我们也可以通过这种方式收到 WETH!

每当我们进行函数调用并修改区块链的状态时,我们就会进行交易。在上面的输出中,我们看到了类似的东西:


      1. `Transaction sent: 0x888bb9d6657b1de2e5eec465bf9641b401647a61a2bd428b51d8a95d5a3e329a`


    

然后,您可以将此交易哈希复制到区块浏览器中以查看该交易的详细信息。

让我们回顾一下。

  • 我们用 Python 获得了帐户
  • 我们学习了如何通过合约的地址和 ABI 与合约进行交互
  • 我们学习了如何通过函数调用发送交易
  • 我们了解了区块浏览器

下一部分我们将主要介绍借贷的内容。

picture.image picture.image picture.image

picture.image

picture.image

点击下方阅读原文加入 社区会员

0
0
0
0
评论
未登录
暂无评论