随着 NFT 将区块链带入公众视野,现在是通过在以太坊区块链上发布您自己的 NFT(ERC-721 代币)来了解炒作的绝佳机会!
Alchemy 非常自豪能够为 NFT 领域的知名人士提供支持,包括 Makersplace(最近在佳士得创下了 6900 万美元的数字艺术品销售记录)、Dapper Labs(NBA Top Shot 和 Crypto Kitties 的创造者)、OpenSea(世界上最大的NFT 市场)、Zora、Super Rare、NFTfi、Foundation、Enjin、Origin Protocol、Immutable 等。
在本教程中,我们将介绍如何使用MetaMask、Solidity、Hardhat、Pinata和Alchemy在 Ropsten 测试网络上创建和部署 ERC-721 智能合约(如果您还不明白其中的任何含义,请不要担心——我们将解释它!)。
第 1 步:连接到以太坊网络
有很多方法可以向以太坊区块链发出请求,但为了方便起见,我们将在Alchemy上使用一个免费帐户,这是一个区块链开发者平台和 API,允许我们与以太坊链进行通信,而无需运行我们的自己的节点。
在本教程中,我们还将利用 Alchemy 的开发人员工具进行监控和分析,以了解我们智能合约部署的幕后情况。如果您还没有 Alchemy 帐户,可以在这里https://alchemy.com/signup/eth免费注册。
第 2 步:创建您的应用(和 API 密钥)
创建 Alchemy 帐户后,您可以通过创建应用程序来生成 API 密钥。这将允许我们向 Ropsten 测试网络发出请求。如果您想了解有关测试网络的更多信息,请查看指南https://docs.alchemyapi.io/guides/choosing-a-network。
- 将鼠标悬停在导航栏中的“应用程序”上并单击“创建应用程序”,导航到 Alchemy 仪表板中的“创建应用程序”页面
- 为您的应用命名(我们选择“我的第一个 NFT!”),提供简短描述,为环境选择“暂存”(用于您的应用记账),然后为您的网络选择“Ropsten”。
- 点击“创建应用程序”,就是这样!您的应用程序应显示在下表中。
第三步:创建以太坊账户(地址)
我们需要一个以太坊账户来发送和接收交易。在本教程中,我们将使用 MetaMask,这是浏览器中的一个虚拟钱包,用于管理您的以太坊账户地址。
您可以在此处https://metamask.io/download.html免费下载和创建 MetaMask 帐户。当您正在创建一个帐户时,或者如果您已经有一个帐户,请确保切换到右上角的“Ropsten 测试网络”(这样我们就不会处理真钱)。
第 4 步:从FAUCET中添加以太
为了将我们的智能合约部署到测试网络,我们需要一些假 ETH。要获得 ETH,您可以前往FaucETH并输入您的 Ropsten 账户地址,点击“请求资金”,然后在下拉列表中选择“Ethereum Testnet Ropsten”,最后再次点击“请求资金”按钮。不久之后,您应该会在您的 MetaMask 帐户中看到 ETH!
第 5 步:检查您的余额
为了仔细检查我们的余额,让我们使用Alchemy 的 composer tool发出一个eth_getBalance请求。这将返回我们钱包中的 ETH 数量。输入您的 MetaMask 帐户地址并单击“发送请求”后,您应该会看到如下响应:
注意:此结果以 wei 为单位,而不是 ETH。wei被用作以太的最小面额。wei 到 ETH 的转换是 1 eth = 10 18 wei。因此,如果我们将 0xde0b6b3a7640000 转换为十进制,我们得到 1 * 10 18 wei,即 1 ETH。
我们的假钱就在那里。
第六步:初始化我们的项目
首先,我们需要为我们的项目创建一个文件夹。导航到您的命令行并键入:
现在我们在项目文件夹中,我们将使用 npm init 来初始化项目。如果您还没有安装 npm,请按照https://docs.alchemyapi.io/alchemy/guides/alchemy-for-macs#1-install-nodejs-and-npm这些说明进行操作(我们还需要Node.js,所以也下载https://nodejs.org/en/download/吧!)。
您如何回答安装问题并不重要。以下是我们如何参考:
批准 package.json,我们就可以开始了!
第 7 步:安装Hardhat
Hardhat 是一个用于编译、部署、测试和调试以太坊软件的开发环境。在部署到实时链之前,它可以帮助开发人员在本地构建智能合约和 dApp。
在我们的 my-nft 项目中运行:
第 8 步:创建hardhat项目
在我们的项目文件夹中运行:
然后,您应该会看到一条欢迎消息和用于选择您想要执行的操作的选项。选择“创建一个空的 hardhat.config.js”:
这将为我们生成一个 hardhat.config.js 文件,我们将在其中指定项目的所有设置(在第 13 步中)。
第 9 步:添加项目文件夹
为了使我们的项目井井有条,我们将创建两个新文件夹。在命令行中导航到项目的根目录并键入:
-
contract/ 是我们保存 NFT 智能合约代码的地方
-
scripts/ 是我们保存脚本以部署和与我们的智能合约交互的地方
第 10 步:编写我们的合同
现在我们的环境已经建立,接下来是更令人兴奋的事情:编写我们的智能合约代码!
在您喜欢的编辑器中打开 my-nft 项目(我们喜欢VSCode)。智能合约是用一种称为 Solidity 的语言编写的,我们将使用它来编写 MyNFT.sol 智能合约。
-
导航到
contracts
文件夹并创建一个名为 MyNFT.sol 的新文件 -
下面是我们基于OpenZeppelin库的 ERC-721 实现的 NFT 智能合约代码。将以下内容复制并粘贴到您的 MyNFT.sol 文件中。
//Contract based on [https://docs.openzeppelin.com/contracts/3.x/erc721](https://docs.openzeppelin.com/contracts/3.x/erc721)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;import “@openzeppelin/contracts/token/ERC721/ERC721.sol”;
import “@openzeppelin/contracts/utils/Counters.sol”;
import “@openzeppelin/contracts/access/Ownable.sol”;
import “@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol”;contract MyNFT is ERC721URIStorage, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;constructor() ERC721(“MyNFT”, “NFT”) {}
function mintNFT(address recipient, string memory tokenURI)
public onlyOwner
returns (uint256)
{
_tokenIds.increment();uint256 newItemId = _tokenIds.current();
_mint(recipient, newItemId);
_setTokenURI(newItemId, tokenURI);return newItemId;
}
} -
因为我们从 OpenZeppelin 合约库继承类,所以在您的命令行运行
npm install @openzeppelin/contracts
将库安装到我们的文件夹中。
那么,这段代码究竟做了什么?让我们逐行分解它。
在我们的智能合约的顶部,我们导入了三个OpenZeppelin智能合约类:
-
@openzeppelin/contracts/token/ERC721/ERC721.sol 包含 ERC-721 标准的实现,我们的 NFT 智能合约将继承该标准。(要成为有效的 NFT,您的智能合约必须实现 ERC-721 标准的所有方法。)要了解有关继承的 ERC-721 功能的更多信息,请查看此处的接口定义。
-
@openzeppelin/contracts/utils/Counters.sol 提供了只能递增或递减 1 的计数器。我们的智能合约使用计数器来跟踪铸造的 NFT 总数,并在我们的新 NFT 上设置唯一 ID。(使用智能合约铸造的每个 NFT 都必须分配一个唯一 ID——这里我们的唯一 ID 仅由存在的 NFT 总数决定。例如,我们使用智能合约铸造的第一个 NFT 的 ID 为“1, “我们的第二个 NFT 的 ID 为“2”,等等)
-
@openzeppelin/contracts/access/Ownable.sol 对我们的智能合约设置访问控制,因此只有智能合约的所有者(您)可以铸造 NFT。(注意,包括访问控制完全是一种偏好。如果您希望任何人都能够使用您的智能合约铸造 NFT,请删除第 10 行的 Ownable 和第 17 行的 onlyOwner。)
在我们的 import 语句之后,我们有我们的自定义 NFT 智能合约,它非常短——它只包含一个计数器、一个构造函数和一个函数!这要归功于我们继承的 OpenZeppelin 合约,它实现了我们创建 NFT 所需的大部分方法,例如ownerOf
返回 NFT 的所有者,以及将 NFT 的transferFrom
所有权从一个账户转移到另一个账户。
在我们的 ERC-721 构造函数中,您会注意到我们传递了 2 个字符串,“MyNFT”和“NFT”。第一个变量是智能合约的名称,第二个是它的符号。您可以随意命名这些变量中的每一个!
最后,我们有了mintNFT(address recipient, string memory tokenURI)
可以铸造 NFT 的函数!你会注意到这个函数有两个变量:
-
address recipient
指定将接收您新铸造的 NFT 的地址 -
string memory tokenURI
是一个字符串,应该解析为描述 NFT 元数据的 JSON 文档。NFT 的元数据确实是让它栩栩如生的原因,它允许它具有可配置的属性,例如名称、描述、图像和其他属性。在本教程的第 2 部分中,我们将描述如何配置此元数据。
mintNFT
从继承的 ERC-721 库中调用一些方法,并最终返回一个数字,该数字表示新铸造的 NFT 的 ID。
第 11 步:将 METAMASK 和 ALCHEMY 连接到您的项目
现在我们已经创建了一个 MetaMask 钱包、Alchemy 帐户并编写了我们的智能合约,是时候连接这三者了。
从您的虚拟钱包发送的每笔交易都需要使用您唯一的私钥进行签名。为了向我们的程序提供此权限,我们可以将我们的私钥(和 Alchemy API 密钥)安全地存储在环境文件中。
首先,在你的项目目录中安装 dotenv 包:
然后,在我们项目的根目录中创建一个.env
文件,并将您的 MetaMask 私钥和 HTTP Alchemy API URL 添加到其中。
-
按照这些说明从 MetaMask 导出您的私钥
-
请参阅下文以获取 HTTP Alchemy API URL 并将其复制到剪贴板
你的.env
现在应该是这样的:
为了将这些实际连接到我们的代码,我们将在第 13 步的 hardhat.config.js https://hardhat.org/plugins/文件中引用这些变量。
.env
!请确保永远不要.env
与任何人共享或公开您的文件,因为这样做会泄露您的秘密。如果您使用版本控制,请将您.env
的添加到gitignore https://git-scm.com/docs/gitignore文件中。第 12 步:安装 ETHERS.JS
Ethers.js 是一个库,它通过使用更用户友好的方法包装标准 JSON-RPC 方法,使交互和向以太坊发出请求变得更加容易。
Hardhat 使集成插件变得非常容易,以获得额外的工具和扩展功能。我们将利用Ethers 插件进行合约部署(Ethers.js https://github.com/ethers-io/ethers.js/有一些超级干净的合约部署方法)。
在您的项目目录类型中:
在下一步中,我们还需要在我们的 hardhat.config.js 中使用 ethers。
第 13 步:更新 HARDHAT.CONFIG.JS
到目前为止,我们已经添加了几个依赖项和插件,现在我们需要更新 hardhat.config.js 以便我们的项目了解所有这些。
将您的 hardhat.config.js 更新为如下所示:
第 14 步:编译我们的合约
为了确保到目前为止一切正常,让我们编译我们的合约。编译任务是内置安全帽任务之一。
从命令行运行:
第 15 步:编写我们的部署脚本
现在我们的合约已经写好并且我们的配置文件已经准备好了,是时候编写我们的合约部署脚本了。
导航到scripts/
文件夹并创建一个名为 的新文件deploy.js
,向其中添加以下内容:
async function main() {
const MyNFT = await ethers.getContractFactory(“MyNFT”)
// Start deployment, returning a promise that resolves to a contract object
const myNFT = await MyNFT.deploy()
await myNFT.deployed()
console.log(“Contract deployed to address:”, myNFT.address)
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
Hardhat 在他们的合同教程中解释了每行代码的作用,我们在这里采用了他们的解释。
ethers.js 中的 ContractFactory 是用于部署新智能合约的抽象,因此这里的 MyNFT 是我们 NFT 合约实例的工厂。使用 hardhat-ethers 插件时,ContractFactory 和 Contract 实例默认连接到第一个签名者。
在 ContractFactory 上调用 deploy() 将启动部署,并返回解析为 Contract 的 Promise。这是为我们的每个智能合约功能提供方法的对象。
第 16 步:部署我们的合约
我们终于准备好部署我们的智能合约了!导航回项目目录的根目录,然后在命令行中运行:
然后,您应该会看到如下内容:
如果我们去Ropsten etherscan并搜索我们的合约地址,我们应该能够看到它已经成功部署。如果您无法立即看到它,请稍等片刻,因为它可能需要一些时间。交易将如下所示:
发件人地址应与您的 MetaMask 帐户地址匹配,收件人地址将显示“合同创建”。如果我们点击进入交易,我们将在 To 字段中看到我们的合约地址:
你刚刚将你的 NFT 智能合约部署到了以太坊链上!
要了解幕后发生的事情,让我们导航到Alchemy 仪表板中的 Explorer 选项卡。如果您有多个 Alchemy 应用程序,请确保按应用程序过滤并选择“MyNFT”。
在这里,您将看到当我们调用 .deploy() 函数时,Hardhat/Ethers 在后台为我们进行的一些 JSON-RPC 调用。这里要提到的两个重要的问题是eth_sendRawTransaction,它是实际将我们的智能合约写入 Ropsten 链的请求,以及eth_getTransactionByHash,它是在给定哈希的情况下读取我们交易信息的请求(发送交易时的典型模式)。