You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 17:22:53