Bitaigen 編輯團隊認為,本文系統梳理了在 Flow 與 IPFS 環境下編寫、部署並鑄造 NFT 的完整步驟。我們從工具安裝到 Cadence 合約實作逐項說明,協助開發者快速上手,後續實戰案例更值得期待,建議詳讀。
用 Flow 與 IPFS 建立 NFT 合約與鑄造代幣操作教學
在 Flow 區塊鏈上配合 IPFS,可透過編寫 Cadence 合約、部署至模擬器或測試網、使用 Pinata 上傳資產取得 CID,隨後在交易中鑄造 NFT 並將元資料綁定到代幣上,完成完整的建立與鑄造流程。
※ 本操作受台灣金融監督管理委員會監管,請自行評估相關法規風險。
環境設定
- 安裝 Flow CLI
- macOS
```bash
brew install flow-cli
```
- Linux
```bash
sh -ci "$(curl -fsSL https://storage.googleapis.com/flow-cli/install.sh)"
```
- Windows
```powershell
iex "& { $(irm 'https://storage.googleapis.com/flow-cli/install.ps1') }"
```
- 準備 IPFS 資產存儲
- 註冊 Pinata 免費帳號,取得 API Key。後續第二篇教學中會使用 Pinata API,本篇僅透過 Pinata 網站手動上傳。
- 安裝 Node.js 與程式碼編輯器
- 推薦使用 Visual Studio Code,並安裝 Cadence 語法外掛,方便高亮顯示智慧合約程式碼。
- 建立專案目錄
```bash
mkdir pinata-party
cd pinata-party
flow project init
```
專案初始化後會產生 `flow.json`,稍後會對其進行設定。
- 組織程式碼結構
```
pinata-party/
├─ cadence/
│ └─ contracts/
│ └─ PinataPartyContract.cdc
├─ transactions/
└─ scripts/
```
所有 Flow 相關程式碼皆放在 `cadence/contracts` 目錄下,後續的交易腳本與查詢腳本分別放在 `transactions` 與 `scripts` 中。
設定 flow.json 為模擬器
在 `flow.json` 中加入合約路徑:
```json
"contracts": {
"PinataPartyContract": "./cadence/contracts/PinataPartyContract.cdc"
},
"deployments": {
"emulator": {
"emulator-account": ["PinataPartyContract"]
}
}
```
以上設定指示 Flow CLI 使用本機模擬器部署 `PinataPartyContract`。
編寫 NFT 合約
合約核心結構
```cadence
pub contract PinataPartyContract {
// NFT 資源定義
pub resource NFT {
pub let id: UInt64
init(initID: UInt64) {
self.id = initID
}
}
// 接收 NFT 的資源介面
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 Collection 實作
pub resource Collection: NFTReceiver {
// 存放 NFT
pub var ownedNFT: @{UInt64: NFT}
// 對應的元資料映射
pub var metadataObjs: {UInt64: {String: String}}
init() {
self.ownedNFT <- {}
self.metadataObjs = {}
}
// 提取 NFT
pub fun withdraw(withdrawID: UInt64): @NFT {
let token <- self.ownedNFT.remove(key: withdrawID)!
return <-token
}
// 存入 NFT 並綁定元資料
pub fun deposit(token: @NFT, metadata: {String: String}) {
self.ownedNFT[token.id] <-! token
self.metadataObjs[token.id] = metadata
}
pub fun idExists(id: UInt64): Bool {
return self.ownedNFT[id] != nil
}
pub fun getIDs(): [UInt64] {
return self.ownedNFT.keys
}
pub fun getMetadata(id: UInt64): {String: String} {
return self.metadataObjs[id]!
}
destroy() {
destroy self.ownedNFT
}
}
// 建立空 Collection 的工廠函式
pub fun createEmptyCollection(): @Collection {
return <-create Collection()
}
// 鑄造者資源
pub resource NFTMinter {
pub var idCount: UInt64
init() {
self.idCount = 1
}
pub fun mintNFT(): @NFT {
let newNFT <- create NFT(initID: self.idCount)
self.idCount = self.idCount + 1
return <-newNFT
}
}
// 合約初始化:部署 Collection、公開介面、保存鑄造者
init() {
// 為部署者建立並保存空 Collection
self.account.save(<-self.createEmptyCollection(), to: /storage/NFTCollection)
// 將 Collection 公開為 NFTReceiver 介面
self.account.link<&Collection{NFTReceiver}>(/public/NFTReceiver, target: /storage/NFTCollection)
// 保存 NFTMinter 資源,僅合約建立者可存取
self.account.save(<-create NFTMinter(), to: /storage/NFTMinter)
}
}
```
關鍵說明
- NFT 資源僅包含唯一標識 `id`。
- NFTReceiver 介面定義了外部可呼叫的四個方法:`deposit`、`getIDs`、`idExists`、`getMetadata`。
- Collection 資源實作了該介面,並額外維護 `metadataObjs` 用於保存每個 NFT 的元資料。
- NFTMinter 負責遞增 `idCount` 並產生新 NFT。
- `init()` 在合約部署時自動建立空 Collection、公開介面以及鑄造者資源。
部署合約
- 在 Flow Playground 或本機模擬器中部署。
- 本機部署指令:
```bash
flow project start-emulator # 啟動本機模擬器
flow project deploy # 部署合約
```
成功後日誌類似:
```
Deploying 1 contracts for accounts: emulator-account.PinataPartyContract -> 0xf8d6e0586b0a20c7
```
鑄造 NFT(交易腳本)
建立交易檔案
在 `transactions` 目錄下新建 `MintPinataParty.cdc`,內容如下:
```cadence
import PinataPartyContract from 0xf8d6e0586b0a20c7
transaction {
// 參照接收器與鑄造者
let receiverRef: &{PinataPartyContract.NFTReceiver}
let minterRef: &PinataPartyContract.NFTMinter
prepare(acct: AuthAccount) {
// 取得公開的 NFTReceiver 能力
self.receiverRef = acct.getCapability<&{PinataPartyContract.NFTReceiver}>(/public/NFTReceiver)
.borrow()
?? panic("Could not borrow receiver reference")
// 取得私有的 NFTMinter 資源
self.minterRef = acct.borrow<&PinataPartyContract.NFTMinter>(from: /storage/NFTMinter)
?? panic("Could not borrow minter reference")
}
execute {
// 元資料範例(請自行替換 IPFS CID)
let metadata: {String: String} = {
"name": "The Big Swing",
"swing_velocity": "29",
"swing_angle": "45",
"rating": "5",
"uri": "ipfs://QmRZdc3mAMXpv6Akz9Ekp1y4vDSjazTx2dCQRkxVy1yUj6"
}
// 鑄造 NFT 並存入 Collection
let newNFT <- self.minterRef.mintNFT()
self.receiverRef.deposit(token: <-newNFT, metadata: metadata)
log("NFT minted and deposited")
}
}
```
說明
- `import` 行的位址需替換為實際部署合約的位址。
- `metadata` 中的 `uri` 欄位使用 `ipfs://` 前綴,指向 Pinata 上傳後取得的 CID。
- `deposit` 同時將 NFT 與元資料寫入 Collection。
產生帳戶金鑰並設定 flow.json
```bash
flow keys generate
```
系統會回傳 `privateKey`、`publicKey`,請將其填入 `flow.json`:
```json
"accounts": {
"emulator-account": {
"address": "0xf8d6e0586b0a20c7",
"privateKey": "YOUR_PRIVATE_KEY",
"chain": "flow-emulator",
"sigAlgorithm": "ECDSA_P256",
"hashAlgorithm": "SHA3_256"
}
}
```
安全提示:切勿將私鑰提交至公共倉庫,建議將 `flow.json` 加入 `.gitignore`。
送出交易
```bash
flow transactions send --code ./transactions/MintPinataParty.cdc --signer emulator-account
```
成功後會回傳交易 ID,表示 NFT 已寫入帳戶的 Collection。
※ 本操作受台灣金融監督管理委員會監管,請自行評估相關法規風險。
查詢 NFT 元資料(只讀腳本)
在 `scripts` 目錄新建 `CheckTokenMetadata.cdc`:
```cadence
import PinataPartyContract from 0xf8d6e0586b0a20c7
pub fun main(): {String: String} {
let nftOwner = getAccount(0xf8d6e0586b0a20c7)
let capability = nftOwner.getCapability<&{PinataPartyContract.NFTReceiver}>(/public/NFTReceiver)
let receiverRef = capability.borrow()
?? panic("Could not borrow the receiver reference")
return receiverRef.getMetadata(id: 1)
}
```
執行腳本:
```bash
flow scripts execute ./scripts/CheckTokenMetadata.cdc
```
預期輸出類似:
```
{"name":"The Big Swing","swing_velocity":"29","swing_angle":"45","rating":"5","uri":"ipfs://QmRZdc3mAMXpv6Akz9Ekp1y4vDSjazTx2dCQRkxVy1yUj6"}
```
※ 本操作受台灣金融監督管理委員會監管,請自行評估相關法規風險。
至此,Flow 與 IPFS 的完整 NFT 建立、鑄造以及元資料查詢流程已全部完成。
---
小結
- 使用 Cadence 編寫符合 Flow 標準的 NFT 合約。
- 透過 Pinata 將媒體檔案上傳至 IPFS,取得 CID。
- 在交易腳本中將 CID 寫入元資料欄位 `uri`,實現鏈上 NFT 與鏈下資產的綁定。
- 本教學涵蓋環境建置、合約開發、部署、鑄造與查詢四個關鍵環節,為進一步建置前端展示或二級市場奠定基礎。

---
*本文翻譯由 Cell Network 贊助。原文連結:https://medium.com/pinata/how-to-create-nfts-like-nba-top-shot-with-flow-and-ipfs-701296944bf*
相關閱讀
💡 註冊幣安使用邀請碼 B2345 享平台手續費折扣。詳見 幣安完整教學。