如何通过以太坊节点获取所有新铸造的ERC721合约
筛选ERC721代币类型的方法
- 核心靠EIP-165标准接口校验:所有符合规范的ERC721合约都必须实现
supportsInterface方法,传入ERC721的固定接口ID0x80ac58cd,如果返回true就可以判定为ERC721合约。 - 补充判断铸造行为:ERC721的铸造操作对应
Transfer事件的from参数为零地址(0x0000000000000000000000000000000000000000),结合这个特征可以直接定位新铸造的代币。
不需要遍历全区块交易,更高效的实现方案
你不需要逐个解析区块内的所有交易,直接监听/拉取区块的日志(Log)即可,日志已经把所有事件触发的记录做了聚合,筛选成本低很多:
- 先确定目标过滤规则:事件签名为
Transfer(address,address,uint256)对应的哈希是0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef,同时第一个主题(对应from参数)为零地址哈希。 - 每次新区块生成时拉取符合过滤规则的日志,再对日志对应的合约地址做EIP-165校验,排除ERC20、ERC1155等其他同事件签名的合约类型即可。
参考实现代码
const ethers = require("ethers"); const url = "你的节点RPC地址"; const customHttpProvider = new ethers.providers.JsonRpcProvider(url); // ERC721接口ID const ERC721_INTERFACE_ID = "0x80ac58cd"; // Transfer事件签名哈希 const TRANSFER_EVENT_SIG = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"; // 零地址 const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; // 校验是否为ERC721合约 async function isERC721(contractAddress) { const contract = new ethers.Contract( contractAddress, ["function supportsInterface(bytes4 interfaceId) view returns (bool)"], customHttpProvider ); try { return await contract.supportsInterface(ERC721_INTERFACE_ID); } catch (e) { // 不支持supportsInterface的合约直接排除 return false; } } async function monitorNewERC721Mint() { // 监听新区块 customHttpProvider.on("block", async (blockNumber) => { console.log("当前区块号:", blockNumber); // 过滤符合条件的日志 const logs = await customHttpProvider.getLogs({ fromBlock: blockNumber, toBlock: blockNumber, topics: [ TRANSFER_EVENT_SIG, ethers.utils.hexZeroPad(ZERO_ADDRESS, 32) // from为零地址,对应铸造 ] }); for (const log of logs) { const contractAddress = log.address; if (await isERC721(contractAddress)) { // 解析Transfer事件参数 const iface = new ethers.utils.Interface(["event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)"]); const parsedLog = iface.parseLog(log); console.log(`检测到新ERC721铸造:合约地址 ${contractAddress},代币ID ${parsedLog.args.tokenId},接收地址 ${parsedLog.args.to}`); } } }); } async function init() { const currentBlock = await customHttpProvider.getBlockNumber(); console.log("初始当前区块号:", currentBlock); await monitorNewERC721Mint(); } init();
注意事项
- 如果要回溯历史区块的铸造记录,修改
getLogs的fromBlock和toBlock范围即可,单次范围不要过大,避免节点限制请求大小。 - 部分不符合EIP标准的ERC721合约可能未正确实现
supportsInterface方法,这类合约会被过滤掉,如果需要覆盖这类非标准合约,可以额外补充元数据校验逻辑。
内容的提问来源于stack exchange,提问作者xwillorg
相关产品推荐
相关产品推荐

