NFT空投预售的几种方法

预售是运营NFT的常见手段。

  • 链上预售白名单

方法是在合约的存储中简单地包含一个地址映射变量,将每个地址映射到一个布尔值,或者每个地址映射到该地址允许的铸币数量。

  1. mapping(address => uint8) _allowList;  
  2.   
  3.     function setAllowList(  
  4.         address[] calldata addresses,  
  5.         uint8 numAllowedToMint  
  6.     ) external onlyOwner {  
  7.         for (uint256 i = 0; i < addresses.length; i++) {  
  8.             _allowList[addresses[i]] = numAllowedToMint;  
  9.         }  
  10.     } 

这种方法使用起来简单,但在配置白名单时,将会耗费大量的gas费用。

  • 默克尔树

使用openzeppelin的MerkleProof.verify进行验证。

在合约中只需要存储roothash,验证时用户需传入默克尔树证明,新增叶子节点时,也只需要更新roothash。

验证通过后可领取空投,并将状态改为已领取,避免重复领取。

  1. import '@openzeppelin/contracts/utils/cryptography/MerkleProof.sol';  
  2. ...  
  3. // declare bytes32 variables to store each root (a hash)  
  4. bytes32 public genesisMerkleRoot;  
  5. bytes32 public authorsMerkleRoot;  
  6. bytes32 public presaleMerkleRoot;  
  7. ...  
  8. // separate functions to set the roots of each individual Merkle Tree  
  9. function setGenesisMerkleRoot(bytes32 _root) external onlyOwner {  
  10.  genesisMerkleRoot = _root;  
  11. }  
  12. function setAuthorsMerkleRoot(bytes32 _root) external onlyOwner {  
  13.   authorsMerkleRoot = _root;  
  14. }  
  15. function setPresaleMerkleRoot(bytes32 _root) external onlyOwner {  
  16.   presaleMerkleRoot = _root;  
  17. }  
  18. ...  
  19. // create merkle leaves from supplied data  
  20. function _generateGenesisMerkleLeaf(  
  21.   address _account,  
  22.   uint256 _tokenId  
  23. )  internal  pure  returns (bytes32) {  
  24.  return keccak256(abi.encodePacked(_tokenId, _account));  
  25. }  
  26. function _generateAuthorsMerkleLeaf(  
  27.   address _account,  
  28.   uint256 _tokenCount  
  29. )  internal  pure  returns (bytes32) {  
  30.   return keccak256(abi.encodePacked(_account, _tokenCount));  
  31. }  
  32. function _generatePresaleMerkleLeaf(  
  33.   address _account,  
  34.   uint256 _max  
  35. )  internal  pure  returns (bytes32) {  
  36.   return keccak256(abi.encodePacked(_max, _account));  
  37. }  
  38. ...  
  39. // function to verify that the given leaf belongs to a given tree using its root for comparison  
  40. function _verifyMerkleLeaf(  
  41.   bytes32 _leafNode,  
  42.   bytes32 _merkleRoot,  
  43.   bytes32[] memory _proof ) internal view returns (bool) {  
  44.   return MerkleProof.verify(_proof, _merkleRoot, _leafNode);  
  45. }  

然后,调用每个 mint/claim 函数都需要使用发送者的地址来生成和验证叶子节点。 例如,当使用 for loop 铸造多个代币时

  1. require(  
  2.   _verifyMerkleLeaf(  
  3.      _generateGenesisMerkleLeaf(  
  4.         msg.sender,  
  5.         _tokenIds[i]),  
  6.      genesisMerkleRoot,  
  7.      _proofs[i]  
  8. ), "Invalid proof, you don't own that Token ID");

猜你喜欢

转载自blog.csdn.net/2301_76642277/article/details/129582931