NFT Development 102 — 公平发售

写在开头

大家好,我是 Jacob Wei,17 年入圈起一直从事区块链相关工作,专注智能合约与服务端的开发。最近 NFT 领域的兴起让我兴奋不已,因此我想在这里和大家分享一些 NFT 教程中缺失的部分即:NFT 项目的开发、部署、上线的完整流程。

本文需对对智能合约及 ERC721 有简单的了解,同时不会包含具体的代码实现,相关的开发资源都附上了对应的教程,本文更多的是分享一些开发思路。

关于 NFT 的章节,计划分为 3 个部分:

  1. NFT Development 102 —— 公平发售:即本文,发售阶段如何保证公平性
  2. NFT Development 102 —— 测试、部署及上架:讲解 NFT 开发阶段如何进行测试、部署及合约管理
  3. NFT Development 102 —— NFT 生成及随机性证明:随机性证明验证属性随机及相关衍生品设计

本文将从合约、后端、前端三个方面讲述如何在 NFT 发售阶段做到尽量公平,尽可能让真实用户 Mint 成功。文章结构如下:

  • 合约
    • 禁止合约调用
    • 白名单验证
    • 验证Merkle Proof
    • 签名参数验证
  • 后端
    • API防护
    • 私钥防护
  • 前端
    • 源码防护
    • 模拟器及群控检测
    • Cloudflare 设置

合约

NFT 的发售中大家讨论最多的问题归纳一下分为以下几种:

  • 禁止合约调用
  • 白名单验证
  • 调用参数验证
  • 合约闭源

禁止合约调用

如果合约允许其他合约调用 Mint ,那大概率就会变成科学家秀操作的舞台。即使每个地址限量也可通过工程合约创建出期望数量的地址进行 Mint。

防范手段: 通过判断 TX 的发出方和发售合约收到请求的来源是否一致来判断,是否来自于其他合约的调用。如 Azuki 中的验证如下:

modifier callerIsUser() {
    require(tx.origin == msg.sender, "The caller is another contract");
    _;
}

注:关于 msg.sender and tx.origin 的区别示例可以查看 Phishing with tx.origin

白名单验证

常见的白名单验证方式分为两种:

合约记录白名单

对于白名单数量较少或对 Merkle tree 不太熟悉的项目方可能会采用这种方式,优点就是逻辑简单,可以随时添加或删除。缺点也很明显,就是项目方需要支付修改白名单数据的费用。如 Azuki 中可以批量设置白名单地址及对应的数量,gas 消耗数量可以参考 seedAllowlist Tx

示例:Azuki seedAllowlist

function seedAllowlist(address[] memory addresses, uint256[] memory numSlots)
    external
    onlyOwner
  {
    require(
      addresses.length == numSlots.length,
      "addresses does not match numSlots length"
    );
    for (uint256 i = 0; i < addresses.length; i++) {
      allowlist[addresses[i]] = numSlots[i];
    }
  }

验证Merkle Proof

比较常见同时推荐使用的的方式是合约验证 Merkle Proof,通过提交链下生成的 Proof 在合约中进行验证。这个方案也是经过了很多次验证,能够充分满足实际需求,除了验证白名单地址外还可以添加 Mint 数量、空投数量等信息。

Mint 过程中用户获取 Proof 的方法可以使用 API 或将 Merkle Tree 公开让用户自行获取,下面的资源中提供了 API 的示例。

这里有很多现成的方案可以参考,资源如下:

  1. 视频教程: OpenZeppelin Building an NFT Merkle Airdrop
  2. Library: Merkletreejs Library
  3. Demo: nft-merkle-drop

注意事项:

  1. 白名单地址判断:有的项目白名单形同虚设在合约中并没有验证。
  2. 白名单 Mint 数量判断:Mint 数量应记录在合约中而不应使用地址的 balanceOf 进行判断,否则会出现白名单重复 Mint 的问题。

签名参数验证

对于公开发售阶段(非白名单),一般会采用参数验证的方式来检验用户数据是否合法,从过往的案例中经常出现的问题有以下几个:

  1. 统一的参数值所有用户使用同一个参数值进行验证,这将降低机器人批量操作的难度。
  2. 参数提前暴露顾名思义当科学家们提前获取到验证参数,就有足够的时间准备机器人。
  3. 私钥泄漏这种情况虽然很少出现但是也应该引起项目方的重视,不要将私钥在前端暴露,将签名过程及参数的生成过程放在后端执行。

参数验证环节,推荐的开发模式:在参数验证环节推荐的开发模式为每个地址的生成不同的调用参数,以防止重放攻击。

参考资源:

针对后续两个问题我们放在后端章节进行讨论

合约闭源

项目方为了降低合约被攻击或滥用的可能选择不公开合约源代码,不单单是在 NFT 领域在 GameFi 项目中也是如此。如果将此作为防御手段并不能够很好的防范机器人操作,举例说明:

SuperGucci 采用合约闭源的方式进行发售,其参数较为简单所以被聪明的科学家朋友攻破是必然的事情,只是时间的早晚而已。最终由于被科学家拿走了太多筹码,而不得不将最后一轮调整为了抽签发售。从链上调用数据可以看出参数和地址无关,没有其他特别的参数,因此对于此类合约存在使用相同参数重放调用的可能。

个人并不推荐这种方式进行发售,对于没有知名 IP 的项目来说未开源的项目并不能够给用户足够的信心,同样这样一点也不 Crypto 。

后端

在参数验证环节提到了参数提前暴露及私钥暴露两个问题,相应的解决方案为:

API防护

为防止参数提前暴露,API 端对参数返回条件进行控制:

  • 按照自身项目需求根据时间戳或起始区块返回签名数据
  • 动态调整返回值结构,或可以尝试对数据进行二次加密等

私钥防护

私钥防护可以从两个方面入手:

  • 由服务端提供 API 用来完成参数构建及签名的过程,避免签名私钥在前端暴露
  • 发售前均适用测试地址进行签名,发售时启用生产地址进行签名

如果完成了以上两个步骤是否就万无一失了呢?对于大部分热门项目来说是的,因为对于热门项目来说公开发售基本上几分钟就销售一空,夸张的可能在几个区块里就卖空,所以留给科学家进行破解的时间就不是特别充足。那么对于采用荷兰拍机制存在长时间的降价等待时,此方法也就失效了,因为科学家们有足够的时间对接 API 获取验证参数来调用合约,最终在期望的价位把库存一扫而空。

IP 限制

另外未了防止被同一用户获取过多可以针对同一 IP 限制签名数量,防止同一用户使用不同地址参与发售。

前端

前端方面将从源码防护、模拟器及群控检测、Cloudflare 设置三个方面聊起。以下方案都是一些思路,具体执行上最终都是项目方和科学家们斗智斗勇,就看谁更技高一筹了,看各位大神表演。

源码防护

完成了合约和后端的防护,那么对于前端来说想要提高业务的安全性大致可以通过加密、混淆、编译、打包等方式,这方面前端的小伙伴可能就比较熟悉了。有个思路如下 JavaScript obfuscator + bytenode + node-packer

同时逻辑部分的代码在发售前几分钟再执行部署,这样让科学家来不及从前端里面扒出更多信息。别忘记部署后刷新下CDN的缓存,防止用户受到旧的缓存影响。下图为 Cloudflare 中清楚缓存的页面:

image

另外需要注意的是针对合约地址和合约 ABI 可以使用一些加密手段进行隐藏或混淆,如拆分多端然后 base64,避免科学家从混淆后的 Js 中通过正则提取出来。

模拟器及群控检测

除了源码部分前端还应该对于群控或模拟器做些判断,如检查浏览器屏幕大小,判断 Selenium 这类自动化插件,一般来说这类插件都会在 js 全局变量里面插入一些函数和变量,有很多检测方案可以尝试,网上资源也比较多这里就不再赘述。

Cloudflare 设置

Cloudflare 中一些配置可以帮助我们提高对 Bot 的防护,当然破解方式还是有的,不存在什么万全之策,能做的只能是尽自己最大的努力进行防护。

Bot Fight Mode

需购买 Cloudflare Pro 版本,价格为 $20 / month 。

image

Under Attack Mode

发售阶段开启 Under Attack Mode 模式,也就是常见的五秒盾用来验证请求合法性。

image

Legacy Captcha

如需要提高防护等级,可以开启 legacy captcha,但是这样会影响一些用户体验,要和用户提前说明可能会遇到验证码而且有些验证码比较难识别。

开启路径为:Firewall Rules → Managed Challenge → Legacy CAPTCHA

写在最后

想要实现真正公平的发售是个挺复杂的问题,项目方可能也没办法把大部分精力放在技术层面。在可以遇见的将来,会出现比较完善的发售平台使得艺术家或项目方只需关注作品层面,而不需要直面技术中的种种困难。

NFT 的发售其实只是 NFT 项目其中一部分,除了上述的注意事项外还有很多细节值得重视,比如版税的设置、合约及前后端的测试、NFT Metadata 的部署、属性的随机性和稀有性、开图的公平性、还有 NFT 质押机制的设计、NFT 衍生品的设计等,如果大家感兴趣可以在后续的文章中继续和大家深入讨论。

祝愿大家都能够 Mint 到自己喜欢的 NFT。

Subscribe to Jacob Wei
Receive the latest updates directly to your inbox.
Verification
This entry has been permanently stored onchain and signed by its creator.