0

I have a basic ERC contract with the user deployer that is owner and only has rights to mint.

The mint function has an "onlyOwner" modifier with no message sent when reversion is triggered via the require(msg.sender == owner); statement in the ERC20 Solidity contract.

The following Hardhat test code (using Chai) fails to pass the test. I am given the error "Error: Transaction reverted without a reason string".

console.log("Minting 5000 tokens to users 1, 2, and 3");
await ERC20Contract.connect(deployer).mint(user1.address, USERS_MINT);
await ERC20Contract.mint(user2.address, USERS_MINT);
await ERC20Contract.mint(user3.address, USERS_MINT);

// Confirm "onlyOwner" modifier
expect(await ERC20Contract.connect(user2).mint(user1.address, USERS_MINT)).to.be.reverted;
// Check minted balances
expect(await ERC20Contract.connect(user1).balanceOf(user1.address)).to.equal(USERS_MINT);
expect(await ERC20Contract.balanceOf(user2.address)).to.equal(USERS_MINT);
expect(await ERC20Contract.balanceOf(user3.address)).to.equal(USERS_MINT);
console.log("Successfully minted and balances confirmed!")

The tests come out when I comment out the "to.be.reverted" test. My understanding is that test is used for this very case: when the transaction is reverted without a reason string.

For additional background, I've added the substantive Solidity code here:

function isOwner() public view returns(bool) {
    return msg.sender == owner;
}

modifier onlyOwner(){
    require(isOwner());
    _;
}

function mint(address _to, uint256 _amnt) public onlyOwner {
    if(_amnt > 10**18){
        _mint(_to, _amnt );
    } 
    else {
        _mint(_to, (1000 * (10**18)));   
    }
}

Why do I have a test error when the reversion happens without an error message? Isn't that what the chai to.be.reverted selector is testing?

1 Answer 1

0

When you are expecting a revert, you should put the await before expect. Instead of:

expect(await ERC20Contract.connect(user2).mint(user1.address, USERS_MINT)).to.be.reverted;

There should be:

await expect(ERC20Contract.connect(user2).mint(user1.address, USERS_MINT)).to.be.reverted;

Notice that in the previous test we wrote expect(await ...) but now we are doing await expect(...). In the first case we were comparing two values in a synchronous way; the inner await is just there to wait for the value to be retrieved. In the second case, the whole assertion is async because it has to wait until the transaction is mined. This means that the expect call returns a promise that we have to await.

You can read more here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.