看過前面幾篇文章的用戶應該知道,對於ERC-20 協議的代幣,我們可以透過以Uniswap 為代表的DEX 進行交易,做到去中心化。那麼對於ERC-721 協議,也就是NFT 來說,如何做到去中心化交易呢。
目前主流的一些NFT 交易所,採用的是掛單的方式進行交易,就像是把一件件商品列到超市的貨架上一樣,購買者覺得價格合適,就可以把商品帶回家。
本文將透過編寫智能合約和一個簡單的前端頁面,實現NFT 的去中心化交易。注意本文只供學習使用,不能真實用在生產環境。
NFT(Non-Fungible Token)
NFT 也就是非同質化代幣,即每一個Token 都是非同質的,不一樣的,它遵循ERC-721 協議。一般來說每一個NFT 在錢包裡面會顯示不同的圖片,每一組NFT 都會有一個獨一無二的ID 來區分。
由於NFT 的特性,它沒有辦法像ERC-20 一樣透過價格曲線來設定價格——因為每個Token 都是不一樣的。所以目前比較常見的交易方式是透過訂單簿的形式。
訂單簿交易
訂單簿模式簡單來說就是商品的價格是人為設定的,有別於Uniswap 這種透過價格曲線計算價格的方式。訂單簿一般來說會分為兩種交易模式,一種是定價單,也就是賣家設定一個自己心裡的出售價格,如果有買家覺得價格合適,就可以由買家購買。另一種是求購單,即買家根據自己的需求,發出求購訂單,當賣家覺得價格合適時,就可以由賣家出售。
一般來說,求購單的價格會低於定價單的價格。本文只介紹第一種定價方式。
NFT DEX 的功能
一個NFT DEX 的基礎功能應該包含以下基本的功能:
上架商品:將一個NFT 依照定價進行上架
購買商品:根據NFT 的定價購買
DEX 手續費:依成交的價格按比例收取手續費
上架商品
上架商品需要做以下幾件事:
前端:使用者選擇自己的NFT,並且設定一個價格,點選上架。
合約:使用者需要為合約設定權限,可以操控使用者的NFT。
這樣商品就算上架了。在合約中,需要維護一份用戶的上架商品價格Map,這部分資料一般來說是可以做到中心化的服務中,以減少合約的負擔,但在本文中這部分Map 資料會維護在合約裡面。
購買商品
購買商品的時候會發生幾件事:
前端:使用者選擇一個想要購買的NFT,點選購買。
合約:調用合約,將用戶的錢轉到NFT 的賣方,並將NFT 轉到買方。
實作一個NFT DEX
在本章節,我們將會從零開始實作一個NFT 的DEX,這是筆者已經部署好的DEX 位址nft-dex-frontend.vercel.app。
1. 建立一個NFT
為了測試需要,我們最好是能夠擁有自己的NFT。我們可以透過Remix 快速建立一個ERC-721 協定的NFT,它提供了對應的模板。
我們按照模板可以方便地部署一個NFT。當然你也可以跳過這一個步驟,直接使用我們準備好的NFT。
2. 合約編寫
我們的合約方法應該要包含幾個方法:
2.1. 賣家上架NFT
賣家需要指定要出售的NFT 以及對應的價格。在上架時,使用者需要簽署NFT 的授權方法,讓我們的智能合約有權限操作這個NFT,這樣當有買家購買之後,這筆交易可以自動成交。
所以流程應該是這樣的: 1. 使用者選擇自己的NFT;2. 設定價格,這裡的計價可以是穩定幣USDT、USDC,也可以是ETH;3. 授權NFT 給到合約。
之後就可以呼叫合約的上架方法了,該方法需要做以下幾件事:
對NFT 的所有權進行校驗
新增上架記錄
觸發上架的事件
2.2. 買家購買NFT
買家在購買NFT 的時候,用戶只需要選擇自己想要的NFT,並支付相應的代幣。合約層面會執行以下幾個步驟: 1. 從「listings 」讀取到對應的NFT 資料;2. 根據NFT 的價格,計算手續費,並從成交價中扣除這部分;3. 轉移NFT 到買家手中;4. 觸發購買的事件
2.3. 取消上架
當然,賣家可能會覺得價格不合適,會選擇取消上架。可以看到我們在保存上架資訊的地方,保留了一個isActive 的字段,用於表明該商品是否有效,因此在取消上架的時候,我們只需要將這個字段設置為false 即可。
2.4. 提取手續費
DEX 可以在每一筆的交易中收取手續費,這個手續費即可以存到合約裡,也可以轉存到另一個你自己的地址中去,本文採取存到合約裡的方式。
到此為止,我們的合約基本功能就算完整了。
3. DEX 前端開發
在開始之前,我們需要準備一些工具,包含以下幾個工具:
Ant Design Web3:用於錢包的連接以及NFT 卡片的展示。
Wagmi:用於和錢包進行互動。
Nextjs + Vercel:部署我們的專案。
我們的前端應用程式應該包含三個頁面,Mint、Buy 以及Portfolio,Mint 是為了讓用戶能夠Mint 我們的NFT,僅用於演示,Buy 的話是我們的DEX 商城,用戶可以在裡面購買我們的NFT,Portfolio 裡面用戶可以對NFT 進行上架和下架操作。
3.1. 連接錢包
連接用戶的錢包,使用Ant Design Web3 實現
連接用戶的錢包的過程非常簡單,使用Ant Design Web3提供的連接元件即可。
首先我們在專案的外層包一個Provider, 這樣在後續的程式碼裡面我們就能用到Ant Design Web3 的能力。另外由於我們需要連接sepolia 測試鏈,為了速度考慮,建議使用一些節點服務來提高資料查詢的速度,我這裡使用的是ZAN的endpoint,它非常適合在亞太環境下使用,速度快並且價格非常划算,支援的鏈也很豐富。
之後在需要連接錢包的地方放置一個連接按鈕:
這樣就算是搞定了,非常的簡單。
3.2. Mint
Mint 一個NFT,獲得測試代幣可以前往https://zan.top/faucet/ethereum
在Mint 頁面我們可以Mint 測試用的NFT。 Mint 是一個寫合約的操作,這裡我們要用到wagmi 裡面的useWriteContract 方法。我們需要指定好合約地址、合約的ABI 以及合約參數即可。
之後在錢包裡面確認就可以Mint 成功了。
3.3. Portfolio
管理用戶的NFT
在這裡需要展示用戶所有的NFT。我們可以使用一些NFT API 來獲取,這裡使用opensea 的API,因為支援sepolia 測試鏈的NFT API 並不多。
在取得到用戶的NFT 清單之後,需要判斷是否已經是上架了的,未上架的支援上架,已上架的支援下架。判斷的方式是透過DEX 合約裡面「 getSellerListings 」方法裡面取得使用者已經上架的NFT,然後根據這些NFT 的「 isAlive 」欄位來判斷是否正在上架。
上架的時候需要呼叫「 listNFT 」合約方法,在取消的時候需要呼叫「 cancelListing 」方法。在上架之前,需要額外呼叫NFT 的授權方法,將NFT 授權給合約,這樣在後續交易成交之後,這個NFT 就可以自動轉給買方。
3.4. Buy
在Buy 裡面可以購買NFT
首先我們需要對已經上架的NFT 進行展示。類似Portfolio 裡面的展示用戶已有的NFT,這裡不同點在於一個是全域的,不再是某個用戶,另一個是只需要展示isAlive 的NFT。
購買的時候使用「 purchaseNFT 」方法,在呼叫這個方法的時候,需要用ETH 來支付售價。
這裡的這個「value 」就是買家需要支付的ETH。
這樣一個包含所有基礎能力的DEX 前端頁面就完成了,我們可以將其部署在vercel 中。
本文由ZAN Team(X 帳號@zan_team ) 的 Yeezo(X 帳號@GaoYeezo 75065 )撰寫。