NFT 白名单实现方案

白名单现在已经成为 NFT 项目必备运营方式了,因为 NFT 数量有限,一般就是 1 万个,通过白名单可以刺激社区成员的参与度,比如社群里回答问题、在社交平台上帮助项目方推广、拉新用户等。项目一开始也只会开放给白名单来 mint,然后由这些用户上交易所进行二级市场交易。

本文将介绍下如何在智能合约里实现白名单,除了 NFT 项目,其他需要白名单的项目都可以采用这样的方案。设计思路也很简单,就是使用一个 mapping 来保存用户地址即可,把添加和移除白名单的权限开放给管理员。为什么不使用数组呢,是因为如果是数组实现,那么在验证某个用户是否在白名单里,就需要遍历数组才行,这会增加资源的消耗,即导致 gas 费用比较高。

以下为代码和对应的注释:

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.8.0 <0.9.0;

contract Whitelist {
    mapping(address => bool) whitelists;
    address owner;

    constructor() {
        owner = msg.sender;
                
    // 合约部署后,将管理员自己添加到白名单
        whitelists[msg.sender] = true;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "should be owner");
        _;
    }

    // 判断 user 是否在白名单里,仅管理员有权限
    function isUserInWhitelist(address user) public onlyOwner view returns (bool) {
        return whitelists[user];
    }

    // 判断自己是否在白名单里
    // 前端在调用合约的时候,用来判断自己是不是在白名单里,从而可以控制是否显示 mint 按钮
    function amIInWhitelist() public view returns (bool) {
        return isUserInWhitelist(msg.sender);
    }

    // 添加 user 到白名单里,仅管理员有权限
    function addToWhitelist(address user) public onlyOwner {
        whitelists[user] = true;
    }

    // 从白名单里移除 user,仅管理员有权限
    function removeFromWhitelist(address user) public onlyOwner {
        whitelists[user] = false;
    }

    event AfterMint(address user);

    // 要求当前用户是否在白名单内
    modifier inWhitelist() {
        require(whitelists[msg.sender], "user not in whitelist");
        _;
    }

    // 只有在白名单里才能 mint
    function mint() public inWhitelist {
        emit AfterMint(msg.sender);
    }
}

通过上述的示例代码就可以实现白名单了,上述代码仅展示了用户是不是在白名单里,但是如果想实现控制用户可以 mint 几张 NFT,则可以使用下述的数据结构:

// 在 uint 中保存可以 mint 的数量
mapping(address => uint) whitelists;

在判断是否在白名单里,就只需要可 mint 的数量大于 0 即可,通过可以控制可以 mint 的数量。