白名单现在已经成为 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 的数量。
