以太坊NFT部署的详细步骤
准备工作
在开始部署以太坊 NFT 之前,务必做好以下详尽的准备工作,确保流程顺利进行:
- MetaMask 钱包: MetaMask 是一款功能强大的浏览器扩展程序,作为你与以太坊区块链进行交互的桥梁。它不仅允许你管理你的以太坊地址,还允许你授权智能合约调用,并查看账户余额。你需要安装 MetaMask 并创建一个新的钱包,务必妥善保管你的助记词(Seed Phrase),它是恢复你钱包的唯一方式。确保你的钱包中拥有足够的 ETH,用于支付部署智能合约以及后续 NFT 铸造、转移等交易所需的 gas 费用。Gas 费用是执行以太坊交易所需的计算资源成本。
- 开发环境: 一个完善的开发环境是成功部署 NFT 的基础。你需要一个代码编辑器,例如 Visual Studio Code (VS Code),它具有丰富的插件和强大的调试功能。同时,Node.js 和 npm (Node 包管理器) 也是必不可少的。Node.js 是一个 JavaScript 运行时环境,允许你在服务器端运行 JavaScript 代码,而 npm 则用于安装和管理项目依赖的各种软件包。
- Solidity 编译器: Solidity 是一种专门为编写智能合约而设计的编程语言,类似于 JavaScript 或 Python,但更侧重于安全性和确定性。你需要安装 Solidity 编译器 (solc) 将你的 Solidity 源代码编译成以太坊虚拟机(EVM)可以理解的字节码。字节码是部署到以太坊区块链上的实际代码。你可以通过 npm 全局安装 solc,或者使用 Hardhat 或 Truffle 等开发框架提供的内置编译器。
- Hardhat 或 Truffle: Hardhat 和 Truffle 是目前最流行的以太坊开发框架,它们提供了一系列工具和功能,极大地简化了智能合约的开发、测试和部署流程。这些框架可以自动处理智能合约的编译、部署、测试和验证,并且集成了许多有用的插件,例如 gas 报告、代码覆盖率等。选择一个你最喜欢的框架并安装。Hardhat 以其速度、灵活性和强大的插件生态系统而闻名。Truffle 则拥有更长的历史和更成熟的社区支持。本文将以 Hardhat 为例,详细介绍如何部署 NFT 智能合约。
使用 Hardhat 创建项目
-
创建项目目录:
在你的终端中创建一个新的项目目录,作为你 NFT 项目的根目录。该目录将包含所有的智能合约代码、测试脚本、部署脚本和配置文件。
bash mkdir my-nft-project cd my-nft-project
-
初始化 Hardhat 项目:
使用 npm 初始化 Hardhat 项目。这将创建一个 `package.` 文件并安装 Hardhat 作为开发依赖项。
bash npm init -y npm install --save-dev hardhat npx hardhat
在运行
npx hardhat
后,Hardhat 会提示你选择项目类型。选择 "Create a basic sample project"。 Hardhat 将生成一个示例项目,包含一个示例合约、测试和部署脚本,为你提供一个良好的起点。 Hardhat还会生成一个 `hardhat.config.js` 配置文件,用于配置 Hardhat 环境,例如 Solidity 编译器版本、网络配置和测试设置。 可以根据项目需求修改此文件。 -
安装 OpenZeppelin 库:
OpenZeppelin 提供了一组安全的、经过审计的智能合约,可以帮助你快速构建 NFT 合约。这些合约实现了 ERC721 标准,并包含了许多有用的功能,如权限管理、元数据管理和 Gas 优化。通过安装 OpenZeppelin 的 ERC721 合约,可以避免从零开始编写复杂的智能合约,从而节省时间和精力,并降低安全风险。
bash npm install @openzeppelin/contracts
编写 NFT 合约
在
contracts
目录下创建一个名为
MyNFT.sol
的文件,并编写以下 Solidity 代码。该合约将实现一个基本的 ERC721 非同质化代币 (NFT) 合约,允许用户铸造和管理 NFT。
solidity // 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/utils/Strings.sol";
contract MyNFT is ERC721 { using Counters for Counters.Counter; Counters.Counter private _tokenIds;
string public baseURI;
constructor(string memory _name, string memory _symbol, string memory _baseURI) ERC721(_name, _symbol) {
baseURI = _baseURI;
}
function setBaseURI(string memory _baseURI) public {
baseURI = _baseURI;
}
function mintNFT(address recipient) public returns (uint256) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(recipient, newItemId);
_setTokenURI(newItemId, string(abi.encodePacked(baseURI, Strings.toString(newItemId), ".")));
return newItemId;
}
function tokenURI(uint256 tokenId) public view override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
return string(abi.encodePacked(baseURI, Strings.toString(tokenId), "."));
}
}
该合约继承自 OpenZeppelin 库的
ERC721
合约,这是一个广泛使用且经过审计的标准,用于在以太坊区块链上创建 NFT。它还使用
Counters
实用程序来安全地跟踪 NFT 的 ID。
Strings
库用于将 uint256 数字转换为字符串,以便构造 tokenURI。
这个合约包含以下关键功能:
-
baseURI
: 存储 NFT 元数据的基础 URI。例如,https://example.com/metadata/
。该 URI 用于构建每个 NFT 的完整元数据 URI。 元数据 URI通常指向存储有关 NFT 的信息的JSON文件,例如图像,描述和属性。 -
constructor
: 构造函数用于初始化合约。它接受 NFT 的名称,符号和 baseURI 作为参数。 这些参数在合约部署时设置。 -
setBaseURI
: 允许所有者更改baseURI
。 这对于更新元数据的位置非常有用。 只有合约所有者才能调用此功能。 -
mintNFT
: 铸造新的 NFT,并将 NFT 的元数据 URI 设置为baseURI + tokenId + "."
。该函数增加内部计数器_tokenIds
,并将新的 NFT 分配给指定的recipient
地址。 tokenURI 使用 baseURI 和 token ID 构建。 -
tokenURI
: 返回指定 NFT 的元数据 URI。它需要一个tokenId
作为参数,并返回一个字符串,该字符串表示 NFT 的元数据 URI。tokenURI
函数是ERC721
标准的一部分,允许应用程序检索有关特定 NFT 的元数据。
请注意,对
_setTokenURI
的调用将元数据 URI 设置为以 "." 结尾。这是标准做法,因为元数据通常以 JSON 格式存储。确保你的元数据文件按照此约定命名。
该合约中使用的 OpenZeppelin 库提供了安全且经过良好测试的智能合约构建块。使用这些库有助于降低漏洞风险并加速开发过程。 始终查阅 OpenZeppelin 文档以获取有关其库的更多信息。
编写部署脚本
为了自动化智能合约的部署流程,在项目的
scripts
目录下创建一个名为
deploy.js
的 JavaScript 文件。这个脚本将使用 Hardhat 提供的 ethers.js 库来连接到以太坊网络,编译合约,并将其部署到链上。
以下是在
deploy.js
文件中需要编写的 JavaScript 代码:
async function main() {
// 获取合约工厂,MyNFT是合约的名称。Hardhat会自动编译合约并生成对应的工厂。
const MyNFT = await ethers.getContractFactory("MyNFT");
// 部署合约。构造函数参数依次为:合约名称(name),代币符号(symbol),和基础URI(base URI)。
// 请务必替换为你的NFT合约的实际名称、符号和元数据URI前缀。
const myNFT = await MyNFT.deploy("MyNFTToken", "MNT", "https://example.com/metadata/");
// 等待合约完成部署。这会确保合约已经被矿工确认,并且在链上可用。
await myNFT.deployed();
// 在控制台输出合约的部署地址。这个地址是与合约交互的关键。
console.log("MyNFT deployed to:", myNFT.address);
}
// 调用main函数来执行部署。
main()
.then(() => process.exit(0)) // 成功部署后退出进程。
.catch((error) => { // 如果部署过程中发生错误,则打印错误信息并退出进程。
console.error(error);
process.exit(1);
});
在部署脚本中,务必根据你的 NFT 项目的需求,替换代码中的占位符。
MyNFTToken
应该替换为你希望的 NFT 合约名称,例如 "AwesomeCollectible"。
MNT
应该替换为你希望的代币符号,例如 "AWSM"。
https://example.com/metadata/
应该替换为你的元数据基础 URI,该 URI 指向存储 NFT 元数据的服务器。例如,如果每个 NFT 的元数据存储在
https://example.com/metadata/1.
,
https://example.com/metadata/2.
等位置,那么基础 URI 应该设置为
https://example.com/metadata/
。确保 URI 的格式正确,以便客户端可以正确检索 NFT 的元数据。
配置 Hardhat
为了成功部署智能合约并与之交互,你需要配置 Hardhat 以连接到以太坊网络。这涉及修改
hardhat.config.js
文件,提供必要的网络参数,包括你的MetaMask或其他钱包的私钥以及以太坊网络的RPC URL。 请务必安全地存储您的私钥,例如使用环境变量,避免直接在代码中暴露敏感信息。
hardhat.config.js
文件是 Hardhat 项目的核心配置文件,它定义了编译器版本、网络设置、部署脚本和其他重要的配置选项。
以下是一个示例
hardhat.config.js
文件,展示了如何配置 Goerli 测试网络:
require("@nomicfoundation/hardhat-toolbox");
require('dotenv').config();
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: "0.8.9",
networks: {
goerli: {
url: process.env.GOERLI_RPC_URL || "", // Goerli RPC URL
accounts: [process.env.PRIVATE_KEY || ""], // 你的私钥
gasPrice: 2000000000, // 可选:设置 gas price,单位 wei
gasLimit: 6000000, // 可选:设置 gas limit
},
},
gasReporter: {
enabled: process.env.REPORT_GAS ? true : false, // 根据环境变量决定是否启用 gas 报告
currency: 'USD',
gasPrice: 30, // gasPrice in gwei
coinmarketcap: process.env.COINMARKETCAP_API_KEY, // CoinMarketCap API 密钥 (用于获取美元汇率)
},
};
配置说明:
-
require("@nomicfoundation/hardhat-toolbox")
: 引入 Hardhat 工具箱,提供编译、测试、部署等功能。 -
require('dotenv').config()
: 使用 dotenv 加载环境变量。 -
solidity: "0.8.9"
: 指定用于编译智能合约的 Solidity 编译器版本。确保选择与你的合约代码兼容的版本。 -
networks
: 定义 Hardhat 连接的网络。在这个例子中,我们配置了 Goerli 测试网络。 -
goerli
: Goerli 网络的配置。你需要替换以下占位符:-
url: process.env.GOERLI_RPC_URL || ""
: 将GOERLI_RPC_URL
替换为你的 Goerli 网络 RPC URL。你可以从 Alchemy, Infura 或其他提供商处获取。使用环境变量存储 RPC URL 是一个好习惯,可以提高安全性。 -
accounts: [process.env.PRIVATE_KEY || ""]
: 将PRIVATE_KEY
替换为你的 MetaMask 钱包或其他钱包的私钥。 请务必谨慎处理私钥,不要将其暴露在公开场合或提交到版本控制系统中。 建议使用环境变量来存储私钥。 -
gasPrice: 2000000000
: (可选)设置 gas price,单位 wei。 根据网络拥堵情况调整。 -
gasLimit: 6000000
: (可选)设置 gas limit,限制单个交易可以消耗的最大 gas 量。
-
-
gasReporter
: Hardhat gas reporter插件的配置,用于分析智能合约部署和函数调用的 gas 消耗情况。-
enabled: process.env.REPORT_GAS ? true : false
: 是否启用 gas 报告。通常使用环境变量控制。 -
currency: 'USD'
: 报告中使用的货币单位。 -
gasPrice: 30
: gasPrice in gwei, 用于计算 gas 费用。 -
coinmarketcap: process.env.COINMARKETCAP_API_KEY
: CoinMarketCap API 密钥,用于获取加密货币的价格信息。
-
获取 RPC URL 和私钥:
- RPC URL: 你可以从诸如 Alchemy, Infura 等以太坊节点服务提供商处获取 Goerli 网络的 RPC URL。这些服务通常提供免费套餐,足以满足开发和测试需求。
- 私钥: 你的私钥存储在你的 MetaMask 钱包或其他钱包中。 切勿与任何人分享你的私钥。 导入账户时,小心钓鱼网站。
使用 .env 文件:
为了安全地管理你的私钥和 RPC URL,建议创建一个
.env
文件并将这些敏感信息存储在其中。 确保将
.env
文件添加到你的
.gitignore
文件中,以防止将其提交到版本控制系统。
示例
.env
文件:
PRIVATE_KEY=0xYOUR_PRIVATE_KEY
GOERLI_RPC_URL=YOUR_GOERLI_RPC_URL
COINMARKETCAP_API_KEY=YOUR_COINMARKETCAP_API_KEY
REPORT_GAS=true
配置完成后,你就可以使用 Hardhat 连接到 Goerli 网络并部署你的智能合约了。
警告: 请勿将你的私钥提交到版本控制系统中。建议使用环境变量来存储私钥。你可以创建一个.env
文件,并将你的私钥存储在其中:
PRIVATEKEY=YOURPRIVATEKEY GOERLIRPCURL=YOURGOERLIRPCURL
然后使用 dotenv
包来加载环境变量。
部署 NFT 合约
在完成智能合约的编写、编译和测试后,下一步是将NFT合约部署到区块链网络上。 此过程涉及使用部署脚本将编译后的合约字节码上传到指定的区块链网络,并创建一个可以在链上进行交互的合约实例。
部署步骤:
1.
配置 Hardhat 环境:
确保你已经正确配置了Hardhat开发环境,包括安装必要的依赖包(如
@nomiclabs/hardhat-ethers
,
@nomiclabs/hardhat-waffle
等),并配置了Hardhat配置文件 (
hardhat.config.js
) 中的网络参数,例如Goerli测试网的RPC URL和你的私钥。
2.
编写部署脚本:
创建或修改
scripts/deploy.js
文件。该脚本应包含以下逻辑:
-
导入必要的库 (
ethers
)。 -
使用
ethers.getContractFactory
获取合约的工厂实例。 -
调用合约工厂的
deploy
方法,传入构造函数所需的参数(如果有)。 -
使用
await
等待合约部署完成。 - 打印合约部署后的地址。
3. 执行部署命令: 在终端中使用以下命令来部署 NFT 合约:
bash
npx hardhat run scripts/deploy.js --network goerli
此命令会执行
scripts/deploy.js
脚本,并将合约部署到指定的网络。
npx
命令确保使用本地安装的 Hardhat 版本。
hardhat run
命令执行指定的脚本。
--network goerli
选项指定了要使用的网络。 请务必在
hardhat.config.js
文件中配置 Goerli 网络,包括提供一个具有足够 gas 费的账户的私钥。
4.
网络选择:
替换
goerli
为你想要部署的网络。 例如,如果要部署到以太坊主网,则将
goerli
替换为
mainnet
(如果已配置)。 如果部署到本地 Hardhat 网络,则使用
hardhat
。 确保在
hardhat.config.js
中配置了所选网络的相关参数,例如RPC URL和私钥。
5.
Gas 费用:
部署智能合约需要消耗 gas。 确保你的账户中有足够的 ETH 或目标网络的原生代币来支付 gas 费用。 可以通过在
hardhat.config.js
中配置 gasPrice 和 gasLimit 来控制 gas 费用。 部署到测试网络通常需要从 faucet 领取测试代币。
6. 合约地址: 部署成功后,终端会输出合约的地址。 请务必保存此地址,因为它用于与已部署的合约进行交互,例如调用合约方法和查询合约状态。
7. 验证合约 (可选): 部署到公共网络后,建议验证合约的源代码。 这允许其他人验证合约代码的真实性。可以使用 Etherscan 等区块链浏览器来验证合约。 Hardhat 提供了相应的插件来简化此过程。
验证合约 (可选)
为了提高透明度和可信度,建议在 Etherscan 或其他区块链浏览器上验证您的智能合约代码。验证后,任何人都可以查看合约的源代码,了解其具体逻辑和功能。这有助于建立社区信任,并允许其他开发者安全地与您的合约进行交互。要验证合约,您需要安装 Hardhat Etherscan 插件:
bash npm install --save-dev @nomiclabs/hardhat-etherscan
安装完成后,需要在
hardhat.config.js
文件中配置 Etherscan API 密钥。Etherscan API 密钥允许 Hardhat 插件与 Etherscan 的 API 进行通信,以便自动验证合约。您可以在 Etherscan 网站上注册并获取 API 密钥。请确保将 API 密钥存储在安全的地方,例如使用环境变量。
javascript require("@nomicfoundation/hardhat-toolbox"); require('dotenv').config(); // 导入 dotenv 以加载环境变量 require("@nomiclabs/hardhat-etherscan");
/** @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: "0.8.9", networks: { goerli: { url: process.env.GOERLI_RPC_URL || "", // 替换为您的 Goerli RPC URL,推荐使用环境变量 accounts: [process.env.PRIVATE_KEY || ""], // 替换为您的私钥,绝对不要直接在代码中暴露私钥!使用环境变量 }, }, etherscan: { apiKey: process.env.ETHERSCAN_API_KEY, // 替换为您的 Etherscan API 密钥,使用环境变量保护密钥 }, };
请注意,在配置网络时,强烈建议使用环境变量来存储敏感信息,如 Goerli RPC URL 和私钥。可以使用
dotenv
库将环境变量从
.env
文件加载到您的配置中。这可以防止您的私钥泄露,并使您的配置更易于管理。
完成配置后,您可以使用以下命令在终端中验证您的合约:
bash npx hardhat verify --network goerli DEPLOYED_CONTRACT_ADDRESS "MyNFTToken" "MNT" "https://example.com/metadata/"
请务必将
DEPLOYED_CONTRACT_ADDRESS
替换为您已部署的合约地址。另外,还需要将 "MyNFTToken"、"MNT" 和 "https://example.com/metadata/" 替换为您的合约构造函数参数。构造函数参数必须按照合约构造函数中定义的顺序提供。如果您的合约没有构造函数,则可以省略这些参数。
与 NFT 合约交互
与 NFT 合约的交互是理解和操作 NFT 的关键步骤。你可以利用多种工具来实现这一点,包括 Hardhat 控制台和 Etherscan 等以太坊交互平台。Hardhat 控制台提供了一个便捷的开发环境,可以直接在命令行中与合约进行互动。Etherscan 则允许你通过其用户友好的界面来读取合约状态、执行函数调用以及查看交易历史。
一个常见的交互示例是铸造(mint)新的 NFT。这意味着创建新的 NFT 实例并将其分配给特定的所有者。使用 Hardhat 控制台可以轻松完成此操作:
bash
npx hardhat console --network goerli
此命令启动 Hardhat 控制台,并连接到 Goerli 测试网络。Goerli 是一个常用的以太坊测试网络,用于在主网上部署之前测试合约和应用程序。请注意,在与主网合约交互时,应使用相应的网络配置。
在控制台中,你需要执行以下 JavaScript 代码来铸造 NFT:
javascript
const MyNFT = await ethers.getContractFactory("MyNFT");
const myNFT = await MyNFT.attach("YOUR_CONTRACT_ADDRESS"); // Replace with your contract address
const recipient = "YOUR_WALLET_ADDRESS"; // Replace with your wallet address
const tx = await myNFT.mintNFT(recipient);
await tx.wait();
console.log("Minted NFT with tokenId:", tx.events[0].args.tokenId.toNumber());
这段代码首先获取 `MyNFT` 合约的工厂实例。然后,它使用 `attach` 函数将合约实例连接到已部署的合约地址。 `recipient` 变量指定了接收新铸造的 NFT 的钱包地址。 `mintNFT` 函数是合约中定义的用于铸造 NFT 的函数。调用此函数会创建一个新的 NFT 并将其所有权转移给指定的接收者。 `tx.wait()` 确保交易已完成并被确认。代码会打印出新铸造的 NFT 的 tokenId。
务必将
YOUR_CONTRACT_ADDRESS
替换为你部署的 NFT 合约的实际地址。此地址是合约在区块链上的唯一标识符。将
YOUR_WALLET_ADDRESS
替换为你希望将 NFT 铸造到的钱包地址。这通常是你自己的钱包地址,或者你想将 NFT 送给的另一个地址。tokenId 是一个唯一的标识符,用于区分合约中的每个 NFT。 `tx.events[0].args.tokenId.toNumber()` 从交易事件中提取tokenId,并将其转换为数字格式以便于显示。