Solidity Hardhat中NFTMinted事件tokenId测试断言错误排查
解决MintNFT合约批量铸造时NFTMinted事件tokenId测试不匹配问题
一、事件参数不匹配的排查方向
- 核对合约与测试代码的事件参数顺序:自定义
NFTMinted事件的参数顺序必须和测试中withArgs的参数顺序完全一致。比如合约定义event NFTMinted(address indexed to, uint256 tokenId);,测试里就不能写成withArgs(tokenId, to),顺序颠倒直接触发AssertionError。 - 检查事件名称拼写:测试中监听的事件名称要和合约里的完全一致,大小写、下划线都不能错,比如把
NFTMinted写成NftMinted也会导致找不到事件参数。
二、tokenId数值不匹配的常见原因
- tokenId起始值不一致:OpenZeppelin的ERC721实现很多默认从
1开始计数(比如ERC721Enumerable),如果你的测试用例默认期望从0开始,就会出现数值偏差。去合约里看_tokenId的初始值和递增逻辑:- 如果是
_safeMint(to, _tokenId++),初始值0的话第一个tokenId是0; - 如果是
_safeMint(to, ++_tokenId),初始值0的话第一个tokenId是1。
- 如果是
- 测试环境未重置:如果之前的测试用例已经铸造过NFT,tokenId会持续递增,导致当前测试的起始tokenId不是你预期的
0。解决方法是在beforeEach钩子中重新部署合约,确保每次测试都从干净状态开始:let mintNftContract; beforeEach(async () => { const MintNFT = await ethers.getContractFactory("MintNFT"); mintNftContract = await MintNFT.deploy(); await mintNftContract.deployed(); }); - 批量铸造的事件emit逻辑错误:批量铸造时,要确保emit的tokenId和实际铸造的完全一致。比如不要先递增
_tokenId再emit,正确的写法应该是:function mintBatch(address[] calldata tos) public { for (uint256 i = 0; i < tos.length; i++) { emit NFTMinted(tos[i], _tokenId); _safeMint(tos[i], _tokenId); _tokenId++; } }
三、快速调试技巧
在测试代码中打印事件的实际参数,直接对比预期值:
const tx = await mintNftContract.mintBatch([testAddress, testAddress]); const receipt = await tx.wait(); const mintEvents = receipt.events.filter(e => e.event === "NFTMinted"); mintEvents.forEach((event, index) => { console.log(`第${index+1}个铸造事件参数:`, event.args); });
通过打印结果可以直观看到参数顺序、tokenId数值是否符合预期,快速定位问题。
内容的提问来源于stack exchange,提问作者Anne CHRETIEN
相关产品推荐
相关产品推荐

