使用Viem.sh读取NFT合约信息
要使用 Viem.sh
读取特定 NFT 合约中的信息,首先,你需要确保在项目中已经安装并配置了 @viem/sh
库。如果还没有安装,可以使用以下命令进行安装:
pnpm install viem
新建viem_nft1
文件夹和文件index.js
mkdir viem_nft1
cd viem_nft1 && vim index.js
在此,需要连接到以太坊网络:你需要使用 Viem
库连接到以太坊网络,例如 Infura 或 Alchemy 提供的节点。
其次,定义合约和调用函数:你需要定义 NFT 合约的 ABI 和地址,并调用相应的函数来读取持有人地址和元数据。
你可以替换NFT_TOKEN_ID
为你实际的 NFT 的 Token ID。
编辑文件index.js
内容如下:
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains';
import erc721Abi from './erc721Abi.json' assert { type: 'json' };
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const nftContractAddress = '0x0483b0dfc6c78062b9e999a82ffb795925381415'
const tokenId = 'NFT_TOKEN_ID'
// 读取持有人地址
async function getOwnerOf(tokenId) {
const owner = await client.readContract({
address: nftContractAddress,
abi: erc721Abi,
functionName: 'ownerOf',
args: [tokenId],
})
return owner
}
// 读取元数据 URI
async function getTokenURI(tokenId) {
const tokenURI = await client.readContract({
address: nftContractAddress,
abi: erc721Abi,
functionName: 'tokenURI',
args: [tokenId],
})
return tokenURI
}
// 主函数
async function main() {
try {
const owner = await getOwnerOf(tokenId)
console.log(`NFT持有人地址: ${owner}`)
const tokenURI = await getTokenURI(tokenId)
console.log(`NFT元数据URI: ${tokenURI}`)
// 如果需要进一步获取元数据,可以发起HTTP请求获取元数据
const response = await fetch(tokenURI)
const metadata = await response.json()
console.log('NFT元数据:', metadata)
} catch (error) {
console.error('读取NFT信息时出错:', error)
}
}
main()
为了读取 NFT 合约的信息,你需要有该合约的 ABI(应用二进制接口)文件。你可以创建一个 erc721Abi.json
文件,其中包含 ERC-721 标准合约的 ABI。
打开浏览器,依次按照进行点击红框,往下拉寻找NFT合约的ABI
点击按钮,复制文件
编辑文件 erc721Abi.json
内容复制粘贴如下:
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"Price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TotalNum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"addToBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"numberOfTokens","type":"uint256"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"blacklist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isContract","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"listClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextOwnerToExplicitlySet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publicMintEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"removeFromBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI_","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enable","type":"bool"}],"name":"setPublicMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"mroot","type":"bytes32"},{"internalType":"uint256","name":"step","type":"uint256"}],"name":"setRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enable","type":"bool"},{"internalType":"uint256","name":"step","type":"uint256"}],"name":"setWlMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wlMintStep1Enabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wlMintStep2Enabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"wlmint1","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"wlmint2","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"wlroot1","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wlroot2","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}]
首先,在你的项目目录中运行以下命令来初始化一个新的项目:
pnpm init
按照提示填写项目名称、版本等信息。完成后,会生成一个 package.json
文件。
{
"name": "viem_nft1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
在脚本文件中添加构建模块和依赖
{
"name": "viem_nft1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"start": "node index.js",
"build": "echo 'Build step, e.g., webpack or babel'",
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"viem": "^2.17.3"
},
"keywords": [],
"author": "",
"license": "ISC"
}
运行以下命令安装依赖构建项目:
pnpm install
pnpm build
填写'NFT_TOKEN_ID' ,比如为1,最后,运行以下命令启动项目:
pnpm start
这里会得出运行结果但是会报一个错误,这个错误是因为 fetch
函数不能直接处理 ipfs://
协议。为了读取 IPFS 上的内容,你需要通过一个网关来访问 IPFS URL,比如 https://ipfs.io/ipfs/
或者其他公共 IPFS 网关。
你可以将 IPFS URL 替换为通过公共网关访问的 HTTP URL。下面是更新后的代码:
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains';
import erc721Abi from './erc721Abi.json' assert { type: 'json' };
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const nftContractAddress = '0x0483b0dfc6c78062b9e999a82ffb795925381415'
const tokenId = '1'
// 读取持有人地址
async function getOwnerOf(tokenId) {
const owner = await client.readContract({
address: nftContractAddress,
abi: erc721Abi,
functionName: 'ownerOf',
args: [tokenId],
})
return owner
}
// 读取元数据 URI
async function getTokenURI(tokenId) {
const tokenURI = await client.readContract({
address: nftContractAddress,
abi: erc721Abi,
functionName: 'tokenURI',
args: [tokenId],
})
return tokenURI
}
// 将 IPFS URL 转换为 HTTP URL
function convertIpfsUrl(ipfsUrl) {
return ipfsUrl.replace('ipfs://', 'https://ipfs.io/ipfs/');
}
// 主函数
async function main() {
try {
const owner = await getOwnerOf(tokenId);
console.log(`NFT持有人地址: ${owner}`);
const tokenURI = await getTokenURI(tokenId);
console.log(`NFT元数据URI: ${tokenURI}`);
// 将 IPFS URL 转换为 HTTP URL
const httpUrl = convertIpfsUrl(tokenURI);
console.log(`转换后的HTTP URL: ${httpUrl}`);
// 发起HTTP请求获取元数据
const response = await fetch(httpUrl);
const metadata = await response.json();
console.log('NFT元数据:', metadata);
} catch (error) {
console.error('读取NFT信息时出错:', error);
}
}
main();
// // 主函数
// async function main() {
// try {
// const owner = await getOwnerOf(tokenId)
// console.log(`NFT持有人地址: ${owner}`)
// const tokenURI = await getTokenURI(tokenId)
// console.log(`NFT元数据URI: ${tokenURI}`)
// // 如果需要进一步获取元数据,可以发起HTTP请求获取元数据
// const response = await fetch(tokenURI)
// const metadata = await response.json()
// console.log('NFT元数据:', metadata)
// } catch (error) {
// console.error('读取NFT信息时出错:', error)
// }
// }
// main()
然后重新运行
pnpm start
结果如下:
@yhbdeMacBook-Air viem_nft1 % pnpm start
> viem_nft1@1.0.0 start /Users/yhb/viem_nft/viem_nft1
> node index.js
(node:93006) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
NFT持有人地址: 0x6897625C2Da7E985e9c22E0d7B27A960Fc81D1D2
NFT元数据URI: ipfs://QmY9wa5FssaBBhLyyC2r649rwfS7CcvH7NG5AJWepeDkGj/1.json
转换后的HTTP URL: https://ipfs.io/ipfs/QmY9wa5FssaBBhLyyC2r649rwfS7CcvH7NG5AJWepeDkGj/1.json
NFT元数据: {
dna: 'b5940ead98dd50c06ccdb56ccfa37123ff083ca3',
name: 'ORBIT#1 Metaverse 1 Time and Space',
description: '',
image: 'ipfs://QmT3wMgcmm9R1dC1F63rBFdQdGYCfWfpv1D1PXYXTwrEaQ/1.jpg',
edition: 1,
date: 1715078282818,
attributes: [
{ trait_type: 'Category', value: 'Metaverse' },
{ trait_type: 'Color', value: 'Green' },
{ trait_type: 'Planet', value: 'Moderate' },
{ trait_type: 'Years', value: '2018' },
{ trait_type: 'Characters', value: 'Null' },
{ trait_type: 'Shapes', value: 'Square' },
{ trait_type: 'Elements', value: 'Mixed' }
]
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!