如何为Solidity合约的purchaseNFT函数编写Hardhat测试用例?
问题解决:Ethers v6下测试用例的BigInt方法错误
错误原因
你使用的是Ethers v6版本,该版本中gasPrice、gasUsed以及余额查询返回的都是原生BigInt类型,而非Ethers v5中的BigNumber对象,因此不能调用.mul()、.sub()、.add()这类方法,需直接用JavaScript算术运算符(*、-、+)处理数值计算。另外你的测试代码重复调用了purchaseTx.wait(),会额外消耗资源,建议只调用一次并保存结果。
修正后的测试用例
it("Should allow a user to purchase an NFT from the marketplace", async function () { const nftURI = "https://gateway.pinata.cloud/ipfs/QmYP96XCnv2GnCJhvbty8U7VL1QpJUkfQC51zzRih8McT8/7705305.jpg"; const listingPrice = ethers.parseEther("0.1"); await nftMarketplace.createAndListNFT(nftURI, listingPrice); const tokenId = 1; const initialSellerBalance = await ethers.provider.getBalance(marketplaceOwner.address); const purchaseTx = await nftMarketplace.connect(buyer).purchaseNFT(tokenId, { value: listingPrice }); const txReceipt = await purchaseTx.wait(); // 仅调用一次wait并存储结果 const updatedSellerBalance = await ethers.provider.getBalance(marketplaceOwner.address); const gasPrice = purchaseTx.gasPrice; const gasUsed = txReceipt.gasUsed; const gasCost = gasPrice * gasUsed; // 用*替代mul() const expectedSellerBalanceInWei = initialSellerBalance - gasCost + listingPrice; // 用-、+替代sub()、add() expect(updatedSellerBalance.toString()).to.equal(expectedSellerBalanceInWei.toString()); const ownerOfNFT = await nftMarketplace.ownerOf(tokenId); expect(ownerOfNFT).to.equal(buyer.address); const marketItem = await nftMarketplace.tokenIdToMarketItem(tokenId); expect(marketItem.sold).to.be.true; });
额外提示:你的Solidity合约存在逻辑bug
查看你提供的purchaseNFT函数,当前逻辑会先将tokenIdToMarketItem[tokenId].seller设为address(0),再调用payable(tokenIdToMarketItem[tokenId].seller).transfer(msg.value),这会导致购买款直接转入零地址,卖家无法收到资金。正确逻辑应先保存卖家地址,再修改状态,最后完成转账:
function purchaseNFT(uint256 tokenId) public payable { MarketItem storage item = tokenIdToMarketItem[tokenId]; uint256 price = item.price; require(msg.value == price, "Please submit the correct purchase price to complete the transaction"); address payable seller = item.seller; // 先保存原卖家地址 item.seller = payable(address(0)); item.sold = true; _itemsSold.increment(); _transfer(address(this), msg.sender, tokenId); seller.transfer(msg.value); // 向原卖家转账 }
内容的提问来源于stack exchange,提问作者VISHNU S
相关产品推荐
相关产品推荐

