NFT Minter 教程:如何创建一个完整的堆栈 dApp

  • Alchemy
  • 发布于 2021-08-31 23:30
  • 阅读 47

本教程介绍了如何构建一个 NFT 铸造器(NFT minter),通过将智能合约连接到 React 前端,使用 Metamask 和 Web3 工具,来创建一个完整的 dApp。内容涵盖连接 Metamask、调用智能合约方法、签署交易等步骤,并详细解释了如何使用 Pinata 将 NFT 元数据存储到 IPFS。

NFT Minter 教程:如何创建一个完整的堆栈 dApp

作者:Alchemy Team

审核人:Brady Werkheiser


发布于 2021 年 8 月 30 日,阅读需要 14 分钟

在本教程中,你将构建一个 NFT minter,并学习如何通过使用 Metamask 和 Web3 工具将你的智能合约连接到 React 前端来创建一个完整的堆栈 dApp。

另外,请务必查看我们的 NFT 教程系列的其他内容:

对于来自 Web2 背景的开发人员来说,最大的挑战之一是弄清楚如何将你的智能合约连接到前端项目并与之交互。

通过构建一个 NFT minter——一个简单的 UI,你可以在其中输入指向你的数字资产的链接、标题和描述——你将学习如何:

  • 通过你的前端项目连接到 Metamask

  • 从你的前端调用智能合约方法

  • 使用 Metamask 签署交易

在本教程中,我们将使用 React 作为我们的前端框架。由于本教程主要侧重于 Web3 开发,因此我们不会花费太多时间来分解 React 的基础知识。相反,我们将专注于为我们的项目带来功能。

作为先决条件,你应该具有 React 的初级理解水平——了解组件、props、useState/useEffect 和基本函数调用的工作方式。 如果你以前从未听说过这些术语中的任何一个,你可能需要查看此 React 入门教程。 对于更多视觉学习者,我们强烈推荐 Net Ninja 提供的这个出色的 完整现代 React 教程 视频系列。

事不宜迟,让我们开始吧!

步骤 0:NFT 101 制作

在我们开始查看任何代码之前,重要的是要了解制作 NFT 的工作原理。 它涉及两个步骤:

1) 在以太坊区块链上发布一个 NFT 智能合约。通常这是一个 ERC-721ERC-1155 智能合约。

两种 NFT 智能合约标准的最大区别在于,ERC-1155 是一种多代币标准,包括批处理功能,而 ERC-721 是一种单一代币标准,因此仅支持一次转移一个代币。

2) 调用该 NFT 智能合约上的铸造函数来铸造 NFT。铸造 只是在区块链上发布你的非同质化代币的唯一实例的行为。

通常,此铸造函数要求你传入两个变量作为参数,首先是接收者,它指定将收到你新铸造的 NFT 的地址,其次是 NFT 的 tokenURI ,一个解析为描述 NFT 元数据的 JSON 文档的字符串。

NFT 的元数据真正赋予了它生命力,使其具有属性,例如名称、描述、图像(或不同的数字资产)和其他属性。 这是一个 tokenURI 示例,其中包含 NFT 的元数据。

在本教程中,我们将重点关注第 2 部分,即使用我们的 React UI 调用现有 NFT 的智能合约铸造函数。

这是一个链接 到我们将在本教程中调用的 ERC-721 NFT 智能合约。 如果你想了解我们是如何制作的,我们强烈建议你查看我们的另一个教程“ 如何创建 NFT”。

太棒了,现在我们了解了制作 NFT 的工作原理,让我们克隆我们的入门文件吧!

步骤 1:克隆入门文件

首先,转到 nft-minter-tutorial github 存储库以获取此项目的入门文件。 将此存储库克隆到你的本地环境。

不知道如何克隆存储库? 查看 Github 的 本指南

当你打开这个克隆的 nft-minter-tutorial 存储库时,你会注意到它包含两个文件夹:minter-starter-filesnft-minter

  • minter-starter-files 包含此项目的入门文件(本质上是 React UI)。 在本教程中,我们将在这个目录中工作,因为你将学习如何通过将其连接到你的以太坊钱包和一个 NFT 智能合约来使这个 UI 焕发生机。

  • nft-minter 包含完整的已完成教程,并且在你遇到困难时可以作为参考

接下来,在你的首选代码编辑器中打开你的 minter-starter-files 的副本(在 Alchemy,我们是 VSCode 的忠实粉丝),然后导航到你的 src 文件夹:

我们将在“src”文件夹中工作

在你的选择的编辑器中打开 minter-starter-files在你的选择的编辑器中打开 minter-starter-files

我们将编写的所有代码都将位于 src 文件夹下。 我们将编辑 Minter.js 组件并编写额外的 javascript 文件,以使我们的项目具有 Web3 功能。

步骤 2:查看我们的入门文件

在开始编码之前,重要的是要查看入门文件中已为我们提供的功能。

运行你的 react 项目

让我们首先在我们的浏览器中运行 React 项目。 React 的优点在于,一旦我们的项目在我们的浏览器中运行,我们保存的任何更改都将在我们的浏览器中实时更新。

要运行该项目,请导航到 minter-starter-files 文件夹的根目录,然后在你的终端中运行 npm install 以安装项目的依赖项:

已复制

cd minter-starter-files npm install

一旦这些安装完成,在你的终端中运行 npm start

已复制

npm start

这样做应该会在你的浏览器中打开 http://localhost:3000/,在那里你将看到我们项目的前端。 它应该包含 3 个字段:一个输入你的 NFT 资产链接的地方、输入你的 NFT 名称的地方以及提供描述的地方。

你的项目 UI 应该是什么样子你的项目 UI 应该是什么样子

如果你尝试单击“连接钱包”或“铸造 NFT”按钮,你会注意到它们不起作用——那是因为我们仍然需要对它们的功能进行编程! :)

Minter.js 组件

注意:确保你在 minter-starter-files 文件夹中,而不是 nft-minter 文件夹中!

让我们回到我们的编辑器中的 src 文件夹并打开 Minter.js 文件。 了解此文件中的所有内容非常重要,因为它是我们将要处理的主要 React 组件。

在我们的这个文件的顶部,我们有我们的状态变量,我们将在特定事件后更新它们。

已复制

//状态变量 const [walletAddress, setWallet] = useState(""); const [status, setStatus] = useState(""); const [name, setName] = useState(""); const [description, setDescription] = useState(""); const [url, setURL] = useState("");

从未听说过 React 状态变量或状态Hook? 查看 这些 文档。

以下是每个变量的表示:

  • walletAddress - 一个存储用户钱包地址的字符串

  • status - 一个包含要在 UI 底部显示的消息的字符串

  • name - 一个存储 NFT 名称的字符串

  • description - 一个存储 NFT 描述的字符串

  • url - 一个指向 NFT 数字资产的链接的字符串

在状态变量之后,你将看到三个未实现的函数:useEffectconnectWalletPressedonMintPressed。 你会注意到所有这些函数都是 async,这是因为我们将在其中进行异步 API 调用! 它们的名称与它们的功能相同:

已复制

` useEffect(async () => { //TODO:实现

}, []); const connectWalletPressed = async () => { //TODO:实现

}; const onMintPressed = async () => { //TODO:实现

}; `

  • useEffect- 这是一个在你的组件渲染后调用的 React Hook。 因为它有一个空数组 [] prop 传递给它(参见第 3 行),它只会在组件的首次渲染时被调用。 在这里,我们将调用我们的钱包监听器和另一个钱包函数来更新我们的 UI,以反映是否已连接钱包。

  • connectWalletPressed - 将调用此函数以将用户的 Metamask 钱包连接到我们的 dApp。

  • onMintPressed - 将调用此函数以铸造用户的 NFT。

在此文件末尾附近,我们有我们组件的 UI。 如果你仔细扫描这段代码,你会注意到当其相应文本字段中的输入发生更改时,我们会更新我们的 urlnamedescription 状态变量。

你还会看到,当单击 ID 为 mintButtonwalletButton 的按钮时,分别调用 connectWalletPressedonMintPressed

最后,让我们说明在哪里添加了这个 Minter 组件。

如果你转到 App.js 文件,这是 React 中的主要组件,充当所有其他组件的容器,你将看到我们的 Minter 组件在第 7 行注入。

在本教程中,我们将只编辑 Minter.js 文件并在我们的 src 文件夹中添加文件。

现在我们了解了我们正在使用什么,让我们设置我们的以太坊钱包!

步骤 3:设置你的以太坊钱包

为了让用户能够与你的智能合约交互,他们需要将他们的以太坊钱包连接到你的 dApp。

下载 Metamask

对于本教程,我们将使用 Metamask,这是一个浏览器中的虚拟钱包,用于管理你的以太坊帐户地址。 如果你想了解更多关于以太坊上的交易如何运作的信息,请查看以太坊基金会的 此页面

你可以在 这里 免费下载并创建一个 Metamask 帐户。 当你创建一个帐户时,或者如果你已经有一个帐户,请确保在右上角切换到“Ropsten 测试网络”(这样我们就不会处理真钱)。

Metamask 钱包示例Metamask 钱包示例

从水龙头添加以太币

为了铸造我们的 NFT(或签署以太坊区块链上的任何交易),我们将需要一些假的 Eth。 要获得 Eth,你可以转到 Ropsten 水龙头 并输入你的 Ropsten 帐户地址,然后单击“发送 Ropsten Eth”。 你应该很快在你的 Metamask 帐户中看到 Eth!

检查你的余额

为了再次确认我们的余额是否存在,让我们使用 Alchemy 的 composer 工具 发出 eth_getBalance 请求。 这将返回我们钱包中的 Eth 数量。 在你输入你的 Metamask 帐户地址并单击“发送请求”后,你应该会看到如下所示的响应:

已复制

{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"}

注意:此结果以 wei 而不是 eth 为单位。 Wei 用作以太币的最小面额。 从 wei 到 eth 的转换是:1 eth = 10¹⁸ wei。 因此,如果我们将 0xde0b6b3a7640000 转换为十进制,我们得到 1*10¹⁸,等于 1 eth。

唷! 我们的假钱都在那里! 🤑

步骤 4:将 Metamask 连接到你的 UI

现在我们的 Metamask 钱包已设置好,让我们将我们的 dApp 连接到它!

因为我们想遵守 M-V-C 范例,我们将创建一个单独的文件,其中包含我们的函数来管理我们的 dApp 的逻辑、数据和规则,然后将这些函数传递到我们的前端(我们的 Minter.js 组件)。

connectWallet 函数

为此,让我们在你的 src 目录中创建一个名为 utils 的新文件夹,并在其中添加一个名为 interact.js 的文件,其中将包含我们所有的钱包和智能合约交互函数。

在我们的 interact.js 文件中,我们将编写一个 connectWallet 函数,然后我们将导入并在我们的 Minter.js 组件中调用它。

在你的 interact.js 文件中,添加以下内容

让我们分解一下这段代码的作用:

首先,我们的函数检查你的浏览器中是否启用了 window.ethereum

window.ethereum 是 Metamask 和其他钱包提供商注入的全局 API,允许网站请求用户的以太坊帐户。 如果获得批准,它可以从用户连接到的区块链读取数据,并建议用户签署消息和交易。 查看 Metamask 文档 以获取更多信息!

如果 window.ethereum 不存在,则表示未安装 Metamask。 这导致返回一个 JSON 对象,其中返回的 address 是一个空字符串,并且 status JSX 对象表明用户必须安装 Metamask。

我们编写的大多数函数都将返回 JSON 对象,我们可以使用它们来更新我们的状态变量和 UI。

现在,如果 window.ethereum 存在,那么事情就会变得有趣。

使用 try/catch 循环,我们将尝试通过调用 window.ethereum.request({ method: "eth_requestAccounts" }); 连接到 Metamask。 调用此函数将在浏览器中打开 Metamask,用户将被提示将其钱包连接到你的 dApp。

  • 如果用户选择连接,则 method: "eth_requestAccounts" 将返回一个数组,其中包含所有已连接到 dApp 的用户的帐户地址。 总而言之,我们的 connectWallet 函数将返回一个 JSON 对象,其中包含此数组中的第一个 address(参见第 9 行)和一个 status 消息,提示用户向智能合约编写消息。

  • 如果用户拒绝连接,则 JSON 对象将包含一个空字符串作为返回的 address 和一个反映用户拒绝连接的 status 消息。

将 connectWallet 函数添加到你的 Minter.js UI 组件

现在我们已经编写了这个 connectWallet 函数,让我们将其连接到我们的 Minter.js. 组件。

首先,我们必须通过添加 import { connectWallet } from "./utils/interact.js" ; 到 Minter.js 文件的顶部来将我们的函数导入到我们的 Minter.js 文件。 你的 Minter.js 的前 11 行现在应该如下所示:

已复制

import { useEffect, useState } from "react"; import { connectWallet } from "./utils/interact.js"; const Minter = (props) => { //状态变量 const [walletAddress, setWallet] = useState(""); const [status, setStatus] = useState(""); const [name, setName] = useState(""); const [description, setDescription] = useState(""); const [url, setURL] = useState("");

然后,在我们的 connectWalletPressed 函数中,我们将调用我们导入的 connectWallet 函数,如下所示:

已复制

const connectWalletPressed = async () => {     const walletResponse = await connectWallet();     setStatus(walletResponse.status);     setWallet(walletResponse.address); };

请注意,我们的大部分功能都从 interact.js 文件中的 Minter.js 组件中抽象出来了吗? 这是为了让我们遵守 M-V-C 范例!

connectWalletPressed 中,我们只是对我们导入的 connectWallet 函数进行 await 调用,并使用它的响应,我们通过它们的状态Hook更新我们的 statuswalletAddress 变量。

现在,让我们保存这两个文件(Minter.jsinteract.js)并测试我们到目前为止的 UI。

http://localhost:3000/ 页面上打开你的浏览器,然后按页面右上角的“连接钱包”按钮。

如果你安装了 Metamask,你将被提示将你的钱包连接到你的 dApp。 接受连接邀请。

你应该看到钱包按钮现在反映你的地址已连接! 太棒了 🔥

接下来,尝试刷新页面...这很奇怪。 我们的钱包按钮提示我们连接 Metamask,即使它已经连接了...

页面重新加载时出现问题页面重新加载时出现问题

不过,别担心! 我们可以通过实现一个名为 getCurrentWalletConnected 的函数轻松修复它,该函数将检查是否已有地址连接到我们的 dApp 并相应地更新我们的 UI!

getCurrentWalletConnected 函数

在你的 interact.js 文件中,添加以下 getCurrentWalletConnected 函数:

此代码与我们之前编写的 connectWallet 函数非常相似。

主要的区别在于,我们没有调用方法 eth_requestAccounts,该方法打开 Metamask 以供用户连接他们的钱包,而是调用方法 eth_accounts,该方法只是返回一个包含当前连接到我们的 dApp 的 Metamask 地址的数组。

要查看此函数的实际效果,让我们在我们的 Minter.js 组件的 useEffect 函数中调用它。

就像我们对 connectWallet 所做的那样,我们必须像这样从我们的 interact.js 文件中将此函数导入到我们的 Minter.js 文件中:

已复制

import { useEffect, useState } from "react"; import { connectWallet, getCurrentWalletConnected //在此处导入 } from "./utils/interact.js";

现在,我们只需在我们的 useEffect 函数中调用它:

已复制

useEffect(async () => {     const {address, status} = await getCurrentWalletConnected();     setWallet(address)     setStatus(status); }, []);

请注意,我们使用我们对 getCurrentWalletConnected 的调用的响应来更新我们的 walletAddressstatus 状态变量。

添加此代码后,尝试刷新我们的浏览器窗口。 按钮应该说你已连接,并显示你连接的钱包地址的预览 - 即使在你刷新后! 😅

实现 addWalletListener

我们 dApp 钱包设置的最后一步是实现钱包监听器,以便我们的 UI 在我们钱包的状态发生变化时更新,例如当用户断开连接或切换帐户时。

在你的 Minter.js 文件中,添加一个 addWalletListener 函数,如下所示:

让我们快速分解一下这里发生的事情:

首先,我们的函数检查是否启用了 window.ethereum(即安装了 Metamask)。

  • 如果没有,我们只需将我们的 status 状态变量设置为一个 JSX 字符串,提示用户安装 Metamask。

  • 如果已启用,我们在第 3 行设置监听器 window.ethereum.on("accountsChanged"),该监听器监听 Metamask 钱包中的状态变化,其中包括用户将其他帐户连接到 dApp、切换帐户或断开帐户连接时。 如果至少连接了一个帐户,则 walletAddress 状态变量将更新为监听器返回的 accounts 数组中的第一个帐户。 否则,walletAddress 将设置为空字符串。

最后,我们必须在我们的 useEffect 函数中调用它:

已复制

`useEffect(async () => {     const {address, status} = await getCurrentWalletConnected();     setWallet(address)     setStatus(status);

    addWalletListener(); }, []); `

万岁! 我们已经完成了我们所有钱包功能的编程! 现在我们的钱包已设置好,让我们弄清楚如何铸造我们的 NFT!

步骤 5:NFT 元数据 101

所以请记住我们刚刚在本教程的步骤 0 中讨论过的 NFT 元数据——它赋予了 NFT 生命力,允许它具有属性,例如数字资产、名称、描述和其他属性。

我们需要将此元数据配置为 JSON 对象并存储它,以便我们可以在调用我们智能合约的 mintNFT 函数时将其作为 tokenURI 参数传入。

“资产链接”、“名称”、“描述”字段中的文本将构成我们 NFT 元数据的不同属性。 我们将把此元数据格式化为 JSON 对象,但我们可以选择将其存储在以下位置:

  • 我们可以将其存储在以太坊区块链上; 但是,由于以太坊的性质,这样做会非常昂贵(我们说的是数百美元)。 ❌

  • 我们可以将其存储在中心化服务器上,例如 AWS 或 Firebase。 但这将违背我们的去中心化精神。 ❌

  • 我们可以使用 IPFS,一种用于在分布式文件系统中存储和共享数据的去中心化协议和点对点网络。 由于此协议是去中心化的且免费,因此它是我们的最佳选择! ✅

为了将我们的元数据存储在 IPFS 上,我们将使用 Pinata,一个方便的 IPFS API 和工具包。 在下一步中,我们将准确地解释如何做到这一点!

步骤 6:使用 Pinata 将你的元数据固定到 IPFS

如果你没有 Pinata 帐户,请在此处注册一个免费帐户 here 并完成验证你的电子邮件和帐户的步骤。

创建你的 Pinata API 密钥

导航到 https://pinata.cloud/keys 页面,然后选择顶部的“新密钥”按钮,将管理员小部件设置为启用,然后命名你的密钥。

创建你的 Pinata API 密钥创建你的 Pinata API 密钥

然后你将看到一个弹出窗口,其中包含你的 API 信息。 确保将其放在安全的地方。

确保将你的 API 密钥和密钥保存在安全的地方确保将你的 API 密钥和密钥保存在安全的地方

现在我们的密钥已设置好,让我们将其添加到我们的项目中,以便我们可以使用它。

创建一个 .env 文件

我们可以安全地将我们的 Pinata 密钥和密钥存储在环境文件中。 让我们在你的项目目录中安装 dotenv 包

在你的终端中打开一个新选项卡(与正在运行本地主机的选项卡分开),并确保你在 minter-starter-files 文件夹中,然后在你的终端中运行以下命令:

已复制

npm install dotenv --save

接下来,通过在你的命令行上输入以下内容,在你的 minter-starter-files 的根目录中创建一个 .env 文件:

已复制

vim .env

这将在 vim(一个文本编辑器)中弹出你的 .env 文件。 要保存它,请在键盘上按“esc”+“:”+“q”,依次进行。

接下来,在 VSCode 中,导航到你的 .env 文件并将你的 Pinata API 密钥和 API 密钥添加到其中,如下所示:

已复制

REACT_APP_PINATA_KEY = REACT_APP_PINATA_SECRET =

保存该文件,然后你就可以开始编写将你的 JSON 元数据上传到 IPFS 的函数了!

实现 pinJSONToIPFS

幸运的是,Pinata 有一个 专门用于将 JSON 数据上传到 IPFS 的 API 和一个方便的带有 axios 示例的 JavaScript,我们可以使用它,并进行一些细微的修改。

在你的 utils 文件夹中,让我们创建另一个名为 pinata.js 的文件,然后像这样从 .env 文件中导入我们的 Pinata 密钥和密钥:

已复制

require('dotenv').config(); const key = process.env.REACT_APP_PINATA_KEY; const secret = process.env.REACT_APP_PINATA_SECRET;

接下来,将以下代码中的附加代码粘贴到你的 pinata.js 文件中。 别担心,我们将分解一切的含义!

已复制

`require('dotenv').config(); const key = process.env.REACT_APP_PINATA_KEY; const secret = process.env.REACT_APP_PINATA_SECRET; const axios = require('axios'); export const pinJSONToIPFS = async(JSONBody) => {     const url =https://api.pinata.cloud/pinning/pinJSONToIPFS`;     //向 Pinata 发出 axios POST 请求 ⬇️     return axios         .post(url, JSONBody, {             headers: {                 pinata_api_key: key,                 pinata_secret_api_key: secret,             }         })         .then(function (response) {            return {                success: true,                pinataUrl: "https://gateway.pinata.cloud/ipfs/" + response.data.IpfsHash            };         })         .catch(function (error) {             console.log(error)             return {                 success: false,                 message: error.message,             }

    }); }; ``

所以这段代码到底做了什么?

首先,它导入 axios,这是一个基于 promise 的 HTTP 客户端,适用于浏览器和 node.js,我们将使用它来向 Pinata 发出请求。

然后我们有我们的异步函数 pinJSONToIPFS,它将 JSONBody 作为其输入,并将 Pinata api 密钥和密钥放在其标头中,所有这些都是为了向他们的 pinJSONToIPFS API 发出 POST 请求。

  • 如果此 POST 请求成功,则我们的函数将返回一个 JSON 对象,其中 success 布尔值为 true,pinataUrl 为固定元数据的位置。 我们将使用返回的此 pinataUrl 作为我们智能合约的 mint 函数的 tokenURI 输入。

  • 如果此 post 请求失败,则我们的函数将返回一个 JSON 对象,其中 success 布尔值为 false,message 字符串传递我们的错误。

与我们的 connectWallet 函数返回类型一样,我们返回 JSON 对象,以便我们可以使用它们的参数来更新我们的状态变量和 UI。

步骤 7:加载你的智能合约

既然我们可以通过我们的 pinJSONToIPFS 函数将我们的 NFT 元数据上传到 IPFS,我们需要一种方法来加载我们的智能合约的实例,以便我们可以调用它的 mintNFT 函数。

正如我们之前提到的,在本教程中,我们将使用 此现有的 NFT 智能合约; 但是,如果你想了解我们是如何制作它的,或者自己制作一个,我们强烈建议你查看我们的另一个教程,“如何创建 NFT”。

合约 ABI

如果你仔细检查我们的文件,你会注意到在我们的 src 目录中,有一个 contract-abi.json 文件。 ABI 对于指定合约将调用的哪个函数以及确保该函数将以你期望的格式返回数据是必需的。

我们还需要一个炼金术 API 密钥和炼金术 Web3 API 来连接到以太坊区块链并加载我们的智能合约。

创建你的 Alchemy API 密钥

如果你还没有 Alchemy 帐户,请在此处 免费注册

创建 Alchemy 帐户后,你可以通过创建一个应用程序来生成 API 密钥。 这将允许我们向 Ropsten 测试网络发出请求。

通过将鼠标悬停在导航栏中的“应用程序”上并单击“创建应用程序”,导航到你的 Alchemy 仪表板中的“创建应用程序”页面

创建一个新应用程序创建一个新应用程序

为你的应用程序命名(我们选择了“My First NFT!”),提供一个简短的描述,为环境选择“分期”(用于你的应用程序记账),并为你的网络选择“Ropsten”。

配置你的应用程序详细信息配置你的应用程序详细信息

单击“创建应用程序”,就这样! 你的应用程序应该出现在下面的表格中。

太棒了,现在我们已经创建了我们的 HTTP Alchemy API URL,像这样将其复制到你的剪贴板……

复制你的 Alchemy API 密钥复制你的 Alchemy API 密钥

……然后让我们将其添加到我们的 .env 文件中。 总而言之,你的 .env 文件应如下所示:

已复制

REACT_APP_PINATA_KEY = REACT_APP_PINATA_SECRET = REACT_APP_ALCHEMY_KEY = https://eth-ropsten.alchemyapi.io/v2/

现在我们有了我们的合约 ABI 和我们的 Alchemy API 密钥,我们准备好使用 Alchemy Web3 加载我们的智能合约。

设置你的 Alchemy Web3 端点和合约

首先,如果你还没有安装 Alchemy Web3,你需要通过导航到主目录来安装它:终端中的 nft-minter-tutorial

已复制

cd .. npm install @alch/alchemy-web3

接下来让我们回到我们的 interact.js 文件。在文件的顶部,添加以下代码以从你的 .env 文件中导入你的 Alchemy 密钥并设置你的 Alchemy Web3 端点:

已复制

require('dotenv').config(); const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY; const { createAlchemyWeb3 } = require("@alch/alchemy-web3"); const web3 = createAlchemyWeb3(alchemyKey);

Alchemy Web3Web3.js 的一个包装器,它提供了增强的 API 方法和其他关键优势,使你作为 web3 开发人员的生活更轻松。 它旨在需要最少的配置,因此你可以立即开始在你的应用程序中使用它!

接下来,让我们将我们的合约 ABI 和合约地址添加到我们的文件中。

已复制

require('dotenv').config(); const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY; const { createAlchemyWeb3 } = require("@alch/alchemy-web3"); const web3 = createAlchemyWeb3(alchemyKey); const contractABI = require('../contract-abi.json') const contractAddress = "0x4C4a07F737Bf57F6632B6CAB089B78f62385aCaE";

一旦我们有了这两个,我们就准备好开始编写我们的 mint 函数了!

步骤 8:实现 mintNFT 函数

在你的 interact.js 文件中,让我们定义我们的函数 mintNFT,它将以同名方式铸造我们的 NFT。

因为我们将进行大量的异步调用(到 Pinata 以将我们的元数据固定到 IPFS,Alchemy Web3 以加载我们的智能合约,以及 Metamask 以签署我们的交易),我们的函数也将是异步的。``` export const mintNFT = async(url, name, description) => { //error handling // 错误处理 if (url.trim() == "" || (name.trim() == "" || description.trim() == "")) {         return {             success: false,             status: "❗Please make sure all fields are completed before minting.", // ❗请确保在铸造之前完成所有字段。         } }

//make metadata // 创建元数据 const metadata = new Object(); metadata.name = name; metadata.image = url; metadata.description = description;

//make pinata call // 发起Pinata调用 const pinataResponse = await pinJSONToIPFS(metadata); if (!pinataResponse.success) {       return {           success: false,           status: "😢 Something went wrong while uploading your tokenURI.", // 😢 上传你的tokenURI时出错。       } } const tokenURI = pinataResponse.pinataUrl; }


请注意,我们将调用 `pinJSONToIPFS(metadata)` 的响应存储在 `pinataResponse` 对象中。然后,我们解析此对象以查找任何错误。

如果存在错误,我们将返回一个 JSON 对象,其中 `success` 布尔值为 false,并且我们的 `status` 字符串传达我们的调用失败。否则,我们从 `pinataResponse` 中提取 `pinataURL` 并将其存储为我们的 `tokenURIvariable`。

现在是时候使用我们在文件顶部初始化的 Alchemy Web3 API 加载我们的智能合约了。将以下代码行添加到 `mintNFT` 函数的底部,以在 `window.contract` 全局变量处设置合约:

window.contract = await new web3.eth.Contract(contractABI, contractAddress);


最后要添加到我们的 `mintNFT` 函数中的是我们的以太坊交易:

//set up your Ethereum transaction // 设置你的以太坊交易 const transactionParameters = {         to: contractAddress, // Required except during contract publications. // 除了合约发布期间,其他时候都需要。         from: window.ethereum.selectedAddress, // must match user's active address. // 必须与用户的活动地址匹配。         'data': window.contract.methods.mintNFT(window.ethereum.selectedAddress, tokenURI).encodeABI()//make call to NFT smart contract // 调用NFT智能合约 };

//sign the transaction via Metamask // 通过Metamask签署交易 try {     const txHash = await window.ethereum         .request({             method: 'eth_sendTransaction',             params: [transactionParameters],         });     return {         success: true,         status: "✅ Check out your transaction on Etherscan: https://ropsten.etherscan.io/tx/" + txHash // ✅ 在Etherscan上查看你的交易:https://ropsten.etherscan.io/tx/     } } catch (error) {     return {         success: false,         status: "😥 Something went wrong: " + error.message // 😥 出了点问题:" + error.message     } }


如果你已经熟悉以太坊交易,你会注意到该结构与你所见过的非常相似。

首先,我们设置我们的交易参数。

- `to` 指定接收者地址(我们的智能合约)

- `from` 指定交易的签名者(用户连接到 Metamask 的地址: `window.ethereum.selectedAddress` `)`

- `data` 包含对我们的智能合约 `mintNFT` 方法的调用,该方法接收我们的 `tokenURI` 和用户的钱包地址 `window.ethereum.selectedAddress` 作为输入

然后,我们进行一个等待调用 `window.ethereum.request`,我们在此处要求 Metamask 签署交易。请注意,在此请求中,我们指定了我们的 eth 方法 ( `eth_SentTransaction` ) 并传入我们的 `transactionParameters`。此时,Metamask 将在浏览器中打开,并提示用户签署或拒绝交易。

- 如果交易成功,该函数将返回一个 JSON 对象,其中布尔值 `success` 设置为 true,并且 `status` 字符串提示用户查看 Etherscan 以获取有关其交易的更多信息。

- 如果交易失败,该函数将返回一个 JSON 对象,其中布尔值 `success` 设置为 false,并且 `status` 字符串传递错误消息。

总而言之,我们的 `mintNFT` 函数应该如下所示:

export const mintNFT = async(url, name, description) => {

    //error handling // 错误处理     if (url.trim() == "" || (name.trim() == "" || description.trim() == "")) {         return {             success: false,             status: "❗Please make sure all fields are completed before minting.", // ❗请确保在铸造之前完成所有字段。         }     }

    //make metadata // 创建元数据     const metadata = new Object();     metadata.name = name;     metadata.image = url;     metadata.description = description;     //pinata pin request // pinata pin请求     const pinataResponse = await pinJSONToIPFS(metadata);     if (!pinataResponse.success) {         return {             success: false,             status: "😢 Something went wrong while uploading your tokenURI.", // 😢 上传你的tokenURI时出错。         }     }     const tokenURI = pinataResponse.pinataUrl;     //load smart contract // 加载智能合约     window.contract = await new web3.eth.Contract(contractABI, contractAddress);//loadContract();     //set up your Ethereum transaction // 设置你的以太坊交易     const transactionParameters = {         to: contractAddress, // Required except during contract publications. // 除了合约发布期间,其他时候都需要。         from: window.ethereum.selectedAddress, // must match user's active address. // 必须与用户的活动地址匹配。         'data': window.contract.methods.mintNFT(window.ethereum.selectedAddress, tokenURI).encodeABI() //make call to NFT smart contract // 调用NFT智能合约     };

    //sign transaction via Metamask // 通过Metamask签署交易     try {         const txHash = await window.ethereum             .request({                 method: 'eth_sendTransaction',                 params: [transactionParameters],             });         return {             success: true,             status: "✅ Check out your transaction on Etherscan: https://ropsten.etherscan.io/tx/" + txHash // ✅ 在Etherscan上查看你的交易:https://ropsten.etherscan.io/tx/         }     } catch (error) {         return {             success: false,             status: "😥 Something went wrong: " + error.message // 😥 出了点问题:" + error.message         }     } }


这是一个巨大的功能!现在,我们只需要将我们的 `mintNFT` 函数连接到我们的 **Minter.js** 组件...

### 第 9 步:将 mintNFT 连接到我们的 Minter.js 前端

打开你的 **Minter.js** 文件并更新顶部的 `import { connectWallet } from "./utils/interact.js"`; 行,如下所示:

 import { connectWallet, mintNFT } from "./utils/interact.js";


最后,实现 `onMintPressed` 函数以对你导入的 `mintNFT` 函数进行等待调用,并更新 `status` 状态变量以反映我们的交易是成功还是失败:

const onMintPressed = async () => {     const { status } = await mintNFT(url, name, description);     setStatus(status); };



### 第 10 步:将你的 NFT 部署到实时网站

准备好让你的项目上线供用户交互了吗?查看此 [教程](https://app.gitbook.com/@alchemyapi/s/alchemy/tutorials/nft-minter/how-do-i-deploy-nfts-online) 以将你的 Minter 部署到实时网站:

### 第 11 步:以迅雷不及掩耳之势席卷区块链世界🚀

开个玩笑,你已经到了本教程的结尾!回顾一下,通过构建 NFT minter,你成功地学习了如何:

- 通过你的前端项目连接到 Metamask

- 从你的前端调用智能合约方法

- 使用 Metamask 签署交易

据推测,你希望能够在你的钱包中炫耀通过你的 dApp 铸造的 NFT - 因此请务必查看我们的快速教程 [如何在你的钱包中查看你的 NFT](https://docs.alchemyapi.io/alchemy/tutorials/how-to-write-and-deploy-a-nft-smart-contract/how-to-view-your-nft-in-your-wallet) !

而且,与往常一样,如果你有任何问题,我们随时在 [Alchemy Discord](https://discord.gg/gWuC7zB) 中提供帮助。我们迫不及待地想看看你如何将本教程中的概念应用于你未来的项目! 🧙‍♂️

Supercharged \| Alchemy \| Substack

[![Logo](https://img.learnblockchain.cn/2025/04/16/2F334f063b-8255-4cbb-8e4e-16b791a7c89e_400x400.png)](https://alchemysupercharged.substack.com/)

## Supercharged

web3 领先的开发者平台的最新消息

作者:Alchemy
· 超过 110,000 名订阅者

订阅

通过订阅,你同意 [Substack 的使用条款](https://alchemysupercharged.substack.com/tos?utm_source=embed_publication)、[我们的隐私政策](https://alchemysupercharged.substack.com/privacy?utm_source=embed_publication) 和 [我们的信息收集通知](https://substack.com/ccpa?utm_source=embed_publication#personal-data-collected)

[![Substack](https://img.learnblockchain.cn/2025/04/16/2Fsubstack.com2Fimg2Fsubstack_wordmark.black.png)](https://substack.com/?utm_source=embed&utm_content=alchemysupercharged)

使用 Alchemy 的 NFT API 免费开始构建你可以想象的任何 NFT 应用程序 [获取你的 API 密钥](https://dashboard.alchemy.com/signup/?a=blog%252Fnft-minter-tutorial-how-to-create-a-full-stack-dapp)

📚 目录

* * *

- 第 0 步:NFT 101 制作
- 第 1 步:克隆启动器文件
- 第 2 步:查看我们的启动器文件
- 第 3 步:设置你的以太坊钱包
- 第 4 步:将 Metamask 连接到你的 UI
- 第 5 步:NFT 元数据 101
- 第 6 步:使用 Pinata 将你的元数据固定到 IPFS
- 第 7 步:加载你的智能合约
- 第 8 步:实现 mintNFT 函数
- 第 9 步:将 mintNFT 连接到我们的 Minter.js 前端
- 第 10 步:将你的 NFT 部署到实时网站
- 第 11 步:以迅雷不及掩耳之势席卷区块链世界🚀

分享:

![Blog post page related articles background](https://img.learnblockchain.cn/2025/04/16/related-articles-background.svg)![Decorative ethereum logo](https://img.learnblockchain.cn/2025/04/16/eth-tilted.svg)![Decorative cube graphic](https://img.learnblockchain.cn/2025/04/16/light-cube.svg)

### 相关文章

[![Spearmint, the Free and Automated Allowlist Platform thumbnail](https://img.learnblockchain.cn/2025/04/16/69963100_image.jpg)\\
\\
NFTs\\
\\
**Spearmint, the Free and Automated Allowlist Platform** \\
\\
使用 Spearmint(免费的自动化允许列表平台)提升你的 NFT 游戏体验。管理 NFT 铸造、培养社区参与度并避免代价高昂的 Gas 战争。](https://www.alchemy.com/blog/spearmint) [![TheFungiNFT Partners with Alchemy to Leverage NFT Drops for Social Good thumbnail](https://img.learnblockchain.cn/2025/04/16/49570701_image.jpg)\\
\\
NFTs\\
\\
**TheFungiNFT Partners with Alchemy to Leverage NFT Drops for Social Good** \\
\\
TheFungiNFT 与 Alchemy 合作,进行有影响力的 NFT 投放,并帮助提高人们对心理健康的认识。](https://www.alchemy.com/blog/thefunginft-partner-with-alchemy-to-leverage-nft) [![Your Guide to ERC-1155: Comparing ERC-721 to ERC-1155 thumbnail](https://img.learnblockchain.cn/2025/04/16/83077686_image.jpg)\\
\\
NFTs\\
\\
**Your Guide to ERC-1155: Comparing ERC-721 to ERC-1155** \\
\\
了解 ERC-1155 代币标准并比较 ERC-721 与 ERC-1155,以便你可以了解差异以及何时使用每种标准。](https://learnblockchain.cn/article/12903)

![Desktop section background image](https://img.learnblockchain.cn/2025/04/16/91032210_image.jpg)

### 构建区块链魔法

Alchemy 将最强大的 web3 开发者产品和工具与资源、社区和传奇支持相结合。

[获取你的 API 密钥](https://dashboard.alchemy.com/signup/?a=blog%252Fnft-minter-tutorial-how-to-create-a-full-stack-dapp)

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

0 条评论

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