随着非同质化通证(NFT)日渐活跃,让更多的人了解到NFT,也让更多的项目甚至个人可以通过在Ethereum区块链上发布自己的非同质化通证(基于ERC-721协议)从而走进Web3.0的世界。
在本篇文章中,将着重介绍如何在Ethereum区块链上发布自己的基于ERC-721协议的非同质化通证。其中我们将涉及到 MetaMask(区块链钱包)、Solidity(智能合约语言)、Hardhat(以太坊软件的开发环境)、Alchemy(区块链开发平台)和Pinata(星际文件系统平台)的学习和使用。并在 Goerli 测试网络上创建和部署 ERC-721 智能合约的完整过程。
上一篇文章中通过一个具体的例子操作了Ethereum非同质化通证(NFT)的编写与部署。本篇文章将讲述如何通过这个智能合约铸造一个非同质化通证以及如何在以太坊钱包中显示出这个通证。
在上一篇文章中,已经使用到了 Ethers.js 这个库,这里的 Web3.js 与之类似,也是用于轻松创建对以太坊区块链请求的库。这里将使用到 Alchemy Web3.js,一个增强版 web3 库,提供自动重试和强大的 WebSocket 支持。
npm install @alch/alchemy-web3
require("dotenv").config()
const API_URL = process.env.API_URL
const { createAlchemyWeb3 } = require("@alch/alchemy-web3")
const web3 = createAlchemyWeb3(API_URL)
合约的 ABI(应用程序二进制接口)是与智能合约交互的接口。项目中使用的HARDHAT能自动生成应用程序的二进制接口,并将其保存在 NewNFT.json 文件中。为了使用该接口,需要通过在 mint-nft.js 文件中添加以下代码行来解析内容:
const contract = require("../artifacts/contracts/NewNFT.sol/NewNFT.json")
console.log(JSON.stringify(contract.abi)) //将应用程序二进制接口发送到控制台以便查看
在项目终端中运行,即可查看发送到控制台的应用程序二进制接口:
node scripts/mint-nft.js
在上一篇文章中,提到了 mintNFT 智能合约函数包含有一个 tokenURI 参数,该参数应解析为描述非同质化通证元数据的 JSON 文档,它是非同质化通证的核心,赋予非同质化通证可配置的属性,如名称、描述、图像和其他属性。这里将要使用到IPFS来存储配置这些元数据。IPFS是一个去中心化的存储网络,用于在分布式文件系统中存储和共享数据。
前言中提到的 将来完成这部分工作,这是一个非常方便的 IPFS 应用程序接口和工具包,用于存储非同质化通证资产和元数据,以确保非同质化通证真正的去中心化。
登录 Pinata 后,点击 Upload 选择 File ,在弹出层中点击 Select a file ,然后在 Name 中输入文件的名字,再点击 Upload 完成上传。
{
"attributes": [
{
"trait_type": "Breed",
"value": "Ape"
},
{
"trait_type": "Eye",
"value": "Glasses"
},
{
"trait_type": "Face",
"value": "Smiled"
}
],
"description": "Very powerful programmer ape.",
"image": "ipfs://QmXectapuW3yBCWwgjf78h3Dqdo2zpD5qaq4zXb63qXbp9",
"name": "Caesar"
}
这个文件是非同质化通证的灵魂所在,其中的 JSON 数据可随意修改。这个例子中定义了非同质化通证中Breed、Eye、Face这几个属性,可以删除或添加相应的属性内容。最重要的是,确保 image 字段指向 IPFS 中的 CID。编辑完成之后以同样的方式上传至 Pinata 中。
const contractAddress = "0x094180BBc8f5e8e9697C0F633D4004e3ecea6510"
const nftContract = new web3.eth.Contract(contract.abi, contractAddress)
API_URL = "https://eth-goerli.alchemyapi.io/v2/api-key"
PRIVATE_KEY = "metamask-private-key"
PUBLIC_KEY = "metamask-account-address"
定义一个名为 mintNFT(tokenData) 的函数并通过执行以下操作创建Transaction:
现在 mint-nft.js 文件看起来应该长得这样:
require('dotenv').config();
const API_URL = process.env.API_URL;
const PUBLIC_KEY = process.env.PUBLIC_KEY;
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const { createAlchemyWeb3 } = require("@alch/alchemy-web3");
const web3 = createAlchemyWeb3(API_URL);
const contract = require("../artifacts/contracts/NewNFT.sol/NewNFT.json");
console.log(JSON.stringify(contract.abi)) //将应用程序二进制接口发送到控制台以便查看
const contractAddress = "0x094180BBc8f5e8e9697C0F633D4004e3ecea6510";
const nftContract = new web3.eth.Contract(contract.abi, contractAddress);
async function mintNFT(tokenURI) {
const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, 'latest'); //get latest nonce
//the transaction
const tx = {
'from': PUBLIC_KEY,
'to': contractAddress,
'nonce': nonce,
'gas': 500000,
'data': nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI()
};
}
当前已经创建了Transaction,接下来需要签署它以便将其发送出去, 在这里需要用户账户的私钥。
require('dotenv').config();
const API_URL = process.env.API_URL;
const PUBLIC_KEY = process.env.PUBLIC_KEY;
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const { createAlchemyWeb3 } = require("@alch/alchemy-web3");
const web3 = createAlchemyWeb3(API_URL);
const contract = require("../artifacts/contracts/NewNFT.sol/NewNFT.json");
console.log(JSON.stringify(contract.abi)) //将应用程序二进制接口发送到控制台以便查看
const contractAddress = "0x094180BBc8f5e8e9697C0F633D4004e3ecea6510";
const nftContract = new web3.eth.Contract(contract.abi, contractAddress);
async function mintNFT(tokenURI) {
const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, "latest") //get latest nonce
//the transaction
const tx = {
from: PUBLIC_KEY,
to: contractAddress,
nonce: nonce,
gas: 500000,
data: nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI(),
}
const signPromise = web3.eth.accounts.signTransaction(tx, PRIVATE_KEY)
signPromise.then((signedTx) => {
web3.eth.sendSignedTransaction(
signedTx.rawTransaction,
function (err, hash) {
if (!err) {
console.log(
"本次Transaction的Hash值是:",
hash,
"\n可以在Alchemy的Mempool中查询本次Transaction的状态信息。"
)
} else {
console.log(
"提交本次Transaction出现了一些问题:",
err
)
}
}
)
}).catch((err) => {
console.log(" Promise failed:", err)
})
}
在新加入的代码中,web3.eth.sendSignedTransaction 会返回交易的哈希值,可以用这个哈希值来确保交易被正常开采没有被网络丢弃。在交易签署部分,增加了一些错误检查,以便知晓交易是否成功通过。
在上面的操作中,已经将 nft-metadata.json 文件上传到 Pinata 。现在从 Pinata 中获取到 nft-metadata.json 文件的 CID 值,将其作为参数传递给 mintNFT 函数。
require('dotenv').config();
const API_URL = process.env.API_URL;
const PUBLIC_KEY = process.env.PUBLIC_KEY;
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const { createAlchemyWeb3 } = require("@alch/alchemy-web3");
const web3 = createAlchemyWeb3(API_URL);
const contract = require("../artifacts/contracts/NewNFT.sol/NewNFT.json");
console.log(JSON.stringify(contract.abi)) //将应用程序二进制接口发送到控制台以便查看
const contractAddress = "0x094180BBc8f5e8e9697C0F633D4004e3ecea6510";
const nftContract = new web3.eth.Contract(contract.abi, contractAddress);
async function mintNFT(tokenURI) {
const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, "latest") //get latest nonce
//the transaction
const tx = {
from: PUBLIC_KEY,
to: contractAddress,
nonce: nonce,
gas: 500000,
data: nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI(),
}
const signPromise = web3.eth.accounts.signTransaction(tx, PRIVATE_KEY)
signPromise.then((signedTx) => {
web3.eth.sendSignedTransaction(
signedTx.rawTransaction,
function (err, hash) {
if (!err) {
console.log(
"本次Transaction的Hash值是:",
hash,
"\n可以在Alchemy的Mempool中查询本次Transaction的状态信息。"
)
} else {
console.log(
"提交本次Transaction出现了一些问题:",
err
)
}
}
)
}).catch((err) => {
console.log(" Promise failed:", err)
})
}
mintNFT("ipfs://QmZ643xL21yDh2BzBNHHuVqpXmYnDDfy69Asn3QSJxcbcu")
node scripts/mint-nft.js
稍等片刻,就能看到这样的响应:
本次Transaction的Hash值是: 0x0b0ab9a67c884c513dbd6f7e786e1a59a0d79f26606aaff0678c5367d5fd4b15
可以在Alchemy的Mempool中查询本次Transaction的状态信息。
在 Alchemy 的 Mempool 中查询到本次 Transaction 的状态为被开采:
现在,已经在以太坊区块链上成功部署和铸造了一个非同质化通证!之后,使用 mint-nft.js 就可以随心所欲的铸造更多的非同质化通证。只要确保传给 mintNFT 函数的是一个新的 tokenURI 来描述非同质化通证的元数据。否则,将最终生成一堆相同属性只具有不同 ID 的非同质化通证。
用了两篇文章的篇幅
通过一个具体的例子,操作了Ethereum上非同质化通证(NFT)的编写、部署、铸造和展示的具体方法和流程,希望能对大家有所帮助。
最后,欢迎大家走进 Web3.0 的世界!
因篇幅问题不能全部显示,请点此查看更多更全内容