如何使用 Ethers.js 铸造 NFT

  • Alchemy
  • 发布于 2021-08-31 12:32
  • 阅读 33

本文介绍了如何使用 Ethers.js 库在以太坊区块链上铸造 NFT。文章通过OpenZeppelin库和Ethers.js库,创建Solidity合约、Hardhat 任务、helper,并进行测试,搭建了一个经过充分测试的 NFT 基础设施。此外,还介绍了使用 Pinata 和 IPFS 等工具来简化 NFT 的铸造过程。

Brady Werkheiser 审核


发布于 2021 年 8 月 30 日 阅读需 2 分钟

本教程介绍如何使用 Ethers 通过 ethers.js 库在以太坊区块链上铸造 NFT,以及来自第一部分:如何创建 NFT 的智能合约。我们还将探讨基本测试

完成本指南的预计时间:约 10 分钟

另外,请务必查看我们的 NFT 教程系列的其余部分:

另一个教程 中,我们学习了如何使用 Web3 和 OpenZeppelin 合约库 铸造 NFT。在本练习中,我们将引导你使用 OpenZeppelin 库 的第 4 版以及 Ethers.js 以太坊库(而不是 Web3)进行替代实现。

我们还将介绍使用 Hardhat 和 Waffle 测试你的合约的基础知识。在本教程中,我使用的是 Yarn,但如果你愿意,也可以使用 npm/npx。

最后,我们将使用 TypeScript。这有相当 完善的文档,因此我们在此不再赘述。

在所有其他方面,本教程与 Web3 版本的工作方式相同,包括 Pinata 和 IPFS 等工具。

快速回顾

提醒一下,“铸造 NFT”是指在区块链上发布 ERC721 Token的唯一实例的行为。本教程假定你已在 NFT 教程系列的 第一部分 中成功地 将智能合约部署到 Ropsten 网络,其中包括安装 Ethers。

步骤 1:创建你的 Solidity 合约

OpenZeppelin 是用于安全智能合约开发的库。你可以简单地继承它们对 ERC20 或 ERC721 等流行标准的实现,并根据你的需求扩展行为。我们将把这个文件放在 contracts/MyNFT.sol 中。

已复制

// Contract based on https://docs.openzeppelin.com/contracts/4.x/erc721
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract MyNFT is ERC721URIStorage {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;
    constructor() ERC721("MyNFT", "MNFT") {}
    function mintNFT(address recipient, string memory tokenURI)
    public
    returns (uint256)
    {
        _tokenIds.increment();
        uint256 newItemId = _tokenIds.current();
        _mint(recipient, newItemId);
        _setTokenURI(newItemId, tokenURI);
        return newItemId;
    }
}

步骤 2:创建 Hardhat 任务来部署我们的合约并铸造 NFT

创建包含以下内容的 tasks/nft.ts 文件:

已复制

import { task, types } from "hardhat/config";
import { Contract } from "ethers";
import { TransactionResponse } from "@ethersproject/abstract-provider";
import { env } from "../lib/env";
import { getContract } from "../lib/contract";
import { getWallet } from "../lib/wallet";
task("deploy-contract", "Deploy NFT contract").setAction(async (_, hre) => {
return hre.ethers
    .getContractFactory("MyNFT", getWallet())
    .then((contractFactory) => contractFactory.deploy())
    .then((result) => {
      process.stdout.write(`Contract address: ${result.address}`);
    });
});
task("mint-nft", "Mint an NFT")
.addParam("tokenUri", "Your ERC721 Token URI", undefined, types.string)
.setAction(async (tokenUri, hre) => {
    return getContract("MyNFT", hre)
      .then((contract: Contract) => {
        return contract.mintNFT(env("ETH_PUBLIC_KEY"), tokenUri, {
          gasLimit: 500_000,
        });
      })
      .then((tr: TransactionResponse) => {
        process.stdout.write(`TX hash: ${tr.hash}`);
      });
});

步骤 3:创建助手函数

你会注意到我们的任务导入了一些助手函数。以下是它们。

contract.ts

env.ts

已复制

export function env(key: string): string {
const value = process.env[key];
if (value === undefined) {
    throw `${key} is undefined`;
}
return value;
}

provider.ts

请注意,最终的 getProvider() 函数使用 ropsten 网络。此参数是可选的,如果省略,则默认为“homestead”。我们当然使用的是 Alchemy,但还有几种 支持的替代方案

已复制

import { ethers } from "ethers";
export function getProvider(): ethers.providers.Provider {
return ethers.getDefaultProvider("ropsten", {
    alchemy: process.env.ALCHEMY_API_KEY,
});
}

wallet.ts

已复制

import { ethers } from "ethers";
import { env } from "./env";
import { getProvider } from "./provider";
export function getWallet(): ethers.Wallet {
return new ethers.Wallet(env("ETH_PRIVATE_KEY"), getProvider());
}

步骤 4:创建测试

在你的 test 目录下,创建这些文件。请注意,这些测试并不全面。它们测试了 OpenZeppelin 库提供的 ERC721 功能的一小部分,旨在为你提供构建更强大的测试的基础。

test/MyNFT.spec.ts(单元测试)

tasks.spec.ts(集成规范)

已复制

import { deployTestContract, getTestWallet } from "./test-helper";
import { waffle, run } from "hardhat";
import { expect } from "chai";
import sinon from "sinon";
import * as provider from "../lib/provider";
describe("tasks", () => {
beforeEach(async () => {
    sinon.stub(provider, "getProvider").returns(waffle.provider);
    const wallet = getTestWallet();
    sinon.stub(process, "env").value({
      ETH_PUBLIC_KEY: wallet.address,
      ETH_PRIVATE_KEY: wallet.privateKey,
    });
});
describe("deploy-contract", () => {
    it("calls through and returns the transaction object", async () => {
      sinon.stub(process.stdout, "write");
      await run("deploy-contract");
      await expect(process.stdout.write).to.have.been.calledWith(
        "Contract address: 0x610178dA211FEF7D417bC0e6FeD39F05609AD788"
      );
    });
});
describe("mint-nft", () => {
    beforeEach(async () => {
      const deployedContract = await deployTestContract("MyNFT");
      process.env.NFT_CONTRACT_ADDRESS = deployedContract.address;
    });
    it("calls through and returns the transaction object", async () => {
      sinon.stub(process.stdout, "write");
      await run("mint-nft", { tokenUri: "https://example.com/record/4" });
      await expect(process.stdout.write).to.have.been.calledWith(
        "TX hash: 0xd1e60d34f92b18796080a7fcbcd8c2b2c009687daec12f8bb325ded6a81f5eed"
      );
    });
});
});

test-helpers.ts 请注意,这需要导入 NPM 库,包括 sinon、chai 和 sinon-chai。由于使用了桩(stubbing),因此 sinon.restore() 调用是必需的。

步骤 5:配置

这是我们相当简单的 hardhat.config.ts

已复制

import("@nomiclabs/hardhat-ethers");
import("@nomiclabs/hardhat-waffle");
import dotenv from "dotenv";
// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more
const argv = JSON.parse(env("npm_config_argv"));
if (argv.original !== ["hardhat", "test"]) {
require('dotenv').config();
}
import("./tasks/nft");
import { HardhatUserConfig } from "hardhat/config";
const config: HardhatUserConfig = {
solidity: "0.8.6",
};
export default config;

请注意,仅当我们未运行测试时,才调用 dotenv 的条件。你可能不想在生产环境中运行它,但请放心,如果 .env 文件不存在,dotenv 将会静默地忽略它。

运行我们的任务

现在我们已经将这些文件放置到位,我们可以运行 hardhat 来查看我们的任务(为简洁起见,不包括内置任务)。

已复制

可用的任务:
deploy-contract    部署 NFT 合约
mint-nft      铸造 NFT

忘记了任务的参数?没问题。

已复制

$ hardhat help deploy-contract
用法:hardhat [全局选项] deploy-contract
deploy-contract:部署 NFT 合约

运行我们的测试

要运行我们的测试,我们运行 hardhat test

已复制

  mintNft
    ✓ 通过调用并返回交易对象 (60ms)
MyNFT
    mintNft
      ✓ 发出 Transfer 事件 (60ms)
      ✓ 返回新的项目 ID
      ✓ 增加项目 ID (57ms)
      ✓ 无法铸造到零地址
    balanceOf
      ✓ 获取此地址的 NFT 计数
6 个通过 (2s)
✨  在 5.66 秒内完成。

总结

在本教程中,我们为基于 Solidity 的经过良好测试的 NFT 基础设施创建了一个坚实的基础。waffle.provider.getWallets() 提供的钱包链接到本地伪 Hardhat 网络 帐户,该帐户 方便地预加载 了 eth 余额,我们可以使用它来资助我们的测试交易。

增压 | Alchemy | Substack

使用 Alchemy 的 NFT API 免费开始构建你可以想象的任何 NFT 应用程序 获取你的 API 密钥

📚 目录


  • 快速回顾
  • 步骤 1:创建你的 Solidity 合约
  • 步骤 2:创建 Hardhat 任务来部署我们的合约并铸造 NFT
  • 步骤 3:创建助手函数
  • 步骤 4:创建测试
  • 步骤 5:配置
  • 运行我们的任务
  • 运行我们的测试
  • 总结

分享:

  • 原文链接: alchemy.com/blog/how-to-...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Alchemy
Alchemy
江湖只有他的大名,没有他的介绍。