编写SmartContract铸造NFT

  • zhengyq
  • 更新于 2022-06-27 11:35
  • 阅读 1737

这是本系列文章的第三篇,这篇文章我们就开始编写一个能铸造NFT的智能合约了。当然这不是一篇solidity的教学文章,所以不会在编码细节上做过多的介绍

这是本系列文章的第三篇,在第一篇文章中部署了开发测试环境,第二篇文章中准备了开发环境,这篇文章我们就开始编写一个能铸造NFT的智能合约了。当然这不是一篇solidity的教学文章,所以不会在编码细节上做过多的介绍

初始化项目

我们可以直接在第二篇文章中准备的container里新建项目目录,也可以通过docker的参数 -v 来挂载一个本地目录。准备好之后就可以初始化项目了

~ $ mkdir app
~ $ cd app
~/app $ npm init -y
~/app $ truffle init

初始化完成后,项目目录会自动生成以下文件:

~/app $ tree
.
|-- contracts
|   `-- Migrations.sol
|-- migrations
|   `-- 1_initial_migration.js
|-- package.json
|-- test
`-- truffle-config.js

3 directories, 4 files

VSCode中打开项目目录

打开VSCode,按照第二篇文章中的方法Remote到container,打开项目目录

Untitled21.png

在开始编写合约之前,还需要安装一个solidity插件,直接在插件搜索框中搜索solidity

Untitled22.png

新建.sol合约文件并安装依赖包

在开始写合约之前,还需要再做一件事,新建一个合约文件和安装依赖包

~/app $ touch contracts/TestNFT.sol
~/app $ npm install @openzeppelin/contracts

新建合约文件之后的目录结构(我过滤了node_modules目录)

~/app $ tree -I "node_modules"
.
|-- contracts
|   |-- Migrations.sol
|   `-- TestNFT.sol
|-- migrations
|   `-- 1_initial_migration.js
|-- package-lock.json
|-- package.json
|-- test
`-- truffle-config.js

3 directories, 6 files

在VSCode中编写合约

编码就不多介绍了,铸造NFT的代码都非常相似,网上也有很多类似文章

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.4.22 <0.9.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

contract TestNFT is ERC721URIStorage, Ownable{

    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    mapping(uint => uint) public priceMap;

    event Minted(address indexed minter, uint price, uint nftID, string uri);
    constructor() ERC721("TestNFT", "NFT"){}

    function mintNFT(string memory _uri, address _toAddress, uint _price) public onlyOwner returns (uint256) {
        _tokenIds.increment();
        uint256 newItemId = _tokenIds.current();

        priceMap[newItemId] = _price;

        _safeMint(_toAddress, newItemId);
        _setTokenURI(newItemId, _uri);

        emit Minted(_toAddress, _price, newItemId, _uri);

        return newItemId;
    }
}

新建合约测试文件并安装依赖库

在正式部署合约之前,还需要对合约做一些测试,新建一个测试文件并安装依赖包

~/app $ touch test/testnft_test.js
~/app $ npm install chan
~/app $ npm install bignumber.js
~/app $ npm install dotenv
~/app $ npm install @truffle/hdwallet-provider
~/app $ npm install @openzeppelin/test-environment
~/app $ tree -I "node_modules"
.
|-- contracts
|   |-- Migrations.sol
|   `-- TestNFT.sol
|-- migrations
|   `-- 1_initial_migration.js
|-- package-lock.json
|-- package.json
|-- test
|   `-- testnft_test.js
`-- truffle-config.js

3 directories, 7 file

编写合约测试文件

const { web3 } = require("@openzeppelin/test-environment");
const { expect } = require("chai");
const { BigNumber } = require("bignumber.js");

const TestNFTContract = artifacts.require("TestNFT");

contract("TestNFT", (accounts) => {

    describe("testnft", () => {
        beforeEach(async () => {
            this.contract = await TestNFTContract.new({ from: accounts[0] });
        });

        it("It should mint NFT successfully", async () => {
            const tokenURI = "ipfs://QmXzG9HN8Z4kFE2yHF81Vjb3xDYu53tqhRciktrt25JpAN";

            const mintResult = await this.contract.mintNFT(
              tokenURI,
              accounts[0],
              web3.utils.toWei("12", "ether"),
              { from: accounts[0] }
            );
            console.log(mintResult);
            const price = web3.utils.fromWei(
              new BigNumber(mintResult.logs[1].args.price).toString(),
              "ether"
            );
            expect(mintResult.logs[1].args.nftID.toNumber()).to.eq(1);
            expect(mintResult.logs[1].args.uri).to.eq(tokenURI);
            expect(mintResult.logs[1].args.minter).to.eq(accounts[0]);
            expect(price).to.eq("12");
        });
    });

    describe("owner()", () => {
        it("returns the address of the owner", async () => {
          const testntf = await TestNFTContract.deployed();
          const owner = await testntf.owner();
          assert(owner, "the current owner");
        });

        it("matches the address that originally deployed the contract", async () => {
          const testntf = await TestNFTContract.deployed();
          const owner = await testntf.owner();
          const expected = accounts[0];
          assert.equal(owner, expected, "matches address used to deploy contract");
        });
    });
});

修改truffle配置文件

在运行测试代码之前还需要修改一下配置文件。在初始化项目的时候生成了一个配置文件:truffle-config.js,我们需要修改这个配置文件添加Quorum测试环境的配置信息。

const HDWalletProvider = require("@truffle/hdwallet-provider");

module.exports = {

  networks: {
    development: {
      provider: () => new HDWalletProvider(mnemonic, `https://chain.azure-api.net/testrpc`),
      network_id: "1337",       // Quorum default network id 1337 (default: none)
    }
  },

  mocha: {},

  compilers: {
    solc: {
      version: "0.8.14",      // Fetch exact version from solc-bin (default: truffle's version)
    }
  },
};

运行测试

~/app $ truffle test --network development
Compiling your contracts...
===========================
> Compiling ./contracts/Migrations.sol
> Compiling ./contracts/TestNFT.sol
> Compiling @openzeppelin/contracts/token/ERC721/ERC721.sol
> Compiling @openzeppelin/contracts/token/ERC721/IERC721.sol
> Compiling @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
> Compiling @openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol
> Compiling @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol
> Compiling @openzeppelin/contracts/utils/Address.sol
> Compiling @openzeppelin/contracts/utils/Context.sol
> Compiling @openzeppelin/contracts/utils/Counters.sol
> Compiling @openzeppelin/contracts/utils/Strings.sol
> Compiling @openzeppelin/contracts/utils/introspection/ERC165.sol
> Compiling @openzeppelin/contracts/utils/introspection/IERC165.sol
> Artifacts written to /tmp/test--792396-qihnnT01oLfP
> Compiled successfully using:
   - solc: 0.8.14+commit.80d49f37.Emscripten.clang

  Contract: TestNFT
    testnft
      ✔ It should mint NFT successfully (9142ms)
    owner()
      ✔ returns the address of the owner (1069ms)
      ✔ matches the address that originally deployed the contract (1090ms)

  3 passing (21s)
点赞 1
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

3 条评论

请先 登录 后评论
zhengyq
zhengyq
我们是微软CSI(Microosft China Strategic Incubator)团队,目前负责中国区web3领域创业孵化。主要是中国大陆、香港、台湾等地区的公司出海去往Global的web3项目。希望大家以后多多支持我们,谢谢!此外,我们在 web3领域和Microsoft Azure相关的所有研究都将放在这个 github 地址上: https://github.com/0xMSDN 联系邮箱:xiaopingfeng@microsoft.com