Hardhat – Resolving Issues with Expect Not Getting Revert Reason

hardhattesting

I'm using Hardhat framewrok and doing some testing with an erc20 contract:

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

I'm expecting the contract to revert with an error of : ERC20: insufficient allowance

Here is the require statement from the contract:

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

and this is the error I'm getting:

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)

in the error message I can see ERC20: insufficient allowance but the expect function is not getting it and failing the test.

Here is the contract:

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);
    }
}

Deploy:

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"];

Test:

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");
    });
});

Best Answer

So after almost a day of debugging it turns out that I need another plugin to use revertedWith() I need to install npm install --save-dev @nomiclabs/hardhat-waffle 'ethereum-waffle@^3.0.0' @nomiclabs/hardhat-ethers 'ethers@^5.0.0' and import it in the config file, otherwise I need to use rejectedWith("ERC20: insufficient allowance").

if anyone can explain this further it would be better because still I don't whats the difference between revertedWith and rejectedWith and why we need to install hardhat-waffle to be able to use revertedWith.

more info about hardhat-waffle in this page: https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-waffle

Related Topic