当前位置:网站首页>Nft智能合约发行,盲盒,公开发售技术实战--合约篇

Nft智能合约发行,盲盒,公开发售技术实战--合约篇

2022-07-06 07:53:00 NFT践行者

这篇文章主要是从技术视角来给大家介绍一下nft主流的玩法-发行,盲盒,公开发售等流程步骤,这也是目前市场上大部分项目的玩法。

本次文章nft开发主要分为两部分: 1. 合约部分 2. 拼图部分。

本次Nft开发系列我也准备分为两篇文章进行讲解,今天主要讲解合约部分。

  合约部分主要是以下功能:
  • 建立和eth测试网互动的智能合约

  • Nft要能够被mint

  • Nft能够设定总量

  • Nft设定每个地址最大持有量

  • Nft要能够限定单次的mint的量

  • Nft要能够设定开关去公开发售

    拼图部分主要是以下功能:

  • 如何快速制作多种拼图以及meta资料

  • 如何上传ipfs星际网络系统(测试网)

    以上就是本次文章需要讲解的技术点。

开发之前,你需要准备好以下工具和环境。

  1. metamask钱包插件

    The crypto wallet for Defi, Web3 Dapps and NFTs | MetaMask

  2. remix在线编译环境

    Remix - Ethereum IDE

具体钱包的安装以及remix的使用,就不再这边讲解。

合约部分

首先将本次合约部分的源码直接粘贴在remix中进行编译。源码如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
   
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
   
contract NftMeta is ERC721Enumerable, Ownable {
    using Strings for uint256;
   
    // 是否准许nft开卖-开关
    bool public _isSaleActive = false;
    // 初始化盲盒,等到一定时机可以随机开箱,变成true
    bool public _revealed = false;
   
    // nft的总数量
    uint256 public constant MAX_SUPPLY = 10;
    // 铸造Nft的价格
    uint256 public mintPrice = 0.3 ether;
    // 铸造的钱包最多只能有一个nft数量
    uint256 public maxBalance = 1;
    // 一次mint的nft的数量
    uint256 public maxMint = 1;
   
    // 盲盒开关打开后,需要显示开箱的图片的base地址
    string baseURI;
    // 盲盒图片的meta,json地址,后文会提到
    string public notRevealedUri;
    // 默认地址的扩展类型
    string public baseExtension = ".json";
   
    mapping(uint256 => string) private _tokenURIs;
   
    // 构造器
    constructor(string memory initBaseURI, string memory initNotRevealedUri)
        ERC721("Nft Meta", "NM") // 实现了ERC721的父类构造器,是子类继承的一种实现方式
    {
        setBaseURI(initBaseURI);
        setNotRevealedURI(initNotRevealedUri);
    } 
    // 外部地址进行铸造nft的函数调用
    function mintNftMeta(uint256 tokenQuantity) public payable {
        // 校验总供应量+每次铸造的数量<= nft的总数量
        require(
            totalSupply() + tokenQuantity <= MAX_SUPPLY,
            "Sale would exceed max supply"
        );
        // 校验是否开启开卖状态
        require(_isSaleActive, "Sale must be active to mint NicMetas");
        // 校验铸造的钱包地址中的nft的数量 + 本次铸造的数量 <= 该钱包最大拥有的nft的数量
        require( 
            balanceOf(msg.sender) + tokenQuantity <= maxBalance,
            "Sale would exceed max balance"
        );
        // 校验本次铸造的数量*铸造的价格 <= 本次消息附带的eth的数量
        require(
            tokenQuantity * mintPrice <= msg.value,
            "Not enough ether sent"
        );
        // 校验本次铸造的数量 <= 本次铸造的最大数量
        require(tokenQuantity <= maxMint, "Can only mint 1 tokens at a time");
        // 以上校验条件满足,进行nft的铸造
        _mintNftMeta(tokenQuantity);
    }
   
    // 进行铸造
    function _mintNftMeta(uint256 tokenQuantity) internal {
        for (uint256 i = 0; i < tokenQuantity; i++) {
            // mintIndex是铸造nft的序号,按照总供应量从0开始累加
            uint256 mintIndex = totalSupply();
            if (totalSupply() < MAX_SUPPLY) {
                // 调用erc721的安全铸造方法进行调用
                _safeMint(msg.sender, mintIndex);
            }
        }
    }
   
    // 返回每个nft地址的Uri,这里包含了nft的整个信息,包括名字,描述,属性等
    function tokenURI(uint256 tokenId)
        public
        view
        virtual
        override
        returns (string memory)
    {
        require(
            _exists(tokenId),
            "ERC721Metadata: URI query for nonexistent token"
        );
   
        // 盲盒还没开启,那么默认是一张黑色背景图片或者其他图片
        if (_revealed == false) {
            return notRevealedUri;
        }
   
        string memory _tokenURI = _tokenURIs[tokenId];
        string memory base = _baseURI();
   
        // If there is no base URI, return the token URI.
        if (bytes(base).length == 0) {
            return _tokenURI;
        }
        // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
        if (bytes(_tokenURI).length > 0) {
            return string(abi.encodePacked(base, _tokenURI));
        }
        // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
        return
            string(abi.encodePacked(base, tokenId.toString(), baseExtension));
    }
   
    // internal
    function _baseURI() internal view virtual override returns (string memory) {
        return baseURI;
    }
   
    //only owner
    function flipSaleActive() public onlyOwner {
        _isSaleActive = !_isSaleActive;
    }
   
    function flipReveal() public onlyOwner {
        _revealed = !_revealed;
    }
   
    function setMintPrice(uint256 _mintPrice) public onlyOwner {
        mintPrice = _mintPrice;
    }
   
    function setNotRevealedURI(string memory _notRevealedURI) public onlyOwner {
        notRevealedUri = _notRevealedURI;
    }
   
    function setBaseURI(string memory _newBaseURI) public onlyOwner {
        baseURI = _newBaseURI;
    }
   
    function setBaseExtension(string memory _newBaseExtension)
        public
        onlyOwner
    {
        baseExtension = _newBaseExtension;
    }
   
    function setMaxBalance(uint256 _maxBalance) public onlyOwner {
        maxBalance = _maxBalance;
    }
   
    function setMaxMint(uint256 _maxMint) public onlyOwner {
        maxMint = _maxMint;
    }
   
    function withdraw(address to) public onlyOwner {
        uint256 balance = address(this).balance;
        payable(to).transfer(balance);
    }
}

以上就是合约源码。

 对erc721的扩展部分和权限部分进行引用,同时进行继承,重写erc721的部分方法,下文会提到。

这些状态变量主要是用来对Nft的一些属性进行设置,包括总量,每个地址最多mint的数量等。

上面是铸造方法的实现,先进行铸造前的条件校验,然后调用erc721的_safemint安全方法进行铸造。

将合约代码进行部署,其中有几个注意的点

同时将测试网络切到Rinkeby测试网,同时需要提前通过faucet进行测试币的领取。领取地址:

Faucets | ChainlinkGet testnet LINK for an account on one of the supported blockchain testnets so you can create and test your own oracle and Chainlinked smart contract.https://faucets.chain.link/FaucETHicon-default.png?t=M5H6https://fauceth.komputing.org/

Rinkeby: Authenticated Fauceticon-default.png?t=M5H6https://faucet.rinkeby.io/部署完成之后,会出现

在我们mint之前,需要进行开启铸造开关(红色框内),点击将状态变量变成true.

红色函数是铸造方法,填入数量1,同时因为我们在合约的状态变量设置了最小Mint的价格是0.3ether,因此我们需要在msg.value中附带ether数量从而完成mint。

因为红色框中是不允许输入小数的,因此,通过ether网站进行费用单位转换

Ethereum Unit Converter | Ether to Gwei, Wei, Finney, Szabo, Shannon etc.icon-default.png?t=M5H6https://eth-converter.com/

 

 将0.3ether输入,从而得到Gwei的数量,将该数量赋值到以上红框中进行mint。成功之后,就会在ipfs测试网看到一张编号为0的图片。ipfs测试网地址:

至此,我们nft开发中的合约部分已经完成。 

原网站

版权声明
本文为[NFT践行者]所创,转载请带上原文链接,感谢
https://blog.csdn.net/xiaozhupeiqi321/article/details/125560899