在上一篇中,我們介紹了 ERC721 的核心 -- Metadata,以及這些資料是以 Json 檔的形式儲存的。今天會提到 NFT 的 Metadata 將會儲存在哪邊,又是如何被 NFT fetch 的呢?
Metadata 其實有很多種儲存方式,我們可以像 web2 一樣,將這些資料儲存在一個私人架設(中心化)的伺服器,並透過 https 來取得 NFT 的 metadata。
但是中心化的伺服器,最明顯的缺點便是:信任問題。
若你的 NFT 的資料儲存在一個私人的儲存空間,這時可能會產生一些疑慮。由於伺服器需要他人的維護與整理,伺服器可能會受到了駭客攻擊或是伺服器擁有者惡意的刪除這些檔案,都可能導致 metadata 的永久遺失,導致你的 NFT 失去價值。
既然我們知道為何中心化伺服器不太適合存放 metadata,那為什麼 metadata 不要直接放在鏈上呢?如此一來不就達到真正的去中心化了嗎?
其主要原因如下:
因此 IPFS 的登場解決了以上提到的幾個原因。
IPFS 全名是:InterPlantery File System,中文名稱叫做星際文件系統,最初由 Juan Benet 設計,並由協定實驗室在開源社群下開始發展。這個系統背後是由類似於區塊鏈的「共同帳本(副本)」所組成。是一個可以實現「檔案的分散式儲存」的傳輸協定。
在我撰寫的初探 Ethereum 一文中提到了,Ethereum 或是 Bitcoin 的基本架構就像是一個上面寫滿了交易的「帳本」,而這個帳本是分散在不同的節點(電腦)中進行儲存的。
而 IPFS 進行分散式儲存檔案的方式類似於 Bitcoin 和 Ethereum,是透過將檔案傳輸不同的副本到不同的裝置中儲存,也就是說在很多個節點中會有相同的檔案副本儲存。
而在 IPFS 中檔案會以 Merkle DAG (Directed Acyclic Graph) aka 「有向無環圖」的形式儲存。下方就是一個 IPFS 儲存的例子。
礙於這邊只是為了要應用 IPFS 在 NFT 的 metadata 上,就不多闡述 IPFS 的檔案的儲存方式還有驗證方式,未來我可能會在個人 medium 上撰寫相關文章(偷偷宣傳),或是可以透過 Consensys 撰寫的文章了解。
IPFS 的使用方式可以分成兩種,一種是透過圖型使用者介面(GUI)來控制,另一種則是透過 ipfs-cli 的方式。而這邊我使用的是透過 GUI 的方式來上傳檔案到 IPFS 系統上。
在 IPFS 官網 有不同系統的 GUI 載點,安裝後會出現 IPFS 的畫面。
接下來可以按下 FILES (檔案),按下 +import (+匯入) 便可以將檔案儲存到 IPFS 在這台電腦所 run 的節點中。這邊我存入了我自己用小畫家製作的一張圖片,並自己製作了一個 metadata 的 JSON 檔。
首先先傳入這張 png 檔案到 IPFS 上,並複製他的連結,然後放入下方metadata 的 "image" 中。
{
"name": "My First Token",
"description": "A masterPiece.",
"image": "https://ipfs.io/ipfs/QmTJZ3MrgfL9ATfeXFAHAnmwG74u6ojTU8BQojGPSE8fLi?filename=14.png",
"external_url": "https://imgur.com/eDPyoHq",
"attributes": [
{
"trait-type": "Square",
"value": "yellow"
},
{
"trait-type": "Ball_1",
"value": "green"
},
{
"trait-type": "Ball_2",
"value": "yellow and orange"
}
{
"trait-type": "cursor",
"value": "black"
}
]
}
再將這份 json 檔傳到 metadata 後,便可以拿到一個屬於它自己的連結,這時就可以再讓我們來改動 NFT 的 URI 吧。
首先,我們昨天 deploy 的第一份 NFT contract 可以再改動一些東西,讓他可以設置 URI。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract MyToken is ERC721, ERC721URIStorage, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
constructor() ERC721("MyToken", "MTK") {}
function safeMint(address to, string memory uri) public onlyOwner {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
// 透過 setTokenURI 可以改變特定 tokenId 之 metadata 指向的地方
}
// The following functions are overrides required by Solidity.
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
}
首先是 import ERCURIStorage.sol
,並且可以透過 tokenURI(uint256 tokenId)
來查詢該 token 的 URI 為何。這時我們可以 deploy 這份合約並執行 safeMint(your_address,ipfs_JSON_URI)
(此時可以使用 polygon 的測試鏈 mumbai 來 deploy,步驟與昨日類似,可參考 polygon 網站教學
此時便可以 check tokenURI(0)
,便可以看到這一枚 NFT 已經被我們 mint 並把它的 URI 設置為 IPFS 上的地址了!
由於 Opensea 上沒有支持 Goreli 的測試鏈,因此這邊使用 polygon 來測試。當我們成功 mint 到之後,就可以到 Opensea testnet 來查詢我們的 NFT。
在 Opensea 登入 metamask,並按下自己的 profile,點入 created,應該就可以看到自己剛剛發布的 FirstToken 了。
有時候圖片可能會跑不出來,這是因為要取得在 IPFS 上地址上的檔案需要花取一點時間,因此需要按右上角 Refresh Metadata 的按鈕並在重新整理頁面幾次才會出現。
今天簡短的介紹了 IPFS 以及如何使用它的圖形使用者介面來上傳檔案到這個系統中,而 Opensea 的網站會自動地抓取在鏈上的資料(包含其中的 metadata)並將你的 NFT 的圖片(如果是圖片)顯示在頁面中,在 mint 之後可以在 Opensea 上看到真的是很有趣的一件事,有一種你「真的做出了甚麼的感覺」!
若有文章內有任何錯誤的地方歡迎指點與討論!非常感謝!
歡迎贊助窮困潦倒大學生
0xd8538ea74825080c0c80B9B175f57e91Ff885Cb4