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. 将合约写入
    在这里插入图片描述

  2. 编译合约
    在这里插入图片描述

  3. 连接小狐狸并部署合约
    在这里插入图片描述
    我部署的是rinkeby网络
    在这里插入图片描述
    最后进行deploy 部署合约
    在这里插入图片描述
    在这里插入图片描述

  4. 运行合约进行 mint
    先设置金额,就是你要花多少钱购买,在这个位置可以传入金额。
    在这里插入图片描述
    调用合约里的互动方法
    在这里插入图片描述
    在这里插入图片描述

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

IPFS部署图片

生成图片

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

上传到IPFS

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

创建默认图片路径

在这里插入图片描述
先复制上图图片到新目录下,我创建的目录名为unpack,图片重命名为unpack.png,如图:
在这里插入图片描述
和上面一样,上传unpack到ipfs空间。
在这里插入图片描述

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

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值