Hardhat

安全帽期望沒有得到恢復原因

  • October 16, 2022

我正在使用 Hardhat 框架並通過erc20契約進行一些測試:

await expect(
   ERC20Contract.transferFrom(ERC20Contract.address, deployer, amount)
).to.be.revertedWith("ERC20: insufficient allowance");

我預計契約會因以下錯誤而恢復:ERC20: insufficient allowance

這是契約中的要求聲明:

require(currentAllowance >= amount, "ERC20: insufficient allowance");

這是我得到的錯誤:

Error: cannot estimate gas; transaction may fail or may require manual gas limit [ See: https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ] (error={"name":"ProviderError","_stack":"ProviderError: HttpProviderError\n    at HttpProvider.request (/home/kadiemq/hh-tut/erc20-tut/node_modules/hardhat/src/internal/core/providers/http.ts:78:19)\n    at LocalAccountsProvider.request (/home/kadiemq/hh-tut/erc20-tut/node_modules/hardhat/src/internal/core/providers/accounts.ts:187:34)\n    at processTicksAndRejections (node:internal/process/task_queues:96:5)\n    at async EthersProviderWrapper.send (/home/kadiemq/hh-tut/erc20-tut/node_modules/@nomiclabs/hardhat-ethers/src/internal/ethers-provider-wrapper.ts:13:20)","code":-32000,"_isProviderError":true,"data":{"stack":"RuntimeError: VM Exception while processing transaction: revert ERC20: insufficient allowance\n    at Function.RuntimeError.fromResults (/tmp/.mount_ganachAQrIFW/resources/static/node/node_modules/ganache-core/lib/utils/runtimeerror.js:94:13)\n    at module.exports (/tmp/.mount_ganachAQrIFW/resources/static/node/node_modules/ganache-core/lib/utils/gas/guestimation.js:142:32)","name":"RuntimeError"}}, tx={"data":"0x23b872dd000000000000000000000000624daf7e06c04e0ab541323b3d3e95b629745a6000000000000000000000000033757dfeda24de8dc2b46d348a035ad60bbc3a3f0000000000000000000000000000000000000000000000000de0b6b3a7640000","to":{},"from":"0x2c93fc47DC6aaF30CD5a6C47F59bD898842B0190","gasPrice":{"type":"BigNumber","hex":"0x04a817c800"},"type":0,"nonce":{},"gasLimit":{},"chainId":{}}, code=UNPREDICTABLE_GAS_LIMIT, version=abstract-signer/5.7.0)

在錯誤消息中我可以看到ERC20: insufficient allowance,但該expect功能沒有得到它並且測試失敗。

這是契約:

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract OurToken is ERC20 {
   constructor(uint256 initialSupply) ERC20("OurToken", "OT") {
       _mint(address(this), initialSupply);
       _approve(address(this), msg.sender, initialSupply);
   }
}

部署:

import { DeployFunction } from "hardhat-deploy/dist/types";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import {
   developmentChains,
   INITIAL_SUPPLY,
   networkConfig,
} from "../helper-hardhat-config";

const DeployToken: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
   const { getNamedAccounts, deployments, network } = hre;
   const { deploy, log } = deployments;
   const { deployer } = await getNamedAccounts();
   const chainId = network.config.chainId!;
   const args = [INITIAL_SUPPLY];

   const OurToken = await deploy("OurToken", {
       from: deployer,
       args: args,
       log: true,
       waitConfirmations: networkConfig[network.name].blockConfirmations || 1,
   });
};

export default DeployToken;
DeployToken.tags = ["all", "token"];

測試:

import { deployments, ethers, getNamedAccounts } from "hardhat";
import { ERC20 } from "../typechain-types";
import { assert, expect } from "chai";

describe("Testing", async () => {
   let deployer: string;
   let second: string;
   let ERC20Contract: ERC20;

   beforeEach(async () => {
       deployer = (await getNamedAccounts()).deployer;
       second = (await getNamedAccounts()).second;

       await deployments.fixture(["all"]);
   });
   it("testing with deployer", async () => {
       ERC20Contract = await ethers.getContract("OurToken", deployer);
       const amount = ethers.utils.parseEther("1");

       const previousBalance = await ERC20Contract.balanceOf(deployer);

       const tx = await ERC20Contract.transferFrom(
           ERC20Contract.address,
           deployer,
           amount
       );
       tx.wait(1);

       const newBalance = await ERC20Contract.balanceOf(deployer);
       assert.equal(
           previousBalance.add(amount).toString(),
           newBalance.toString()
       );
   });

   it("testing with second", async () => {
       ERC20Contract = ERC20Contract.connect(second);
       const amount = ethers.utils.parseEther("1");

       await expect(
           ERC20Contract.transferFrom(ERC20Contract.address, deployer, amount)
       ).to.be.revertedWith("ERC20: insufficient allowance");
   });
});

revertedWith是 waffle 庫中的一個 chai 匹配器,用於斷言還原的錯誤數據匹配或不匹配特定字元串。

rejectedWith是一個 chai 外掛,用於擴展 chai 以斷言有關承諾的事實。

hardhat-waffle是一個用於與 Waffle 集成的安全帽外掛,因此如果您想使用revertedWithWaffle 的 chai matcher,則需要在安全帽中安裝此外掛。您也可以安裝@nomicfoundation/hardhat-chai-matchersrevertedWith在安全帽中使用。

看:

https://ethereum-waffle.readthedocs.io/en/latest/matchers.html

https://hardhat.org/hardhat-c​​hai-matchers/docs/overview

https://www.chaijs.com/plugins/chai-as-promised/

您是否已批准ERC20Contract.address轉讓?您應確保已批准將指定金額轉入的契約deployer

請提供整個程式碼或至少提供它處理的函式和狀態變數,以便我可以幫助您。

編輯:在你發布了整個程式碼之後,我看到它在 TS 中,這不是我的權力。但是我為 JS 執行了等效的程式碼,它執行良好:

const { ethers } = require("hardhat");
const { assert, expect } = require("chai");

let ERC20Contract;
let contract;

describe("Testing", async () => {
 beforeEach(async () => {
   [owner, second] = await ethers.getSigners();
   ERC20Contract = await ethers.getContractFactory("OurToken"); //getting the contract factory
   contract = await ERC20Contract.deploy(500); //providing arguments to the construcotr and deploying it
   await contract.deployed();
   let balance = await contract.balanceOf(contract.address);
   console.log(balance);
 });
 it("testing with second", async () => {
   const amount = 300; 

   await expect(
     contract
       .connect(second)
       .transferFrom(contract.address, second.address, amount)
   ).to.be.revertedWith("ERC20: insufficient allowance");
 });
});

引用自:https://ethereum.stackexchange.com/questions/137527