solidity nft编写 demo

前提

该项目是我这段时间的一个学习心得,一个简单的以太坊的NFT demo项目,该代码仅供学习,在学习前,希望你已经熟悉了solidity、eth、ipfs等技术。
该项目简单的总结是:利用ipfs存储图片和图片的json信息,然后将图片/json的ipfs 地址传入solidity合约中进行售卖,其中利用到了ERC721非同质化协议。
值得一提的是你买到的作品不是属于你的,因为作品在ipfs上,你没有ipfs的账号权限那你并没有NFT作品的实质拥有权。所以请要购买nft的同学小心。

安装

  • Metamask 安裝 -
    https://metamask.io/

  • Rinkeby faucet 測試幣領取 -
    https://faucets.chain.link/rinkeby
    https://fauceth.komputing.org/
    https://faucet.rinkeby.io/

  • ETH 線上編輯器 -
    https://remix.ethereum.org/

  • Nic Meta 智能合約範例 -
    https://github.com/niclin/nic_meta/blob/master/contracts/nic_meta_nft.sol

  • ETH 轉 Gwei -
    https://eth-converter.com/

  • OpenSea 測試網路 -
    https://testnets.opensea.io/

  • HashLips 組圖專案 -
    https://github.com/HashLips/hashlips_art_engine

  • IPFS 上傳空間 -
    https://www.pinata.cloud/

OpenSea

OpenSea是一個總部位於美國紐約市的非同質化代幣在线交易市场[1]。截止2022年1月,該公司的估值為 133億美元,被認為是最大的非同質化代幣交易平台。

代码

// Contract based on https://docs.openzeppelin.com/contracts/3.x/erc721
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

contract NicMeta is ERC721Enumerable, Ownable {
    using Strings for uint256;
	// 是否开始售卖
    bool public _isSaleActive = false;
    // 是否展示
    bool public _revealed = false;

    // Constants
    // 最大支持NFT数
    uint256 public constant MAX_SUPPLY = 10;
    // nft发布交易的最小值
    uint256 public mintPrice = 0.01 ether;
    // 最大金额
    uint256 public maxBalance = 1;
    // 最大发型数
    uint256 public maxMint = 1;
	// 基础路径,后面要放nft图片
    string baseURI;
    // 不显示图片路径
    string public notRevealedUri;
    // 展示的数据结尾:.json
    string public baseExtension = ".json";

    mapping(uint256 => string) private _tokenURIs;
	// ERC721("Nic Meta", "NM") 创建nft 的名字和简称
    constructor(string memory initBaseURI, string memory initNotRevealedUri)
        ERC721("Nic Meta", "NM")
    {
    	// 初始化图片的路径
        setBaseURI(initBaseURI);
        setNotRevealedURI(initNotRevealedUri);
    }

    function mintNicMeta(uint256 tokenQuantity) public payable {
    	// 进行判断你所挖的NFT是否大于最大数
        require(
            totalSupply() + tokenQuantity <= MAX_SUPPLY,
            "Sale would exceed max supply"
        );
        // 必须先开启售卖才能进行购买
        require(_isSaleActive, "Sale must be active to mint NicMetas");
        // 判断金额大小
        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");
		// 开始mint
        _mintNicMeta(tokenQuantity);
    }

    function _mintNicMeta(uint256 tokenQuantity) internal {
    	// 进行售卖,查找有没有合适的NFT
        for (uint256 i = 0; i < tokenQuantity; i++) {
            uint256 mintIndex = totalSupply();
            if (totalSupply() < MAX_SUPPLY) {
            	// ERC721 下的方法,进行安全铸造NFT,并且转给合约调用者 
                _safeMint(msg.sender, mintIndex);
            }
        }
    }

    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);
    }
}

Remix操作合约

remix 地址:https://remix.ethereum.org/

  1. 将合约写入
    solidity nft编写 demo_第1张图片

  2. 编译合约
    solidity nft编写 demo_第2张图片

  3. 连接小狐狸并部署合约
    solidity nft编写 demo_第3张图片
    我部署的是rinkeby网络
    solidity nft编写 demo_第4张图片
    最后进行deploy 部署合约
    solidity nft编写 demo_第5张图片

  4. 运行合约进行 mint
    先设置金额,就是你要花多少钱购买,在这个位置可以传入金额。
    solidity nft编写 demo_第6张图片
    调用合约里的互动方法
    solidity nft编写 demo_第7张图片
    solidity nft编写 demo_第8张图片

  5. 打开测试网的opensea 查看你的nft
    这里的opensea要先连接小狐狸才能进行查看
    solidity nft编写 demo_第9张图片
    到这,如果看到了这个图片就是成了,只是图片没有,因为我们还没开始进行IPFS部署图片

IPFS部署图片

生成图片

打开https://github.com/HashLips/hashlips_art_engine,克隆项目,这需要你有前端编程技术,如果没有,那可以结束了。
solidity nft编写 demo_第10张图片
下载后,src/main.js 这里修改为0
solidity nft编写 demo_第11张图片
进行build
solidity nft编写 demo_第12张图片
ta会帮你建立很多图片
solidity nft编写 demo_第13张图片
solidity nft编写 demo_第14张图片
到时候我们传上ipfs上的就是build文件里的images和json文件夹

上传到IPFS

打开https://www.pinata.cloud/,上传build文件里的images文件夹
solidity nft编写 demo_第15张图片
得到地址
在这里插入图片描述
将config.js文件的路径更换成我们的IPFS地址,如图第十行
solidity nft编写 demo_第16张图片
然后更新
solidity nft编写 demo_第17张图片
打开https://www.pinata.cloud/,上传build文件里的json文件夹里的文件
solidity nft编写 demo_第18张图片
和上面的图片文件夹一样得到一个ipfs地址

创建默认图片路径

solidity nft编写 demo_第19张图片
先复制上图图片到新目录下,我创建的目录名为unpack,图片重命名为unpack.png,如图:
solidity nft编写 demo_第20张图片
和上面一样,上传unpack到ipfs空间。
solidity nft编写 demo_第21张图片

新增unpack.json 文件,里面的内容如图:
image填写的是刚上传的unpack.png的ipfs地址。
solidity nft编写 demo_第22张图片
上传unpack.json到ipfs
solidity nft编写 demo_第23张图片
返回remix, 在互动setNotRevealedURI里填写unpack.json的ipfs
在这里插入图片描述
在setBaseURI填写unpack.png的ipfs
solidity nft编写 demo_第24张图片
结尾要加上"/"
solidity nft编写 demo_第25张图片
再打开opensea,如果图片变了就是成功了。

你可能感兴趣的:(技术)