本系列文將分享如何使用 Python 的 Brownie 框架開發 ERC-721,也就是 NFT。並且 deploy contract 到 Ethereum 的測試網路 Rinkeby,圖檔和 Metadata 則上傳到 IPFS,再透過測試版本的 OpenSea 來看看成果!
在上一篇 自己寫 NFT 吧!- 實現 ERC-721 – 以 Python Brownie 開發 我們使用 OpenZeppelin 的 ERC-721 樣板快速實現一個 NFT 的 smart contract。這篇我們要 deploy 到 Ganache 來實測與互動。
目錄
啟動 Local Ganache Network
如果 local 環境沒有啟動任何 Ganache,透過 Browine 跑 script 時會自動起一個「一次性」的 Ganache,跑玩後隨即關閉。如果我們需要做多次互動的測試,就需要 Ganache 一直活著,因此在 console 輸入
$ ganache-cli
Ganache 節點就會一直執行,監聽 8545 port,直到按下 ctrl + C 停止。
用 Python Deploy NFT Smart Contract
我們在專案目錄下的 scripts 資料夾中新增一個 deploy.py 的檔案,並貼入以下 script:
from brownie import network, accounts, KongLongNFT
def main():
owner = accounts[0]
kong_long = KongLongNFT.deploy({"from": owner})
print(f"Contract deployed to {kong_long.address}")
return kong_long
解釋一下上面的 script:
- 首先由 browine 匯入套件中的 network、accounts、以及我們寫的 ERC-721 smart contract KongLongNFT。brownie 會幫我們把 Solidity 寫的 contract 包裝成同名 class,如此可用 python 與 smart contract 互動
- 定義 main 函數。使用 brownie 跑 script 時如果沒有特別指定跑檔案中哪一個函數,預設會跑 main
- 因為 Ganache 會幫我們建立十個測試用的 account,我們直接從 accounts 取用第一個當作執行 deploy 的帳戶
- 接下來呼叫 KongLongNFT 中的方法 deploy 發布 smart contract。deploy 方法帶入 dictionary 傳入執行者的 account,回傳 deploy 後的 contract instance
- 印出 contract 的地址
我們來實測看看,在 console 中輸入
$ brownie run script/deploy.py
會看到 shell 回應 transaction 的 hash,deploy 過程用的 gas,以及最後 contract 的位置
Brownie v1.17.2 - Python development framework for Ethereum
TokenProject is the active project.
Attached to local RPC client listening at '127.0.0.1:8545'...
Running 'scripts/deploy.py::main'...
Transaction sent: 0x28fe8322442356b1ea88fe80925973a53dcae1a651dfa01558607bedc4b4f00c
Gas price: 0.0 gwei Gas limit: 6721975 Nonce: 0
KongLongNFT.constructor confirmed Block: 1 Gas used: 1421519 (21.15%)
KongLongNFT deployed at: 0x684f51E9A4Ec41DDaC067A9E03eECad3274F4FDd
Contract deployed to 0x684f51E9A4Ec41DDaC067A9E03eECad3274F4FDd
用 Python Mint 一個 NFT
deploy 完成,我們開一個新的檔案 mint.py,準備鑄造用的 script
from brownie import network, accounts, KongLongNFT
def main():
owner = accounts[0]
receiver = accounts[1]
nft = KongLongNFT.at('0x684f51E9A4Ec41DDaC067A9E03eECad3274F4FDd')
nft.mintToken(receiver, "ipfs://test-hash", {"from": owner})
current_token_id = nft.getCurrentTokenId({"from": owner})
print(f"mint successfully, token id: {current_token_id}")
解釋一下 mint 的 script
- 這邊一樣以第一個 account 作為發起 mint 的帳戶,第二個 account 作為新鑄造的 NFT 擁有者
- 透過 KongLongNFT.at() 方法,傳入剛剛 deploy 的 contract address,取得 contract instance
- 呼叫 smart contract 中定義的 mintToken 方法。這個方法在 Solidity 中需要傳入兩個參數「address」和「tokenURI」,因此我們依序放入 receiver 和假的 tokenURI 字串。最後一樣要傳入發起 transaction 的帳戶位置
- 透過 smart contract 中定義的 getCurrentTokenId 方法,取得目前最新一張 NFT 的 token id,並列印出來
立刻實測看看,在 console 中輸入
$ brownie run script/mint.py
一樣會印出 transaction 的基本資訊,以及目前的 token id 為 1
Transaction sent: 0xb1cef49556a6ee1628487198b593729da0624ebbfa1b19996da96f6dc46da348
Gas price: 0.0 gwei Gas limit: 6721975 Nonce: 2
KongLongNFT.mintToken confirmed Block: 3 Gas used: 112400 (1.67%)
<Transaction '0xb1cef49556a6ee1628487198b593729da0624ebbfa1b19996da96f6dc46da348'>
mint successfully, token id: 1
到這裡可以了解,「鑄造」其實就是寫入一筆 token_id 對 owner address ,以及 token_id 對 URI 的 mapping。
用 Python 測試呼叫 NFT Smart Contract
接下來我們要透過 Brownie 提供的 console 互動模式,用 Python 與 ERC-721 smart contract 做即時互動,驗證我們剛剛 deploy 和 mint 的資料是正確的。
使用以下指令進入 console:
$ brownie console
Brownie v1.17.2 - Python development framework for Ethereum
TokenProject is the active project.
/Users/jim/.local/pipx/venvs/eth-brownie/lib/python3.9/site-packages/brownie/network/main.py:44: BrownieEnvironmentWarning: Development network has a block height of 2
warnings.warn(
Attached to local RPC client listening at '127.0.0.1:8545'...
Brownie environment is ready.
>>>
首先先來抓 NFT token 的 name 和 symbol:
>>> from brownie import KongLongNFT
>>> nft = KongLongNFT.at('0x684f51E9A4Ec41DDaC067A9E03eECad3274F4FDd')
>>> nft.name()
'KongLongNFT'
>>> nft.symbol()
'KLG'
我們要怎麼知道剛剛 mint 的 NFT 真的屬於 owner 呢?
>>> nft.ownerOf(1)
'0xEC63C0c7ed151b7eeC6E4e8571F0363B32359878'
>>> accounts[1]
<Account '0xEC63C0c7ed151b7eeC6E4e8571F0363B32359878'>
透過 ERC-721 定義的 ownerOf(uint256 tokenId) 方法,傳入愈查詢的 tokenId,回傳擁有者的地址。同時我們檢查 Ganache 預設的第二個地址,的確相同。
這邊的 accounts 跟之前 script 中從 brownie import 的是一樣的,在 console 中 brownie 會自動幫我們匯入,很貼心。
接下來檢查 tokenURI 是否與鑄造時傳入的一致:
>>> nft.tokenURI(1)
'ipfs://test-hash'
透過這幾個方法,就可以知道一個 NFT 的基本資訊、擁有者、以及該張 NFT 對應的 URI 位置,就能夠顯示在 Opensea 了……..嗎?還沒!我們還沒研究 tokenURI 指向的內容!下一篇我們會分享如何準備 meta data 讓 NFT 可以正確顯示在 Opensea 上!
延伸閱讀:
如何以 Python Brownie 開發 DeFi 應用?- 環境準備
自己寫 NFT 吧!- 實現 ERC-721 – 以 Python Brownie 開發
自己寫 NFT 吧!- 準備 Metadata – 以 Python Brownie 開發
自己寫 NFT 吧!- Deploy 到 Rinkeby testnet – 以 Python Brownie 開發