---
title: "如何使用 web3.js 铸造 NFT"
description: "了解使用 Web3.js 铸造 NFT 的分步指南，轻松进入数字资产的世界，释放你的创造力。"
---

# 如何使用 web3.js 铸造 NFT

本教程介绍如何使用 Web 3 以及我们在第一部分《How to Create an NFT》中创建的智能合约，在 Ethereum 区块链上铸造一个 NFT。

*预计完成本指南所需时间：约 10 分钟*

此外，别忘了查看我们 NFT 教程系列的其他文章：

- 🪄  [How to mint an NFT with Ether.js](https://www.alchemy.com/blog/how-to-mint-an-nft-with-ethers-js)
- 👛  [How to view your NFT in your mobile wallet](https://www.alchemy.com/blog/how-to-view-your-nft-in-your-mobile-wallet)
- 💸  [How to set a price on an NFT](https://www.alchemy.com/blog/how-to-set-a-price-on-an-nft)
- 💻  [NFT minter tutorial: How to create a full stack dApp](https://www.alchemy.com/blog/nft-minter-tutorial-how-to-create-a-full-stack-dapp)

“铸造 NFT”是指在区块链上发布你的 ERC721 代币的一个唯一实例。既然我们已经在本 NFT 教程系列第一部分中 [将智能合约部署到了 Sepolia 网络](https://www.alchemy.com/blog/how-to-create-an-nft)，接下来就让我们运用 web3 技能来铸造一个 NFT 吧！

完成本教程后，你就可以用这段代码随意铸造任意数量的 NFT —— 现在开始吧！

## 第 1 步：安装 Web3

如果你完成了第一篇教程中关于[创建 NFT 智能合约](https://www.alchemy.com/docs#create-and-deploy-your-smart-contract-using-hardhat)的内容，你应该已经使用过 Ethers.js。Web3 与 Ethers 类似，都是用于简化向 Ethereum 区块链发起请求的库。在本教程中，我们将使用 [Alchemy Web3](https://www.alchemy.com/docs)，这是一个增强版的 web3 库，提供自动重试和稳健的 WebSocket 支持。

在你的项目根目录下运行：

## 第 2 步：创建 mint-nft.js 文件

在 scripts 目录下创建一个 mint-nft.js 文件，并添加以下代码：

## 第 3 步：获取你的合约 ABI

我们的合约 ABI（Application Binary Interface，应用二进制接口）是与智能合约交互的接口。[Hardhat](https://www.alchemy.com/dapps/hardhat) 会自动为我们生成 ABI，并保存在 MyNFT.json 文件中。要使用它，我们需要在 **mint-nft.js** 文件中添加以下代码来解析出其内容：

如果你想查看这个 ABI，可以将其打印到控制台：

要运行 **mint-nft.js** 并在控制台看到打印出的 ABI，请前往终端运行

## 第 4 步：使用 IPFS 配置 NFT 的元数据

如果你还记得第一部分教程的内容，我们的 mintNFT 智能合约函数接受一个 tokenURI 参数，该参数应指向一个描述 NFT 元数据的 JSON 文档 —— 这正是赋予 NFT 生命力的关键所在，使其能够拥有可配置的属性，比如名称、描述、图片以及其他特征。

<CalloutBlock>

星际文件系统（Interplanetary File System，IPFS）是一种去中心化协议，也是一个用于在分布式文件系统中存储和共享数据的点对点网络。

</CalloutBlock>

我们将使用 [Pinata](https://pinata.cloud/)——一个便捷的 IPFS API 和工具包——来存储我们的 NFT 资产和元数据，以确保 NFT 真正去中心化。如果你还没有 [Pinata](https://www.alchemy.com/dapps/pinata) 账户，请前往 [pinata.cloud](https://pinata.cloud/) 注册一个免费账户，并完成邮箱验证步骤。

创建好账户后：

- 点击右上角的“Pinata Upload”按钮
- 上传一张图片到 pinata —— 这将作为你的 NFT 图像资产。你可以随意为这个资产命名
- 上传完成后，页面顶部会出现一个绿色弹窗，让你查看上传内容的哈希值 —> 复制该哈希码。你可以在这里查看你的上传内容：`https://gateway.pinata.cloud/ipfs/<hash-code>`

为方便更偏好可视化学习的读者，上述步骤总结如下：接下来，我们还需要再上传一份文档到 Pinata。但在此之前，我们需要先创建它！

<ImageBlock
  src="https://media.alchemy.com/1704625396-pinata-upload.gif"
  alt="Pinata 控制台：将 NFT 图片资源上传到 IPFS"
  width={844}
  height={480}
  caption="上传文件到 Pinata"
/>

在你的根目录下，新建一个名为 nft-metadata.json 的文件，并添加以下 json 代码：

​你可以自由修改 json 中的数据，也可以在 attributes 部分增删内容。最重要的是，确保 image 字段指向你上传到 IPFS 的图片位置 —— 否则你的 NFT 将会带有一张（非常可爱的！）狗狗照片。

编辑完 json 文件后，保存它，并按照我们上传图片时的相同步骤，将其上传到 Pinata。

<ImageBlock
  src="https://media.alchemy.com/1704625535-upload-json-file-to-pinata.gif"
  alt="Pinata 控制台：上传 NFT 元数据 JSON 文件"
  width={844}
  height={480}
  caption="上传 json 文件到 Pinata"
/>

## 第 5 步：创建你的合约实例

现在，为了与我们的合约交互，我们需要在代码中创建它的一个实例。为此，我们需要合约地址，可以从部署记录中获取，也可以通过 [Etherscan](https://sepolia.etherscan.io/) 查找你用于部署合约的地址来获取。

<ImageBlock
  src="https://media.alchemy.com/1704625679-create-an-instance-of-contract.png"
  alt="Etherscan：查找已部署的 NFT 合约地址"
  width={2880}
  height={1510}
  caption="创建你的合约实例"
/>

在上面的示例中，我们的合约地址是 0x81c587EB0fE773404c42c1d2666b5f557C470eED。

接下来，我们将使用 web3 的 [contract 方法](https://web3js.readthedocs.io/en/v1.2.0/web3-eth-contract.html?highlight=constructor#web3-eth-contract)，通过 ABI 和地址创建我们的合约。在你的 **mint-nft.js** 文件中，添加以下内容：

## 第 6 步：更新 .env 文件

现在，为了创建并向 Ethereum 链发送交易，我们需要使用你的公共 ethereum 账户地址来获取账户的 **nonce**（下文会解释）。

将你的公钥添加到 **.env** 文件中 —— 如果你完成了教程第一部分，**.env** 文件现在应该是这样的：

## 第 7 步：创建你的交易

首先，让我们定义一个名为 `mintNFT(tokenData)` 的函数，并按照以下方式创建我们的交易：

1. 从 .env 文件中取出你的 **PRIVATE_KEY** 和 **PUBLIC_KEY**。
1. 接下来，我们需要确定账户的 nonce。nonce 规范用于记录从你的地址发出的交易数量 —— 这既是出于安全考虑，也是为了防止[重放攻击](https://www.alchemy.com/docs)。要获取从你的地址发出的交易数量，我们使用 [getTransactionCount](https://www.alchemy.com/docs)。
1. 最后，我们用以下信息配置我们的交易：
1. **'from': PUBLIC_KEY**：我们交易的发起地址即我们的公共地址
1. **'to': contractAddress**：我们希望交互并发送交易的合约
1. **'nonce': nonce**：账户 nonce，即从我们地址发出的交易数量
1. **'gas': estimatedGas**：完成交易所需的预估 gas
1. **'maxPriorityFeePerGas': estimatedFee**：每单位 gas 的预估出价费用
1. **'data': nftContract.methods.mintNFT\(PUBLIC_KEY, md\).encodeABI\(\)**：我们希望在此交易中执行的计算 —— 在本例中即铸造一个 NFT

你的 `mint-nft.js` 文件现在应该是这样的：

<CalloutBlock>

**如何铸造多个 NFT：** 要在单条命令中铸造 x 个 NFT，我们可以在包装铸造过程的函数内使用一个从 0 到 x-1 的简单 for 循环。这样，每次调用该包装铸造函数时，就能有效铸造出 x 个 NFT。

</CalloutBlock>

## 第 8 步：签名交易

现在我们已经创建了交易，需要对其进行签名才能发送出去。这时我们就需要用到私钥了。

`web3.eth.sendSignedTransaction` 会返回交易哈希，我们可以用它来确认交易是否被成功打包，还是被网络丢弃了。你会注意到，在交易签名部分，我们添加了一些错误检查，以便知道交易是否成功发出。‍

## 第 9 步：调用 mintNFT 并运行 node contract-interact.js

还记得你上传到 Pinata 的 metadata.json 吗？从 Pinata 获取其哈希码，并将以下内容传入对 mintNFT 的调用 [https://gateway.pinata.cloud/ipfs/](https://gateway.pinata.cloud/ipfs/%3Chash-code%3E)​

获取哈希码的方法如下：

<ImageBlock
  src="https://media.alchemy.com/1704625935-get-the-hashcode-on-pinata.gif"
  alt="Pinata 控制台：复制已上传元数据的 IPFS 哈希"
  width={844}
  height={480}
  caption="在 Pinata 上获取哈希值"
/>

<CalloutBlock>

在单独的窗口中打开 [https://gateway.pinata.cloud/ipfs/](https://gateway.pinata.cloud/ipfs/%3Chash-code%3E)，仔细确认你复制的哈希码链接到的正是你的 `metadata.json`。该页面应类似于下方截图：

</CalloutBlock>

<ImageBlock
  src="https://media.alchemy.com/1704626043-returned-hashcode-on-pinata.png"
  alt="从 Pinata IPFS 网关返回的 NFT 元数据 JSON"
  width={2878}
  height={1714}
  caption="Pinata 返回的哈希值"
/>

整合起来，你的代码应该类似这样：

现在，运行 `node scripts/mint-nft.js` 来部署你的 NFT。几秒钟后，你应该会在终端看到类似这样的响应：

接下来，访问你的 [Alchemy mempool](https://dashboard.alchemy.com/mempool) 查看交易状态（是待处理、已打包，还是被网络丢弃）。如果你的交易被丢弃了，检查 [Sepolia Etherscan](https://sepolia.etherscan.io/) 并搜索你的交易哈希也会有帮助。

<ImageBlock
  src="https://media.alchemy.com/1704626257-search-for-transaction-hash.png"
  alt="在区块浏览器中搜索 NFT 铸造交易哈希"
  width={2846}
  height={1586}
  caption="搜索你的交易哈希"
/>

就是这样！你现在已经在 Ethereum 区块链上完成了 NFT 的部署和铸造 🎉

使用 `mint-nft.js`，你可以随心所欲（钱包也允许的话）铸造任意数量的 NFT！只需确保每次传入一个新的 `tokenURI` 来描述 NFT 的元数据 —— 否则，你最终只会铸造出一堆 ID 不同但内容相同的 NFT。

想必你也希望能在钱包中展示你的 NFT 😉 —— 那就一定要看看第三部分：[How to View Your NFT in Your Wallet](/blog/how-to-view-your-nft-in-your-mobile-wallet)。
