22

如何更優雅的實現 NFT 智能合約的白名單功能

 2 years ago
source link: https://www.frank.hk/blog/nft-whitelist/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

如何更優雅的實現 NFT 智能合約的白名單功能

如果玩過 NFT,相信你對「白名單」制度不會陌生。NFT公開發售之前,都會讓一小部分被授權的地址,可以提前購買。因為能夠保證取得購買資格,無需與其他人瘋搶,所以往往大家都非常想擠進這個白名單中去。

本文不討論 marketing 的策略,而是說說 NFT 智能合約如何更優雅的處理白名單。

聰明的你肯定想到,可以用一個 mapping,來儲存所有 whitelist 的地址,當 presale 時檢查這個 mapping 中是否有這個地址即可。

1//SPDX-License-Identifier: GPL-3.0
2pragma solidity ^0.8.4;
3import "@openzeppelin/contracts/access/Ownable.sol";
5contract Whitelist is Ownable {
6 mapping (address => bool) userAddr;
8 function addToWhitelist (address[] calldata users) external onlyOwner {
9 for (uint i = 0; i < users.length; i++) {
10 userAddr[users[i]] = true;
14 function preSale() external payable
16 require(whiteList[msg.sender] == true, "STOP: not in whitelist");
17 ...

當然,這個方法絕對沒錯。很多 NFT 專案都是使用這個方法。 可是,這種的做法的一大問題就是成本太貴。 我做了一個實驗,假如按照 gas price 89 gwei 計算, 一次過儲存 1,000 個白名單地址,消耗 502,774 gwei gas, 需要支付 2.06 ETH,約合 67,885 港幣的費用。如果分開多次存儲,花費更高。

當然如果你「不差錢」,那麼就可以不要再看下去了。但如果不捨得這六萬元,我們可以看看有沒有更好的方法。

答案當然是有的。我們看看下面一段 solidity 程式:

1function presale(
2 bytes memory _ticket, // 伺服器發出的「票據」
3 bytes memory _signature // 伺服器發出的「簽名」
4 ) public payable {
6 // 如果你想的話,我們可以在智能合約中檢查「票據」是否被使用過。
7 require(!_ticketUsed[_ticket], "FRANK: ticket has already been used");
9 // 驗證「票據」和「簽名」是否有效
10 require(
11 isAuthorized(
12 msg.sender,
13 _ticket,
14 _signature,
15 signerAddress
17 "FRANK: ticket is invalid"
20 _mint();

相信聰明的你看完後已經有點頭緒了。 這個做法就是引入了一個「票據」和「簽名」的概念。當用戶在你的網頁上 mint NFT 時,不僅僅是直接同智能合約互動,而是需要預先從 web 伺服器憑藉自己的地址,取得一個授權,這個授權包括一個「票據」和一個「簽名」。

從伺服器的角度來看,伺服器保管有一個簽名私鑰,可以根據用戶的地址,加上一個隨機生成的有意義或無意義數據,即「票據」,組合後進行數位簽署,從而得到一個「簽名」。

然後,用戶可以憑藉「票據」和「簽名」,向智能合約發起購買請求。當智能合約收到購買請求後,會對「票據」和「簽名」進行認證。

認證的步驟,我們會使用 solidity 的 ecrecover 方法。ecrecover 可以根據「簽名」,得出簽名者的公鑰地址。因此,在知道簽名者的公鑰地址的前提下,我們就可以透過核對這個地址,來判斷「簽名」是否由簽名者發出。

我們附帶一個「票據」,則某種程度上是為了防止「回放攻擊」( replay attack )。我們可以在智能合約中檢查該 「票據」是否已經被使用過,從而執行不同的邏輯。

1function isAuthorized(
2 address sender, // 發起 trx 人的地址;
3 bytes memory ticket, // 伺服器發出的「票據」
4 bytes memory signature, // 伺服器發出的「簽名」
5 address signerAddress // 簽名人的地址
6 ) private pure returns (bool) {
7 bytes32 hash = keccak256(abi.encodePacked(sender, ticket));
8 return signerAddress == hash.recover(signature);

這種簽名認證的方法,好處非常明顯。我們完全不需要在智能合約中花費大量成本存儲任何白名單地址,就可以優雅的做到白名單效果,而且也可以隨時增加或減少白名單的數量。

不僅如此,使用這個方法,我們亦可以讓智能合約能夠輕易做到一些邏輯驗證。比如,一個購物的智能合約,需要驗證傳入的 ETH 是否和商品價格符合,一個做法是在智能合約中存儲一個商品ID和價格的列表,每當交易時進行比對。而使用簽名認證,則可以使用上述相同邏輯,透過傳入一個「簽名」,智能合約則可以驗證數據的真確性,而無需在智能合約中保存海量昂貴數據。

技術交流,其他諮詢等,請按此聯絡

訂閱我的網站,接收更新以及其他有趣的消息 😙 。 訂閱不收費,走過路過別錯過。
Subscribe to my website, I will email you if any new posts or interesting stuff available.

如果你喜歡我的內容,請考慮用一杯咖啡支持我一下吧,非常感謝 🥰 。
If you like my contents, please support me via BuyMeCoffee, Thanks a lot.

其它相關文章

尚未有任何評論,歡迎在下方發表評論。

評論內容

暱稱 *

電郵(頭像及區分用途,保密且不會顯示) *

WRITTEN BY

Frank Shi

Frank, 居住在香港, 從事 IT 行業,並為這個行業投身了大半生的精力。 沒事喜歡寫寫程式,看看書,畫畫圖,可他並不是一個『宅男』,他很喜歡旅行,遠的去過約旦,近的去過深水埗,每到一個地方,都讓他對這個世界有不同的認識。他也很喜歡寫網誌,錄播客,發 Instagram,就這樣簡單而快樂的生活著。

Frank is an IT guy living in Hong Kong who was majoring in Biology Engineering back to college. Because of the endless love and passion to IT, he changed his direction to Information Technology and got a Master Degree in IT field. What he loves to do including coding, building stuff, gadgets, drawing, traveling and taking (sometimes boring ) photos.


Recommend

  • 10
    • blog.csdn.net 3 years ago
    • Cache

    純前端 - 各種實現進度條

    進度條是一個非常常見的功能,實現起來也不難,一般我們會用 div 來實現。作為一個這麼常見的需求,這篇就要來康康有哪些,以純前端有哪些有意思的方式來實現進度條。 基礎版 - div ps. (這邊以下 gif 周圍稍有些瑕疵,我也不知...

  • 8
    • blog.darkthread.net 3 years ago
    • Cache

    用 80 行 C# 程式實現 Word 套版功能

    用 80 行 C# 程式實現 Word 套版功能 2021-03-06 05:39 PM 5 5,021 Word 套版在本站是個老話題了,我最早是啟動 Word 程式用 Office Auto...

  • 7

    使用 「我的最愛」在 IE 實現 VIP 專屬客製功能-黑暗執行緒開發網站有時會遇到一種狀況,某位使用者有個特殊需求,為一個人修改網頁設計正當性不足,但該功能確實可為他帶來可觀效益(我一直把增進人類全體之生活當成寫程式的核心價值呀)。因此,實務上偶爾會出...

  • 9

    用 Visual Studio Code 實現完美 IoT 網頁介面開發流程-黑暗執行緒如前幾天所說,接觸新語言、新工具或新平台,在正式投入生產前,我習慣先做好幾件事:確立專案通用框架並研究如何讓「修改...

  • 8

    PolkaFantasy 第三章白名單活動介紹 : Play To Earn BTC 預言家...

  • 7

    使用 C#/PowerShell 實現檔案下載續傳功能-黑暗執行緒從網站下載大檔案,若下載一半中斷,從中斷處繼續下載已是所有瀏覽器的基本功能。其背後原理是透過 HTTP 1.1 協定加入的 HTTP...

  • 1

    使用 Azure Functions 搭配 Azure SignalR Service 實現無伺服器架構要在 Azure 實現即時連線式的無伺服器架構(Serverless architecture)其實相當容易,只要學會 Azure Functions 的開發方式,搭配著 Azure SignalR Service 就可以輕鬆實現,本篇文章我將說明實...

  • 3

    美國新稅項打未實現收益主意【匯君】 美國第三季的GDP出爐,按季增長只有2%,是疫情以來按季最低的增長率。市場預期是2.7%,實際上預期由0%~5%也有。

  • 5

    我經常需要在 Azure 手動建立許多測試站台,雖然說設定上並沒有很複雜,但是時間一久,累積出將近百來個 Web App 也是蠻難維護的,而且 組態漂移 (

  • 2
    • blog.niclin.tw 2 years ago
    • Cache

    實現投票功能 acts_as_votable

    Nic Lin's Blog喜歡在地上滾的工程師這兩天挑戰了12 in 12 Challenge的作法,目前第一關有學到一個投票的gem,筆記下來怕以後忘記。不外乎這個gem的名稱正是

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK