本文是一个全面的指南,教你如何在 Arbitrum Nova 上创建和部署一个 10,000 个 NFT 的集合。详细讲解了所需工具、设置开发环境、创建 NFT 合约、上传元数据到 IPFS,以及如何在 NFT 市场上铸造和展示这些 NFT,适合对区块链和 Solidity 有一定基础的人士阅读。
想要创建一个10,000个NFT的系列吗?本指南将带你踏上将你的10,000件NFT系列在Arbitrum Nova上实现的旅程。你将学习如何创建元数据,使用Hardhat部署NFT智能合约,以及铸造独特的代币以展示在像TofuNFT这样的知名NFT市场。
Arbitrum Nova是以太坊的二层扩展解决方案,旨在为去中心化应用提供超快且低廉的交易。它结合了AnyTrust技术和数据可用性委员会(DAC)来实现其目标,并且比Arbitrum One便宜得多。
AnyTrust是Arbitrum Nitro技术的一种变体,通过假设一定程度的信任来降低成本。AnyTrust利用第三方数据可用性委员会(DAC)来存储数据并根据请求提供。QuickNode作为领先的区块链服务提供商,被选为Arbitrum Nova的DAC委员会成员(与Google Cloud、Reddit和Consensys一起)。作为DAC成员,QuickNode运行数据可用性服务器,可以通过REST API按需提供交易批量数据。有关DAC的更多信息,请参见这篇QuickNode的博客文章。
Arbitrum Nova有多种用例,比如Web3游戏和社交基础设施,但在本指南中,我们将专门讨论NFT(非同质化代币)。这些独特的数字资产近年来变得越来越流行,有几个原因让人们希望在Arbitrum Nova上开发NFT:
这些优点对具有大量交易量的项目也非常有利,例如游戏开发、社交项目和去中心化金融(DeFi)。
如果你想了解更多关于Arbitrum Nova与Arbitrum One及其他区块链的优势,可以查看这篇QuickNode指南
你需要一个API端点来与Arbitrum Nova链进行通信。你可以使用公共节点或部署和管理自己的基础设施;然而,如果你想要8倍更快的响应时间,你可以把繁重的工作留给我们。请在这里注册一个免费账户。
登录后,点击创建端点,然后选择Arbitrum Nova主网链。
创建端点后,请保持HTTP提供者URL,以便在后面的指南中配置你的.env时使用。
在本指南中,我们将使用Torus Wallet,这是一个支持多个链和网络的非托管钱包,包括以太坊、Arbitrum One、Arbitrum Nova以及其他EVM相关链。请注意,为了在Arbitrum Nova主网上部署,你需要拥有实际资金(ETH)以覆盖交易费用。这些费用应该是微不足道的,并且不应超过$0.25。你可以在去中心化交易所如Uniswap上获取ETH,或在传统交易所如Coinbase上获得。你可以使用Arbitrum Nova Bridge将资金转移到Arbitrum Nova。
要开始,请访问Torus并按照说明生成私钥。
在进行本指南的技术方面之前,请确保你在Arbitrum Nova主网地址上有足够的资金来支付合约的部署和交易。如果你需要桥接资金,可以使用Arbitrum Nova bridge。
要使用Hardhat,你首先需要在计算机上安装Node.js。你可以从官方网站nodejs.org下载。
打开终端,检查Node.js是否已安装且版本在18以上:
node -v
导航到你想要创建项目的目录。对于本指南,我们将创建一个名为10k-collection的文件夹:
mkdir 10k-collection
进入刚刚创建的文件夹,然后使用以下命令初始化一个新的npm项目:
npm init -y
然后,通过运行以下命令安装Hardhat:
npm install --save-dev hardhat
--save-dev 将此项添加到package.json的devDependencies列表中
现在,我们通过运行以下命令初始化Hardhat项目:
npx hardhat create
当提示选择要创建的项目类型时,选择第三个选项(即,创建一个空的hardhat配置文件)。
这将创建一个具有默认Hardhat项目结构的新目录。接下来,我们需要为我们的10k-collection创建所需的文件夹。
mkdir contracts
mkdir test
mkdir scripts
在项目目录中,运行以下命令以安装项目所需的依赖项:
npm install dotenv @openzeppelin/contracts @nomicfoundation/hardhat-toolbox
为了保护你的私钥和RPC URL(如果你将代码发布到Github上),我们将创建一个.env文件来存储凭据。此文件在推送到Github时不应包含在内。
在你的主项目目录中,运行以下终端命令来创建.env文件:
echo > .env
打开文件并输入以下变量。然后,用你的实际凭据替换占位符值。记得保存文件!
RPC_URL=<YOUR_RPC_URL>
PRIVATE_KEY=<YOUR_PRIVATE_KEY>
接下来,我们将设置hardhat.config.js文件。打开文件并输入以下代码。
require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();
module.exports = {
solidity: "0.8.17",
networks: {
nova: {
url: process.env.RPC_URL,
accounts: [process.env.PRIVATE_KEY]
}
}
};
记得保存文件!在下一部分,我们将为我们的10K NFT系列创建图像和元数据。
在此部分中,我们将为10K NFT系列创建元数据。
具体来说,我们将使用Figma和这个Github 仓库来生成图像资产和元数据(感谢编写此内容的任何人!)。请注意,你可以使用其他工具来生成元数据,并且这并不是唯一的方法。
为了创建具有不同图像的10,000个NFT,你需要至少七个层和四个不同选项。查看这个Figma文件来查看示例。请注意,这个Figma文件只包含三个层,其他四个已经在我们使用的仓库中创建。或者,你也可以跳过此步骤,仅使用Github 仓库中的示例资产。
一旦你将图像资产导出到计算机上,克隆以下仓库并在首选代码编辑器中打开它。
git clone https://github.com/manuelpires/nft-collection-generator/
然后,使用以下命令安装所需的依赖项:
npm install
如果你在Mac OSX上运行,并且上述安装命令抛出错误,你可能需要先安装以下库:
brew install pkg-config cairo pango libpng jpeg giflib librsvg pixman
然后安装canvas:
npm i canvas
现在,创建两个文件夹metadata和images:
mkdir metadata && mkdir images
然后,进入traits目录并为每个层创建文件夹。在我们的示例中,我们为箭头、_圆_和_星_创建了文件夹。
注意:如果你只使用traits文件夹中已有的示例图像,请跳过此步骤,直接运行node index.js命令。
然后,打开config.js文件,将每个层添加到ORDERED_TRAITS_LIST对象中。示例代码将如下所示:
{
type: "Square",
options: [\
{\
image: "./traits/square/bright-coral.png",\
value: "Bright Coral",\
weight: 1,\
},\
{\
image: "./traits/square/liliac.png",\
value: "Liliac",\
weight: 1,\
},\
{\
image: "./traits/square/pumpkin.png",\
value: "Pumpkin",\
weight: 1,\
},\
{\
image: "./traits/square/spring.png",\
value: "Spring",\
weight: 1,\
},\
{\
weight: 1,\
},\
],
},
请注意,层是按顺序添加的,因此请注意你使用的顺序。weight选项与同一选项数组中的其他项目的权重相关,且至少应为1的整数。如果你在某个选项中设置了权重为10,则它被选中的概率应是同一数组中权重为1的选项的十倍。
一旦你用所有的元数据和图像引用设置好config.js,并且安装了所需的依赖项,通过运行命令生成元数据和图像:
node index.js
一旦生成了图像和元数据,请花几分钟的时间检查它们以确保按预期生成。一旦我们将图像和元数据上传到IPFS,我们需要替换基本URL为我们实际的元数据链接,因此请保留这个文件夹以备后用。
现在我们的元数据和图像已创建,我们需要将它们上传到IPFS,这是一个用于在分布式文件系统中存储和共享数据的协议、超媒体和文件共享点对点网络。我们将使用IPFS而非中心化存储解决方案(如Amazon),因为我们希望我们的NFT系列与其去中心化特性相符。然而,请注意,IPFS是免费使用的,但有时可能会很慢,你需要积极固定你的内容(即使你的IPFS节点保持运行)以便使元数据可检索。
另外,你还可以使用像Pinata(免费和付费版本)或NFT.Storage(免费但存储有限)等服务轻松将数据上传到IPFS,并确保你的内容被固定并能更快速地检索,但它们有存储限制且可能会收费。
无论如何,你需要将元数据上传到一个文件夹中,以便该目录中所有文件具有相同的根路径。
例如:
https://ipfs.io/ipfs/bafybeidhtkrvmboa4pel3i3asl57rgmrtai4zelpoeccfulw7qxqbhwyw4/metadata/
上述URL指向IPFS上的一个文件夹,其中包含NFT元数据的文件。你还可以在路径末尾添加一个数字(例如,/metadata/1)来查看每个单独NFT的元数据。重要的是,这些数据是标准化的,以便更容易地让应用程序展示和与你的NFT互动。
首先,我们将使用以下链接安装IPFS。你可以多种方式访问IPFS;但是,我们将通过Kubo二进制文件安装。
然后,打开一个新的终端窗口(Mac上为CMD + T),检查IPFS是否已安装:
ipfs --version
接下来,我们将启动将用于将内容固定到IPFS网络并保持持久运行的IPFS节点。
ipfs init
你应该会看到类似于以下内容的信息:
initializing ipfs node at /Users/user/.ipfs
> generating 2048-bit RSA keypair...done
> peer identity: Qmcpo2iLBikrdf1d6QU6vXuNb6P7hwrbNPW9kLAH8eG67z
> to get started, enter:
>
> ipfs cat /ipfs/QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG/readme
要使我们的IPFS节点上线,请运行以下命令:
ipfs daemon
注意守护程序正在侦听的TCP端口
然后,打开另一个终端窗口。如果你已连接到网络,你应该能够通过运行以下命令查看你的对等体的IPFS地址:
ipfs swarm peers
你可以通过运行以下命令测试你的IPFS是否可以从网络请求数据:
ipfs cat /ipfs/QmSgvgwxZGaBLqkGyWemEDqikCqU52XxsYLKtdy3vGZ8uq > ~/Desktop/spaceship-launch.jpg
如果你能够成功下载图像,那就太好了!我们现在可以将我们的图像和元数据上传到IPFS。
在你的项目根目录中,运行以下IPFS命令以固定图像文件夹:
ipfs add -r images/
输出的最后一行将显示根目录的CID,这是你上传的文件夹的顶级目录。你可以通过将CID添加到IPFS网关URL的末尾访问该文件夹“ https://ipfs.io/ipfs/”。
现在我们的图像已上传,从你的根images/文件夹获取CID哈希并返回到nft-collection-generator仓库。使用以下终端命令一次性替换所有占位符URL为你的实际图像URL:
find metadata -type f -exec perl -pi -e 's#https://base-uri-to-my-nft-images.com/#https://ipfs.io/ipfs/{CID}/#g' {} +
请记得将命令中的{CID}
替换为你上传的images/文件夹的IPFS CID哈希!
最后,你元数据文件中的内容应如下所示:
{
"tokenId": 0,
"name": "KT0",
"description": "KT Collection",
"image": "https://ipfs.io/ipfs/Qma5p2daHfdui4keZjMrJpgmL7JRjoZ6J5GcyLPUcmTTuT/0.png",
"attributes": [\
{\
"trait_type": "Background",\
"value": "Robin"\
},\
{\
"trait_type": "Square",\
"value": "Spring"\
},\
{\
"trait_type": "Triangle",\
"value": "Green"\
},\
{\
"trait_type": "Circle",\
"value": "Blue"\
},\
{\
"trait_type": "Arrows",\
"value": "Up"\
}\
]
}
接下来,我们需要将我们的元数据(JSON文件)打包为一个.CAR(内容寻址存档)文件。你可以使用ipfs car命令来完成此操作。
运行以下命令以创建包含JSON文件的CAR文件:
npx ipfs-car --pack metadata/
可能会要求你安装外部库
现在,我们将我们的JSON打包为.CAR文件后,使用以下命令将其固定到IPFS上:
ipfs dag import metadata.car
你应该会看到类似以下的信息响应:
Pinned root bafybeihzssbfdo6cmprolorfimhda4yapkzkyukffsteta6exwcr4nipzi success
你可以通过转到上传中引用的CID来检查元数据是否可访问。记得在URL的末尾加上/metadata/路径:
https://ipfs.io/ipfs/{CID}/metadata/
你还可以通过本地IPFS节点(守护程序)访问IPFS URL。根据网络状态,curl可能会由于公共网关过载或联系你困难而需要较长时间才能响应。要查看你本地网关上的对象,请尝试“ http://127.0.0.1:8080/ipfs/{CID}”。对于公共网关,使用https://ipfs.io/ipfs/{CID}。
注意,使用IPFS网关检查器来查看当前最快的网关。
在下一部分中,你将开发你的NFT合约!
在contracts目录中创建一个名为NFT.sol的新文件。
打开该文件,输入以下代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
// 创建10k个代币的合约,继承自ERC721和Ownable
contract KTokens is ERC721, Ownable {
// 最大供应量
uint256 public constant MAX_SUPPLY = 10000;
// 当前供应量
uint256 public totalSupply = 0;
// 使用Counters库来跟踪代币ID
using Counters for Counters.Counter;
// 私有变量以跟踪代币ID
Counters.Counter private _tokenIdCounter;
// 构造函数以初始化合约,名称为“10K Tokens”及符号为“10KT”
constructor() ERC721("10K Tokens", "10KT") {}
// 内部函数返回合约的基础URI
function _baseURI() internal pure override returns (string memory) {
return "https://ipfs.io/ipfs/{CID}/metadata/";
}
// 铸造新代币的函数,仅可由合约所有者调用
function safeMint(address to) public onlyOwner {
// 确保当前供应量小于最大供应量
require(totalSupply <= MAX_SUPPLY, "Maximum supply reached");
// 增加总供应量变量
totalSupply++;
// 获取当前代币ID
uint256 tokenId = _tokenIdCounter.current();
// 增加代币ID计数器
_tokenIdCounter.increment();
// 将代币铸造至指定地址
_safeMint(to, tokenId);
}
}
花点时间查看代码注释以更好地理解逻辑
在此处未显示的,但从ERC721.sol合约中继承的函数是 tokenURI。此只读函数接收一个_tokenId并返回指向该特定代币元数据的URL。
你需要将 _baseURI() 函数中的占位符( https://ipfs.io/ipfs/{CID})替换为你在上传元数据目录时获得的CID。这个CID或URL,如果你不使用IPFS,应指向你的元数据所在的目录。记得在继续下一步之前保存文件!
接下来,你需要编译NFT合约。这涉及将Solidity代码编译为字节码,字节码将在区块链上部署。
要编译合约,请运行以下Hardhat命令:
npx hardhat compile
你应该会看到类似的信息:
Compiled 13 Solidity files successfully
在下一部分中,我们将为NFT合约创建测试,以确保在向Arbitrum Nova主网部署时一切顺利。
在此部分中,我们将创建测试以检查我们的NFT合约的行为。对我们的NFT进行测试很重要,因为它让开发人员确保他们的智能合约按预期功能运行,并且在部署到区块链之前没有错误。这是至关重要的,因为一旦合约被部署,就无法修改或删除,因此任何错误或问题将是永久性的。此外,测试还有助于防止合约中的潜在安全漏洞,恶意行为者可以利用这些漏洞。
在tests目录中,创建一个名为NFT.js的文件,并输入以下代码:
const { expect } = require("chai");
describe("KTokens", () => {
let kTokens;
let owner;
beforeEach(async function () {
// 从ethers检索默认账户
[owner] = await ethers.getSigners();
// 一个帮助器获取合同实例并本地部署它
const KTokens = await ethers.getContractFactory("KTokens");
kTokens = await KTokens.deploy();
});
it("应具有正确的名称和符号", async () => {
expect(await kTokens.name()).to.equal("10K Tokens");
expect(await kTokens.symbol()).to.equal("10KT");
});
it("应能够铸造新代币", async () => {
// 铸造一个新代币
await kTokens.safeMint(owner.address);
expect(await kTokens.ownerOf(0)).to.equal(owner.address);
});
});
花点时间查看代码注释以更好地理解逻辑
要执行测试文件,运行以下命令:
npx hardhat test
你应该看到以下输出:
KTokens
✔ 应具有正确的名称和符号
✔ 应能够铸造新代币
2 passing (1s)
在下一部分中,我们将把10K NFT系列部署到Arbitrum Nova!
在你的scripts文件夹中,创建一个名为deploy.js的文件:
echo > scripts/deploy.js
然后,打开文件并输入以下代码:
const hre = require("hardhat");
async function deploy() {
// 部署合约
const NFT = await hre.ethers.getContractFactory("KTokens");
const nft = await NFT.deploy();
// 打印部署合约的地址
console.log("NFT contract deployed at:", nft.address);
}
deploy()
.then(() => console.log("Deployment complete"))
.catch((error) => console.error("Error deploying contract:", error));
该文件将包含所需的逻辑,以将我们的合约部署到Arbitrum Nova主网。
要部署合约,请在终端中运行以下hardhat命令:
npx hardhat run --network nova scripts/deploy.js
nova
对象是我们在hardhat.config.js中创建的对象
你应该会看到包含你部署合约地址的输出:
NFT contract deployed at: 0xf18802cb61EF336E30c5B93a7c9C961b1e80BeDE
Deployment complete
现在我们的NFT合约已部署,让我们铸造一个NFT并在NFT市场上查看它。为了本指南的目的,我们只铸造1个NFT,但你可以使用相同的过程铸造多个NFT。
在你的scripts文件夹中创建一个mint.js文件:
echo > scripts/mint.js
然后,打开文件并输入以下代码:
const hre = require("hardhat");
async function main() {
let owner;
// 从ethers检索默认账户
[owner] = await ethers.getSigners();
// 获取NFT合约的合约工厂
const NFT = await ethers.getContractFactory("KTokens");
// 在指定地址附加到已部署合约
const nft = await NFT.attach(
"DEPLOYED_CONTRACT_ADDRESS" // 你的已部署合约地址
);
// 调用safeMint函数以更新值
let safeMintTx = await nft.safeMint(owner.address)
console.log("safeMint函数调用。等待确认...")
// 等待3个区块以确认交易
await safeMintTx.wait(confirm=3);
// 获取最新的总供应量
let tokenSupply = (await nft.totalSupply()).toString()
// 减1,因为tokenID从零开始
let tokenIdInt = parseInt(tokenSupply) - 1
// 获取铸造的tokenID的拥有者
let tokenOwner = await nft.ownerOf(tokenIdInt);
console.log(`Token ID ${tokenIdInt} - tokenOwner ${tokenOwner}`)
}
// 启动脚本并处理任何错误
main()
.then(() => console.log("脚本完成"))
.catch((error) => console.error("运行脚本时出错:", error));
铸造后,你可以访问如tofuNFT.com的NFT市场,这是一个支持Arbitrum Nova的多链NFT市场,并输入你的钱包地址以查看NFT。
如果你对一次性铸造10,000个代币感兴趣,可以查看这篇如何使用ERC721A实现铸造NFT的指南。
现在你已在Arbitrum Nova上部署了首个智能合约,你可以探索Arbitrum Nova链提供的一些资源:
如果你希望继续学习关于Arbitrum Nova和智能合约的内容,请查看以下资源:
祝贺!你现在具备了部署10K NFT系列的技能!
你将在Arbitrum Nova上使用它做什么?我们很想知道你正在创造的内容!在Discord或Twitter上与我们分享你的应用。如果你对本指南有任何反馈或问题,我们很想听到你的想法!
- 原文链接: quicknode.com/guides/oth...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!