用 Python 開發(fā) DeFi 去中心化借貸應(yīng)用
Python中文社區(qū)(ID:python-china)
介紹
傳統(tǒng)的金融科技世界充滿了使用戶能夠制作復(fù)雜算法交易模型和系統(tǒng)的工具。而去中心化金融 (DeFi) 也同樣為用戶和開發(fā)人員提供了相同的工具,圍繞底層金融協(xié)議和工具具有更高的透明度和靈活性,從而催生了 DeFi 量化交易和應(yīng)用開發(fā)。DeFi 開發(fā)人員和 DeFi quants 甚至可以利用這些工具的衍生品,并將它們組合成新的服務(wù),以建立在傳統(tǒng)金融科技世界中沒有的創(chuàng)新金融頭寸。DeFi 開發(fā)人員的基本工具之一是能夠以非托管方式借出和借入加密貨幣資產(chǎn)。使用 DeFi 借貸協(xié)議的一些巨大優(yōu)勢是:
- 無摩擦賣空
- 無需平倉即可獲得流動性
- 從您存入的抵押品中獲得收益
- 在傳統(tǒng)金融世界中不能完成的事情,比如閃電貸。
由于出色的開發(fā)體驗,金融科技世界的很大一部分人都在使用 Python。通過智能合約,您可以使用您熟悉的完全相同的 Python 工具。您無需了解 Solidity 或如何編寫智能合約即可參與定量 DeFi 或建立自己的加密貨幣對沖基金。然而,如果你決定學(xué)習(xí) Solidity,你的 DeFi 實力將成倍增加,因為你將能夠參與去中心化的量化金融并更有效地集中資源。
在本教程中,我們將學(xué)習(xí)如何:
- 將抵押品存入 Aave 借貸池
- 獲取我們的抵押品和另一種資產(chǎn)之間的對話率
- 使用該抵押品借入不同的資產(chǎn)(貸款)
- 償還貸款
學(xué)習(xí)如何做到這一點將使我們能夠利用 DeFi 生態(tài)系統(tǒng)中的交易,而這些交易在傳統(tǒng)金融科技世界中遠(yuǎn)不那么容易接近,有時甚至是不可能的。
Web3.py 和 Brownie 介紹
和大多數(shù)系統(tǒng)一樣,區(qū)塊鏈?zhǔn)澜缒壳坝袃蓚€ Pythonic 接口:web3.py 和 brownie。Web3.py 是與區(qū)塊鏈交互的原始和最精細(xì)的方式(除非自己編寫自己的 web3.py 包?。?。Brownie 是一個建立在 web3.py 之上的框架,抽象了很多區(qū)塊鏈上交易的難點。在本教程中,我們將向您展示如何編寫這些腳本并使用 Brownie 進(jìn)行鏈上交互。Brownie 讓我們的工作變得更輕松,如果您已經(jīng)熟悉 web3.py,您也可以將 web3.py 與 Brownie 一起使用。如果您更喜歡原始的 web3.py,我們也在 web3.py 存儲庫中完成了所有示例。
設(shè)置
首先,讓我們克隆 repo。
- git clone https://github.com/PatrickAlphaC/aave_brownie_py
- cd aave_brownie_py
你會看到一個這樣的目錄。
如果您對路徑文件不太熟悉,也可以隨時閱讀README以獲取一些有用的提示。
1、安裝
首先要安裝 Python,并安裝Nodejs 以更快地運(yùn)行我們的測試和開發(fā),但我們現(xiàn)在可以跳過這一步。
安裝 Python 后,讓我們運(yùn)行:
- pip install -r requirements.txt
這樣將安裝 eth-brownie 和 python-dotenv。eth-brownie 是 brownie 包,附帶 web3.py。
如果遇到問題,您可以使用 pipx 安裝 eth-brownie:
- pip install --user pipx
- pipx ensurepath
- # restart your terminal
- pipx install eth-brownie
如果你可以運(yùn)行 brownie--version 并得到下面類似的結(jié)果,你就會知道你做對了:
- Brownie v1.14.6- Python development framework forEthereum
2、獲取 ETH 錢包和設(shè)置環(huán)境變量
你需要一個以太坊錢包,可以下載使用 MetaMask 。一旦你有了 MetaMask,你將需要 2 個環(huán)境變量, WEB3_INFURA_PROJECT_ID 和 PRIVATE_KEY。
您的 WEB3_INFURA_PROJECT_ID 將是您在 Infura 中的項目 ID。Infura 是一個節(jié)點基礎(chǔ)設(shè)施解決方案,用于連接到以太坊區(qū)塊鏈并與之交互。
- # DO NOT SEND THESE TO GIT/GITHUB
- export WEB3_INFURA_PROJECT_ID=<PROJECT_ID>
- export PRIVATE_KEY=<PRIVATE_KEY>
您可以將它們添加到標(biāo)有 .env 的文件中,然后運(yùn)行 source.env 將環(huán)境變量添加到您的 shell/terminal。請注意,如果您關(guān)閉了 shell/terminal,則下次打開 shell/terminal備份時,您必須在 .env 文件所在的位置運(yùn)行 source .env。
3、獲取一些測試網(wǎng) ETH
對于那些要運(yùn)行本地鏈的人,您可以跳過此步驟。如果您不明白我所說的“本地鏈”是什么意思,請繼續(xù)閱讀并按照以下步驟操作。
使用此水龍頭鏈接前往 Kovan 水龍頭。如果以下步驟不起作用,您可以隨時訪問 Chainlink 文檔 LINK Token Contract 頁面以查找最新的水龍頭。輸入您的新錢包地址,并獲得一些測試網(wǎng) ETH。您應(yīng)該會在 MetaMask 中看到您的余額更新。
我們將在 Kovan 測試網(wǎng)上運(yùn)行。測試網(wǎng)是對與真實區(qū)塊鏈交互的模擬。
4、將您的 ETH 換成 WETH
如果您從 2 ETH 開始,執(zhí)行此步驟后您將擁有大約 0.99ish ETH 和 1 WETH 的余額。讓我們繼續(xù)。
為了與 Aave 協(xié)議交互,我們將把我們的 ETH 換成 ERC20 版本的 ETH,稱為 WETH(也稱為wrapped ETH)。它使我們更容易與 AAVE 協(xié)議交互。ERC20 是以太坊上的通用代幣標(biāo)準(zhǔn)。
- brownie run scripts/get_weth.py --network kovan
對于那些想要在主網(wǎng)(本地)上運(yùn)行的人,只需刪除命令的 --network kovan 部分。
您應(yīng)該會看到您的 MetaMask 余額減少。這是因為我們正在將 ETH 換成 WETH。為了查看我們的新余額,進(jìn)入 MetaMask,然后點擊添加令牌。然后,在自定義令牌下輸入地址 0xd0a1e359811322d97991e03f863a0c30c2cf029c。這是 Kovan 測試網(wǎng)上 Wrapped Ether 代幣的合約地址。
你會注意到現(xiàn)在總共不到 2 個 ETH (1 + 0.99 != 2)。這是因為每次在區(qū)塊鏈上進(jìn)行交易時,都需要支付一點 gas。gas 是一種向礦工和驗證者支付少量交易費用的方式。隨著您了解更多,您會發(fā)現(xiàn)有兩種 gas:
1、 TransactionGas2、 OracleGas
在本教程中,我們只需要關(guān)注 transaction gas。
這就是你在測試網(wǎng)上的第一筆交易!
5、放下抵押品,借用LINK,然后歸還借入的金額,一個腳本搞定
- brownie run scripts/aave_borrow.py --network kovan
或者,運(yùn)行主網(wǎng)分支腳本:
- brownie run scripts/aave_borrow.py --network mainnet-fork
你應(yīng)該得到這樣的輸出:
- Brownie v1.14.6- Python development framework forEthereum
- AaveBrowniePyProjectis the active project.
- Running'scripts/aave_borrow.py::main'...
- Approving ERC20...
- Transaction sent: 0x04b86b3c11d8b45ad410ecb580becb8f1ef57fb1f72d3ac3944365317b99ca2
- Gas price: 2.0 gwei Gas limit: 50695Nonce: 3
- IERC20.approve confirmed - Block: 25241881Gas used: 46087(90.91%)
- IERC20.approve confirmed - Block: 25241881Gas used: 46087(90.91%)
- Approved!
- Depositing...
- Transaction sent: 0xade4ab7c979e96dcb8ca6ebfda4206f8927d12fc078b32c59a723c3ae4883bca
- Gas price: 2.0 gwei Gas limit: 253974Nonce: 4
- ILendingPool.deposit confirmed - Block: 25241883Gas used: 212742(83.77%)
- Deposited!
- You have 0.100000012276459112 worth of ETH deposited.
- You have 0 worth of ETH borrowed.
- You can borrow 0.08000000982116729 worth of ETH.
- LETS BORROW IT ALL
- The DAI/ETH price is0.0003642722357682
- We are going to borrow 208.6351960638322 DAI
- Transaction sent: 0x07b07852de7ac7cf492b34e0c929c65f38f1f83bf5953c14011ba9f659475247
- Gas price: 2.0 gwei Gas limit: 392549Nonce: 5
- ILendingPool.borrow confirmed - Block: 25241886Gas used: 351754(89.61%)
- ILendingPool.borrow confirmed - Block: 25241886Gas used: 351754(89.61%)
- Congratulations! We have just borrowed 208.6351960638322
- You have 0.100000036829377336 worth of ETH deposited.
- You have 0.076000009330108915 worth of ETH borrowed.
- You can borrow 0.004000020133392954 worth of ETH.
- Approving ERC20...
- Transaction sent: 0xede77fa7f91db8cda493a9aad092b4771c3dcf16718b086da64fe1b3b20dda9f
- Gas price: 2.0 gwei Gas limit: 50798Nonce: 6
- IERC20.approve confirmed - Block: 25241888Gas used: 46180(90.91%)
- IERC20.approve confirmed - Block: 25241888Gas used: 46180(90.91%)
- Approved!
- Transaction sent: 0xfda598cede32c2af0b8309b330bb93d08a8ccb2787adedef0de485220ee7d88a
- Gas price: 2.0 gwei Gas limit: 242655Nonce: 7
- ILendingPool.repay confirmed - Block: 25241889Gas used: 187617(77.32%)
- ILendingPool.repay confirmed - Block: 25241889Gas used: 187617(77.32%)
- Repaid!
這個腳本生成了很多結(jié)果!讓我們分解一下剛剛發(fā)生的事情……
獲取WETH
所以我們在這里做的第一件事就是用一些 ETH 交換 WETH。我們使用 ./scripts/get_weth.py 腳本中的 get_weth 函數(shù)完成了此操作。
- def get_weth(account=None):
- """
- Mints WETH by depositing ETH.
- """
- account = (
- account if account else accounts.add(config["wallets"]["from_key"])
- ) # add your keystore ID as an argument to this call
- weth = interface.WethInterface(
- config["networks"][network.show_active()]["weth_token"]
- )
- tx = weth.deposit({"from": account, "value": 1000000000000000000})
- print("Received 1 WETH")
- return tx
為了在以太坊上進(jìn)行交易或調(diào)用,如果您想修改區(qū)塊鏈的狀態(tài),您必須始終 from一個帳戶。我們正在修改區(qū)塊鏈的狀態(tài),因為我們將修改我們的 ETH 和 WETH 余額。
我們使用從配置中獲得的 account,位于 brownie-config.yaml。我們在底部附近看到它使用我們的 PRIVATE_KEY 環(huán)境變量。
- wallets:
- from_key: ${PRIVATE_KEY}
- from_mnemonic: ${MNEMONIC}
現(xiàn)在不用擔(dān)心 MNEMONIC。
我們將該帳戶添加到我們的Brownie accounts列表中:
- accounts.add(config["wallets"]["from_key"])
現(xiàn)在,我們有了一個可以在腳本中使用的帳戶。
接下來,我們需要獲取 WETH 合約對象,以便與它進(jìn)行交互。我們想將 ETH 存入合約,所以它會為我們鑄造相同數(shù)量的 WETH。我們可以隨時使用此合約將 WETH 轉(zhuǎn)換回 ETH。所有 ERC20 代幣(如 LINK、WETH、AAVE 等)本身都是鏈上合約。要與合約交互,我們需要兩個東西。
- 合約ABI/接口
- 合約地址
我們的 interfaces文件夾中有接口。我們也有 ABI。編譯后的項目將合約放入 build 文件夾中。如果我們查看 build 下的 interfaces 文件夾,我們可以看到一個名為 WethInterface.json 的文件。在該文件夾中,有一個名為 abi 的密鑰。我們可以使用該接口,因為它可以編譯為 ABI。
ABI 代表 APP 二進(jìn)制接口,是程序了解如何與合約交互的標(biāo)準(zhǔn)方式,包括 Python。
我們可以通過創(chuàng)建一個像這樣的 weth 變量來將地址和 ABI 添加到一個對象中以供我們交互:
- weth = interface.WethInterface(
- config["networks"][network.show_active()]["weth_token"]
- )
我們再一次從配置文件中獲取了 weth_token 地址。你會注意到不同的代幣有不同的地址,這取決于你正在處理的鏈。如果我們要 print(type(weth)),我們會得到:
- <class'brownie.network.contract.Contract'>
Contract 對象就像一個類,它代表鏈上的合約。然后我們可以在鏈上調(diào)用該合約的函數(shù)。
然后,我們調(diào)用合約上的存款函數(shù):
- tx = weth.deposit({"from": account, "value": 1000000000000000000})
Solidity 合約 weth具有 deposit存款功能。事實上,我們可以看到鏈上的代碼。此鏈接指向區(qū)塊瀏覽器 Etherscan。這是一種區(qū)塊鏈可視化的方法。
我們可以看到下面的代碼部分,其中包含合約中的所有代碼。您有時會遇到?jīng)]有代碼部分的合約。這是因為他們尚未通過區(qū)塊瀏覽器進(jìn)行驗證。如果我們轉(zhuǎn)到 WriteContract 部分,我們可以看到相同的 deposit存款功能。
所以我們也可以通過這種方式收到 WETH!
每當(dāng)我們進(jìn)行函數(shù)調(diào)用并修改區(qū)塊鏈的狀態(tài)時,我們就會進(jìn)行交易。在上面的輸出中,我們看到了類似的東西:
- Transaction sent: 0x888bb9d6657b1de2e5eec465bf9641b401647a61a2bd428b51d8a95d5a3e329a
然后,您可以將此交易哈希復(fù)制到區(qū)塊瀏覽器中以查看該交易的詳細(xì)信息。
讓我們回顧一下。
- 我們用 Python 獲得了帳戶
- 我們學(xué)習(xí)了如何通過合約的地址和 ABI 與合約進(jìn)行交互
- 我們學(xué)習(xí)了如何通過函數(shù)調(diào)用發(fā)送交易
- 我們了解了區(qū)塊瀏覽器
下一部分我們將主要介紹借貸的內(nèi)容。