Flow區塊鏈是著名的加密貓團隊特別針對NFT應用開發的新的公鏈,其目的是解決以太坊在NFT開發應用上存在的諸多問題,目前已經得到NBA、UFC等多個大牌廠商的支持,在這個教程中我們將學習如何創建Cadence智能合約并在Flow區塊鏈上發行NFT,
區塊鏈開發教程鏈接: 以太坊 | 位元幣 | EOS | Tendermint | Hyperledger Fabric | Omni/USDT | Ripple | Tron
1、Flow開發環境安裝
首先我們需要安裝Flow CLI,詳細的安裝說明可以查看Flow官方檔案, 在這里我們僅列出幾種作業系統下的安裝命令:
- macOS
brew install flow-cli
- Linux
sh -ci “$(curl -fsSL https://storage.googleapis.com/flow-cli/install.sh)"
- Windows
iex “& { $(irm ‘https://storage.googleapis.com/flow-cli/install.ps1') }”
我們需要將檔案保存到IPFS,為此我們使用Pinata,你可以注冊一個免費賬號,然后點擊這里獲取API訪問密鑰,在下一教程中我們將使用Pinata API,
我們還需要安裝NodeJS和一個支持Flow智能合約代碼語法高亮的文本編輯器,Flow的智能合約使用Cadence語言撰寫,Visual Studio Code提供Cadence高亮擴展,
下面讓我們創建專案目錄:
mkdir pinata-party
進入該目錄,然后執行如下命令初始化一個新的Flow專案:
cd pinata-party
flow project init
現在使用你喜歡的代碼編輯器(比如加載了Cadence擴展的Visual Studio Code)打開專案檔案,
可以看到flow.json,我們接下來就會用到,首先創建一個cadence檔案夾,并在該檔案夾內創建contracts檔案夾,最后在contracts檔案夾內創建合約檔案PinataPartyContract.cdc,
在我們繼續之前,需要指出的是,下面我們的操作將在Flow區塊鏈仿真器上完成,要將專案部署到測驗鏈或主鏈,只需要更新flow.json中的配置引數即可,現在讓我們在flow.json中設定仿真環境以便接下來進行智能合約代碼的撰寫:
"contracts": {
"PinataPartyContract": "./cadence/contracts/PinataPartyContract.cdc"
}
接下來更新flow.json中的deployments物件:
"deployments": {
"emulator": {
"emulator-account": ["PinataPartyContract"]
}
}
上面的設定用來告訴Flow CLI使用仿真器來部署合約,在配置中同時也宣告了賬號以及我們接下來要開發的合約,
2、撰寫Cadence智能合約
Flow提供了一個創建NFT智能合約的出色的教程,這是一個很好的參考,但是Flow自己同時指出,他們還沒有解決NFT元資料的問題,Flow團隊希望在鏈上存盤元資料,這是一個好主意,他們肯定會給出一個合理的解決方案,然而我們現在就希望鑄造一些帶元資料的通證,我們也希望這些元資料關聯到NFT,元資料只是一個部分,我們也希望指向通證最終代表的媒體,
如果你熟悉以太坊區塊鏈上的NFT,你可能知道這些NFT支持的資產存盤在傳統資料庫和云主機上,在大多數情況下這沒太大問題,我們之前討論過可尋址內容的天才思路,以及在傳統云平臺上存盤區塊鏈附加資料的問題,這指向了兩個要點:
- 資產應當可驗證
- 應當易于轉移維護責任
IPFS解決了這些問題,Pinata則提供了一個簡單的接入層方面我們將內容長期鎖定在IPFS上,這就是我們希望的解決方案,對嗎?我們希望確保可以證明NFT的所有權,提供NFT的資料,并確保我們可以控制IPFS上的底層資產,
綜合這些想法,現在我們來撰寫智能合約,該合約將負責鑄造NFT、關聯元資料并確保元資料指向保存在IPFS上的底層資產,
打開PinataPartyContract.cdc檔案,輸入如下代碼:
pub contract PinataPartyContract {
pub resource NFT {
pub let id: UInt64
init(initID: UInt64) {
self.id = initID
}
}
}
第一步是定義我們的合約,并在合約內創建一個資源,資源存盤在用戶賬號中,對其的訪問需要滿足訪問控制條件,NFT必須是唯一標識的,id屬性就是用來標識我們的通證,
接下來我們需要創建一個資源介面以便定義可以為其他人可用的能力,例如合約主之外的其他人,
pub resource interface NFTReceiver {
pub fun deposit(token: @NFT, metadata: {String : String})
pub fun getIDs(): [UInt64]
pub fun idExists(id: UInt64): Bool
pub fun getMetadata(id: UInt64) : {String : String}
}
將上述代碼放在NFT資源代碼下面,這個NFTReceiver介面定義了具備訪問權限的人可以呼叫以下方法:
- deposit
- getIDs
- idExists
- getMetadata
接下來我們需要實作通證集,可以將其視為保存用戶全部的NFT的錢包,
pub resource Collection: NFTReceiver {
pub var ownedNFTs: @{UInt64: NFT}
pub var metadataObjs: {UInt64: { String : String }}
init () {
self.ownedNFTs <- {}
self.metadataObjs = {}
}
pub fun withdraw(withdrawID: UInt64): @NFT {
let token <- self.ownedNFTs.remove(key: withdrawID)!
return <-token
}
pub fun deposit(token: @NFT, metadata: {String : String}) {
self.metadataObjs[token.id] = metadata
self.ownedNFTs[token.id] <-! token
}
pub fun idExists(id: UInt64): Bool {
return self.ownedNFTs[id] != nil
}
pub fun getIDs(): [UInt64] {
return self.ownedNFTs.keys
}
pub fun updateMetadata(id: UInt64, metadata: {String: String}) {
self.metadataObjs[id] = metadata
}
pub fun getMetadata(id: UInt64): {String : String} {
return self.metadataObjs[id]!
}
destroy() {
destroy self.ownedNFTs
}
}
上面代碼中包含了很多內容,不過我們將很快理解其中的含義,
首先,我們有一個名為onwedNFTs的變數,它負責跟蹤一個用戶持有的全部NFT,
接下來,名為metadataObjs的變數用來保存每個NFT的元資料映射,這個變數將通證id映射到關聯的元資料,因此在設定之前我們需要先有通證id,
然后我們初始化變數,在Flow的資源中定義的變數需要進行初始化,
最后我們實作NFT集資源的全部函式,注意這些函式并非都向外部公開,別忘了之前我們在NFTReceiver資源介面中定義了任何人可以訪問的函式,
我還想特別指出deposit函式,因為我們繼承了默認的Flow NFT合約以便包含metadataObjs映射,我們也擴展默認的deposit函式來接收額外的metadata引數,為什么要這么做?我們需要確保只有通證的鑄造人可以添加通證的元資料,為保持其私有化,我們將元資料的初始添加限制在鑄造環節,
快要完成Cadence合約代碼了,在NFT集資源下面,添加如下內容:
pub fun createEmptyCollection(): @Collection {
return <- create Collection()
}
pub resource NFTMinter {
pub var idCount: UInt64
init() {
self.idCount = 1
}
pub fun mintNFT(): @NFT {
var newNFT <- create NFT(initID: self.idCount)
self.idCount = self.idCount + 1 as UInt64
return <-newNFT
}
}
首先,我們定義一個函式負責創建空的NFT集合,這是初次訪問我們合約的用戶獲得存盤位置的實作代碼,
之后,我們再創建一個資源,這很重要,否則將無法鑄造通證,NFTMinter資源包含遞增的idCount以確保我們的NFT的id不會重復,代碼還定義了一個創建NFT的函式,
在NFTMinter資源下面,添加主合約初始化代碼:
init() {
self.account.save(<-self.createEmptyCollection(), to: /storage/NFTCollection)
self.account.link<&{NFTReceiver}>(/public/NFTReceiver, target: /storage/NFTCollection)
self.account.save(<-create NFTMinter(), to: /storage/NFTMinter)
}
這個初始化函式僅在合約部署時呼叫,它主要完成以下作業:
- 創建一個空的NFT集合,以便合約主可以鑄造并持有NFT
- 集合資源發布到參考NFTReceiver介面的公共位置,這表明了NFTReceiver定義的方法可以被外部訪問
- NFTMinter資源保存在合約創建者的賬號存盤中,這意味著只有合約創建者可以鑄造通證
可以在這里查看完整的合約代碼,
3、在Flow區塊鏈部署Cadence合約
現在我們有了合約,在部署之前,最好使用Flow Playground進行測驗,前往Flow Playground并打開側欄的第一個賬號,用我們的合約代碼替換示例合約,然后點擊Deploy,如果一切順利,你應該在日志視窗看到類似下面這樣的內容:
16:48:55 Deployment Deployed Contract To: 0x01
現在我們準備將合約部署到本地運行的仿真器上了,在命令列運行如下命令:
flow project start-emulator
仿真器運行并且flow.json配置正確的話,我們可以執行如下命令部署合約:
flow project deploy
如果一切順利的話,應當可以看到下面這樣的輸出:
Deploying 1 contracts for accounts: emulator-account
PinataPartyContract -> 0xf8d6e0586b0a20c7
現在我們在Flow仿真器上有了一個激活的合約,接下來該鑄造NFT了,
4、使用Cadence腳本鑄造NFT
在下一個教程中,我們將創建一個app和用戶界面來讓整個鑄造程序更加用戶友好,不過在這個教程中,為了說明元資料與NFT在Flow上如何運作,我們將使用Cadence腳本和命令列來鑄造NFT,
讓我們在專案目錄下創建一個新的目錄transactions,然后在該目錄中創建一個檔案MintPinataParty.cdc,
為了撰寫交易,我們需要使用一個檔案來參考提供給NFT的元資料,為此我們將通過Pinata上傳檔案到IPFS,點擊這里上傳你選好的視頻檔案,
上傳檔案后你會得到一個IPFS哈希(通常被稱為內容識別符號或CID),拷貝下來這個哈希,因為我們在鑄造程序中需要用到它,
現在,在你的MintPinataParty.cdc檔案中,添加如下內容:
import PinataPartyContract from 0xf8d6e0586b0a20c7
transaction {
let receiverRef: &{PinataPartyContract.NFTReceiver}
let minterRef: &PinataPartyContract.NFTMinter
prepare(acct: AuthAccount) {
self.receiverRef = acct.getCapability<&{PinataPartyContract.NFTReceiver}>(/public/NFTReceiver)
.borrow()
?? panic("Could not borrow receiver reference")
self.minterRef = acct.borrow<&PinataPartyContract.NFTMinter>(from: /storage/NFTMinter)
?? panic("could not borrow minter reference")
}
execute {
let metadata : {String : String} = {
"name": "The Big Swing",
"swing_velocity": "29",
"swing_angle": "45",
"rating": "5",
"uri": "ipfs://QmRZdc3mAMXpv6Akz9Ekp1y4vDSjazTx2dCQRkxVy1yUj6"
}
let newNFT <- self.minterRef.mintNFT()
self.receiverRef.deposit(token: <-newNFT, metadata: metadata)
log("NFT Minted and deposited to Account 2's Collection")
}
}
這個交易很簡單,讓我們解釋一下,
首先你會注意到開頭的import陳述句,你可能還記得我們部署合約時收到一個賬號,這就是我們需要參考的,因此將0xf8d6e0586b0a20c7替換為部署的賬號地址,
接下來我們定義交易,這里的內容與我們期望執行的交易有關,
在我們的交易中做的第一件事,就是定義兩個參考變數receiverRef和minterRef,在這個案例中我們同時是NFT的接收方和鑄造方,這兩個變數參考我們在合約中創建的資源,如果執行交易的人沒有訪問資源的權限,交易將失敗,
接下來我們定義了一個prepare函式,這個函式輸入賬號資訊并進行一些驗證,我們嘗試借用在NFTMinter和NFTReceiver上定義的能力,如果執行人沒有權限,就會在這里失敗,
最后是我們的execute函式,這個函式中我們為NFT構造元資料,鑄造NFT,關聯元資料,將NFT存入我們的賬號,可以看到我創建了一個metadata變數,在其中添加了關于我們通證的資訊,由于我們希望盡可能復制NBA Top Shot,在元資料中我還定義了一些統計資訊,當然你可以輸入任何有意義的資訊,
你會注意到,在metadata中我也定義了一個uri屬性,這指向保存我們資產檔案的IPFS哈希,在這個示例中就是我們上傳的視頻,你可以將其替換為你得到的哈希,
出于一些考慮我們在哈希之前附加ipfs://前綴,這樣在IPFS桌面客戶端和瀏覽器擴展中就可以訪問,也可以在Brave瀏覽器中直接訪問,Brave提供了IPFS的原生支持,
我們呼叫mintNFT函式,它負責創建通證,接下來需要呼叫deposit函式以便將其放入賬號,
最后是簡單的日志輸出,
現在我們基本上準備好發送交易、鑄造NFT了,但是首先我們需要準備賬號,在命令列進入專案根目錄,創建一個新的私鑰用于簽名,
flow keys generate
上面的命令會生成公鑰和私鑰,記得保護好你的私鑰!
我們需要私鑰來簽名交易,因此將其拷貝到flow.json檔案中,我們還需要指定簽名演算法,最后看起來是這樣:
"accounts": {
"emulator-account": {
"address": "YOUR ACCOUNT ADDRESS",
"privateKey": "YOUR PRIVATE KEY",
"chain": "flow-emulator",
"sigAlgorithm": "ECDSA_P256",
"hashAlgorithm": "SHA3_256"
}
},
如果你要將專案放到github或其他遠端git倉庫,確保別包含你的私鑰,你可以使用.gitignore避免將flow.json公開,即使我們只是使用本地仿真器,也要記得保護你的私鑰,
現在發送交易,只需執行如下命令:
flow transactions send --code ./transactions/MintPinataParty.cdc --signer emulator-account
如果一切順利,看起來應該是這樣:
Getting information for account with address 0xf8d6e0586b0a20c7 ...
Submitting transaction with ID 4a79102747a450f65b6aab06a77161af196c3f7151b2400b3b3d09ade3b69823 ...
Successfully submitted transaction with ID 4a79102747a450f65b6aab06a77161af196c3f7151b2400b3b3d09ade3b69823
5、使用Cadence腳本驗證NFT
現在要做的最后一件事,是驗證通證并提取元資料,為此我們將撰寫一個簡單的腳本并在命令列呼叫,
在專案根目錄創建一個新的scripts檔案夾,并在其中創建檔案CheckTokenMetadata.cdc, 在檔案中添加如下內容:
import PinataPartyContract from 0xf8d6e0586b0a20c7
pub fun main() : {String : String} {
let nftOwner = getAccount(0xf8d6e0586b0a20c7)
// log("NFT Owner")
let capability = nftOwner.getCapability<&{PinataPartyContract.NFTReceiver}>(/public/NFTReceiver)
let receiverRef = capability.borrow()
?? panic("Could not borrow the receiver reference")
return receiverRef.getMetadata(id: 1)
}
上面的腳本可以視為對以太坊智能合約的只讀方法的呼叫,免費并且只是回傳資料,
在我們的腳本中,從部署地址匯入合約,然后定義個main函式,并在此函式內定義三個變數:
- nftOwner: 持有NFt的賬號
- capability: 資源能力
- receiverRef: 接收方
現在呼叫腳本:
flow scripts execute ./scripts/CheckTokenMetadata.cdc
應該可以看到如下類似內容:
{"name": "The Big Swing", "swing_velocity": "29", "swing_angle": "45", "rating": "5", "uri": "ipfs://QmRZdc3mAMXpv6Akz9Ekp1y4vDSjazTx2dCQRkxVy1yUj6"}
恭喜!你已經在Flow區塊鏈成功部署Cadence合約、鑄造NFT并將NFT關聯的元資料保存在IPFS!
原文鏈接:Flow區塊鏈NFT開發教程 — 匯智網
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/293022.html
標籤:區塊鏈
上一篇:ZICC全新一代隱私計算基礎網路,如何解決行業痛點?
下一篇:華為區塊鏈,構建可信政務服務
