作者:林冠巨集 / 指尖下的幽靈。轉載者,請: 務必標明出處。
GitHub : https://github.com/af913337456/
出版的書籍:
NFT (Non-Fungible Token),這2年又火了起來,早在18年已經火過一波。
本文只從寫程式碼實現NFT的技術方案
層面去介紹 NFT,不從其金融意義、案例,等層面去談,因為這類內容可以隨便在瀏覽器搜尋到,而我接下來要談的內容,淺層搜尋下,數量不多。
第一步: 製作id
製作id,這是把物質製作成 NFT 的第一步。物質有哪些?一段文字、一張圖片,一件衣服等,誇張的說,現實世界的物質,無論是虛擬的(遊戲裝備)或實質物質,都可以被通證化。
如何操作?
通過第三方技術手段
獲取物質的唯一標誌性中間產物。
因此製作 NFT 第一步,廣義於下面等式:
- id = F(I)
- I = 輸入的物質
- F = 處理函式,代表一種方法
- id 唯一標誌性的中間產物
最簡單的例子就是雜湊函式,不考慮雜湊碰撞,它就可以根據不同的內容輸出不同的雜湊值。思維在這裡不要侷限於雜湊函式。
獲取圖片的唯一id
這裡用圖片代表一系列的檔案類資料。
- 我們可以將圖片轉換成 []byte 位元組陣列,然後計算其雜湊值。這種操作雖然比較簡單,但是圖片別人卻不能訪問,看不到;
- 如果我們想向外部任何人提供圖片的讀許可權,在計算完 id 後,有兩種做法:
- 上傳圖片到檔案伺服器,任何人可以通過 url 連結訪問。這裡的伺服器是中心化的;
- 增加區塊鏈屬性。上傳檔案到 IPFS (ipfs是什麼,自行搜尋),如此一來,檔案別人能訪問,同時還具備了區塊鏈的去中心化等屬性。其中 IPFS 會在上傳完檔案後,會使用它的演算法,幫你計算好雜湊值返回,可以直接用它的作為id。
獲取衣服的唯一id
這裡用衣服來代表一系列的實際物質。如果獲取它們的唯一id呢?做法可以放飛思維去思考,比如可以:
- 衣服的出廠資訊、掃描內容、照片,等系列關於它的資訊,資料化,然後用這些資料製作成檔案,最後參考圖片的做法。
第二步:通證化
第一步中獲取了物質的id,現在要把它們通證化。切記一點:目前公認的 NFT 都是基於區塊鏈公鏈的,那麼以後是不是會一直這樣呢?不一定,說不準出來了新的共識。
基於不同公鏈的流程
通證化的流程如下:
- 選擇一條區塊鏈公鏈。這裡的選擇會決定後面
智慧合約
等系統元件的技術棧,這一點很核心; - 在所選的公鏈上開發智慧合約;
- 所開發的智慧合約需要遵循一些基礎約定,比如至少能保證物質的id能達到驗證去重,什麼意思呢?意思是,如果 A 在今天上傳了 id=1 到鏈上,明天 B 也上傳同個 id=1 到鏈上,合約要能告訴 B,你不能上傳了,id 已經存在;
- 部署智慧合約到鏈上,此時它變成 DApp;
- 通過發交易的方式,呼叫該智慧合約的方法,將id等相關資料儲存到鏈上。
NFT 的智慧合約
NFT 智慧合約可以基於不同的公鏈開發,它不侷限於任何一條公鏈。不同公鏈的智慧合約方案實現也不同,下面以 以太坊 公鏈舉例說明。
在以太坊上面,開發 NFT 智慧合約,已經有很多標準,比如 ERC-721 \1155 \998,各有各的特點,但它們的特點是在基礎屬性上擴充而來的。(各標準文件: https://eips.ethereum.org/EIPS/eip-721)
如果選擇 ERC-721 標準開發 NFT 智慧合約,在後設資料儲存部分,就有 tokenUrl 這項,它相當於物質的唯一id,像下面的樣子, _tokenURIs
儲存的就是通證當前計數id與其對應的 tokenUrl,這裡的tokenUrl 是字串格式,一般是檔案url,儲存在 IPFS 或其他服務上面的檔案的連結,但不侷限於連結,也可以是其它的內容。
// 虛擬碼
contract MyERC721 is IERC721Metadata, ... {
...
mapping(uint256 => address) private _tokenOwner;
mapping(uint256 => string) private _tokenURIs;
uint256 public tokenCounter; // 計數,當前總的 NFT 的數量,累增
constructor () public ERC721 ("name", "symbol"){
tokenCounter = 0;
}
// 外部呼叫方,呼叫這個函式,傳引數:tokenURI 即物質的id,tokenURI 唯一
function createNFT(string memory tokenURI) public returns (uint256) {
uint256 tokenId = tokenCounter;
_mint(msg.sender, tokenId); // 將交易傳送者和當前的 tokenId 繫結
_setTokenURI(tokenId, tokenURI); // tokenId 對映到 tokenUrl
tokenCounter = tokenCounter + 1; // 累加
return tokenId;
}
// _exists 函式判斷 tokenId 是否存在,_tokenOwner[tokenId]
// 根據 id 讀取對應的 url
function tokenURI(uint256 tokenId) external view returns (string memory) {
require(_exists(tokenId));
return _tokenURIs[tokenId];
}
// 根據 tokenId 和 url 建立 map 資料關係
function _setTokenURI(uint256 tokenId, string memory uri) internal {
require(_exists(tokenId)); // _exists
_tokenURIs[tokenId] = uri;
}
... // 省略系列介面,包含讀介面
}
上面的 tokenUrl 是標準要求的儲存資料項。整個合約具備下面約束功能:
- NFT 持有者,即 msg.sender(owner) 和 tokenId 一對多關係,代表一個人可以擁有多個 NFT;
- tokenId 和 tokenUrl 一對一關係,代表每份資料一個鏈上的唯一id,同時 tokenUrl 沒要求是唯一,但在呼叫方,一般會把 tokenUrl 設定唯一,即使不唯一也沒關係,衝突的時候,tokenId 越小的,其當初被設定的時間就越早;
- NFT 持有者在將資料寫入鏈上後,能夠獲取 NFT 的鏈上唯一 id,後續可以根據 id 進行系列的讀寫操作。
一般來說,我們常規的 NFT 有一個和資料建立關係的項就足夠了,但並不侷限於此,合約在實現了標準要求的介面後,完全可以自己新增自定義資料項及其讀寫函式。
第三步:展示與修改
展示 NFT 內容
所謂展示,就是對 NFT 的資料進行讀取再展示。一般的流程如下:
- 根據當初設定 NFT 資料到鏈上時獲得的 id 去智慧合約讀取資訊;
- 將獲得的資訊通過某介質應用還原出原始的 NFT 資料。
比如將圖片 NFT 展示出。(藉助上面的 721 合約標準和 IPFS 結合為例)
- 假設呼叫合約儲存資料時候得到的 tokenId 是 3,那麼使用這個 tokenId 去呼叫合約的讀資料方法;
- 執行完 1 步驟,可以得到 tokenUrl,即檔案儲存在 IPFS 中所得到的連結;
- 直接將 tokenUrl 連結在瀏覽器開啟,看到圖片。
修改 NFT 內容
修改是一項 NFT 智慧合約的擴充功能,可有可無,具體是怎樣的方式,完全看需求的實現。比如:
- 允許重置 tokenId 所對應的內容;
- 在 NFT 原資料中增加其他欄位內容,再允許修改這些欄位;
- 轉讓 NFT,可以把某 tokenId 對應的 NFT 資訊轉讓給其他 owner,達到轉讓目的;
出售 NFT
、拍賣 NFT
等操作....
所有權共識
目前 NFT,非同質化通證。本質是想借助區塊鏈的屬性來標示一種資產的所有權證明。
比如曾拍賣出6000多萬美金的數字作品(圖片)《Everydays: The First 5000 Days》,中標者能獲得原圖 和 該圖的 NFT。這兩樣東西,一樣是實質的作品,一樣是它的所有權者的證明。
我們假設下,如果持有某作品的人,是一位匿名者A,過了多年後,該作品本身不小心被盜並被找回。那麼如何證明 A 是真正的擁有者,此時 A 只需要展示他對該作品的 NFT 擁有權,就可以證明。
那麼 NFT 是不是類似於我們現實中的證照?不全是,分兩點:
- NFT 和證照都能證明某資產的所有權;
- 對比的儲存介質 與 永恆時效:
- 證照可能要找個保險櫃保養放著,但它終究佔據一方土地,僅受一方土地容納的保險櫃保證安全,在時過境遷的影響下,持續性儲存下去的時間會較短;
- NFT 儲存在區塊鏈上,受整個網際網路的鏈節點所保護。它能夠存活到整個鏈網路垮掉那天,對於節點數量眾多的公鏈來說,這個概率幾乎等同於網際網路終結那天。
第三方平臺
現在已經有很多的第三方的 NFT 製作與釋出平臺。比如 opensea、rarible 等,這些平臺自己實現了 NFT 的智慧合約 和 NFT 展示應用(介質應用---網站),方便大眾 0 程式碼基礎體會 NFT。但也有一些門檻,需要具備錢包和發交易的油費。