以太坊实现NFT白名单合约,并且实现前端传入对应的白名单地址来创建(mint)NFT

介绍

一个开源solidity合集仓库
https://github.com/qdwds/smart-contracts
以太坊ERC721全栈开发开NFT合集从入门到项目实战项目
https://learnblockchain.cn/course/31
https://edu.51cto.com/course/33566.html

一起学习吧

我们一起沟通、交流、学习吧!

白名单NFT

默克尔树

Markle Tree 也叫做默克尔树或者哈希树,是区块链的底层加密技术。Markle Tree是一颗倒立的树,根部在最上面,叶子在下面,每片叶子就对应数据的哈希,而且每个叶子的两个节点也是哈希。

默克尔树的原理是将大量数据分割成小块,然后逐层进行哈希运算,最终生成一个根哈希值。具体过程如下:

  • 将要传输的数据分割成固定大小的块,每个块的大小可以根据实际需求确定。
  • 对每个块进行哈希运算,得到一个哈希值
  • 将相邻的两个哈希值进行合并,形成一个新的哈希值。
  • 重复步骤3,直到最后只剩下一个哈希值,这个哈希值就是默克尔树的根哈希值。

在这里插入图片描述

智能合约默克尔树白名单

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract MerkleTree is ERC721 {
    using Counters for Counters.Counter;
    bytes32 public immutable root; // Merkle树的根
    mapping(address => bool) public whiteLists; // 记录已经mint的地址
    Counters.Counter private _tokenIdCounter;

    // 构造函数,初始化NFT合集的名称、代号、Merkle树的根
    constructor(bytes32 merkleroot) ERC721("nft", "nft") {
        root = merkleroot;
    }

    // 利用Merkle树验证地址并完成mint
    function mint(
        address account,
        bytes32[] calldata proof
    ) external {
        require(_verify(_leaf(account), proof), "Invalid merkle proof"); // Merkle检验通过
        require(!whiteLists[account], "Already minted!"); // 地址没有mint过
        uint256 tokenId = _tokenIdCounter.current();
        _tokenIdCounter.increment();
        _mint(account, tokenId); // mint
        whiteLists[account] = true; // 记录mint过的地址
    }

    // 计算Merkle树叶子的哈希值
    function _leaf(address account) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(account));
    }

    // Merkle树验证,调用MerkleProof库的verify()函数
    function _verify(bytes32 leaf, bytes32[] memory proof)
        internal
        view
        returns (bool)
    {
        return MerkleProof.verify(proof, root, leaf);
    }
}

前端实现默克尔树白名单mint

使用到merkletreejs来验证白名单列表

import { keccak256 } from "ethers/lib/utils";
import { ethers } from "hardhat"
import { MerkleTree } from "merkletreejs";
const white = [
    "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
    "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC",
    "0x90F79bf6EB2c4f870365E785982E1f101E93b906"
]
const main = async ()=> {
    // 生成MerkleTree
    const leaf = white.map(x => keccak256(x));
    const markletree = new MerkleTree(leaf, keccak256, {sortPairs: true});
    const root = markletree.getHexRoot();
   
    // 部署合约
    const MarkleTree = await ethers.getContractFactory("MarkleTree");
    const tree = await MarkleTree.deploy(root);
    console.log(tree.address);
    await tree.deployed();

    // 白名单 mint
    for (let i = 0; i < white.length; i++) {
        const proof = markletree.getHexProof(leaf[i]);
        await tree.mint(white[i], proof);
        console.log(await tree.whiteLists(white[i]));
    }

    //  不存在的白名单 会报错
    const proof = markletree.getHexProof(leaf[0]);
    await tree.mint("0x71bE63f3384f5fb98995898A86B02Fb2426c5788", proof);
}

main()
    .catch(err =>{
        console.log(err);
        process.exit(1);
    })
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一份基本的 NFT 工厂合约,它可以创建新的 NFT 代币,并记录其生命周期和所有者历史记录,以实现 NFT 的溯源功能: ``` // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract NFTFactory { // 事件用于记录所有新的 NFT 代币的创建和转让 event NewNFT(address indexed owner, uint256 indexed tokenId); event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); // NFT 代币的数据结构,包含名称、符号、初始所有者等信息 struct NFT { string name; string symbol; address owner; uint256 tokenId; uint256 timestamp; } // 存储所有已经创建NFT 代币 NFT[] public nfts; // 创建新的 NFT 代币 function createNFT(string memory _name, string memory _symbol, address _owner) public returns (uint256) { uint256 tokenId = nfts.length + 1; nfts.push(NFT(_name, _symbol, _owner, tokenId, block.timestamp)); emit NewNFT(_owner, tokenId); return tokenId; } // 获取指定 tokenId 的 NFT 代币信息 function getNFT(uint256 _tokenId) public view returns (string memory, string memory, address, uint256, uint256) { require(_tokenId > 0 && _tokenId <= nfts.length, "Invalid token ID"); NFT memory nft = nfts[_tokenId - 1]; return (nft.name, nft.symbol, nft.owner, nft.tokenId, nft.timestamp); } // 将 NFT 代币转让给新的所有者 function transferNFT(address _from, address _to, uint256 _tokenId) public { require(_from != address(0), "Invalid from address"); require(_to != address(0), "Invalid to address"); require(_tokenId > 0 && _tokenId <= nfts.length, "Invalid token ID"); require(nfts[_tokenId - 1].owner == _from, "Not the owner of the token"); nfts[_tokenId - 1].owner = _to; emit Transfer(_from, _to, _tokenId); } } ``` 合约中有一个 `NFT` 结构体存储每个 NFT 代币的数据,包括名称、符号、初始所有者、代币 ID 和创建时间戳等。当创建新的 NFT 代币时,该结构体会被添加到 `nfts` 数组中,同时会通过 `NewNFT` 事件记录下来。 另外,合约还提供了 `getNFT` 函数用于获取指定 tokenId 的 NFT 代币信息,以及 `transferNFT` 函数用于将 NFT 代币转让给新的所有者。在转让 NFT 代币时,合约会检查转让人是否为有效的 NFT 代币所有者,并将所有者地址更新为新的地址。 通过这份 NFT 工厂合约,我们可以记录每个 NFT 代币的生命周期和所有者历史记录,实现 NFT 的溯源功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值