2

in the code below, if a revert using the custom error inside the pure function it reverts with a different error (below). If I do the same things without pure, it reverts with the custom error as expected

After @hroussille comment I tried it in remix but couldn't recreate the issue, so it seems I'm having an issue with hardhat.


test contract

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;

contract RevertProblem  {
    error aCustomError(string errorText);

    function test1() public pure {
        revert ("BadHappened");
    }

    function test2() public {
        revert aCustomError("BadHappened");
    }

    function test3() public pure {
        revert aCustomError("BadHappened");
    }
}

test script

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

describe("Should revert with expected message", async function() {
 

    it("not so pure", async function () {
        const rpContractFactory = await ethers.getContractFactory('RevertProblem')
        const rpContract = await rpContractFactory.deploy()
        await rpContract.deployed()

        await expect(rpContract.test1()).to.be.revertedWith("BadHappened")
        await expect(rpContract.test2()).to.be.revertedWith('aCustomError("BadHappened")')
        await expect(rpContract.test3()).to.be.revertedWith('aCustomError("BadHappened")')
    })
});

the first two functions are fine. the third one reverts with

 AssertionError: Expected transaction to be reverted with aCustomError("BadHappened"), but other exception was thrown: Error: call revert exception [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="test3()", data="0x062089cf0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b42616448617070656e6564000000000000000000000000000000000000000000", errorArgs=["BadHappened"], errorName="aCustomError", errorSignature="aCustomError(string)", reason=null, code=CALL_EXCEPTION, version=abi/5.6.3)

It should revert with something like

Error: VM Exception while processing transaction: reverted with custom error 'aCustomError("BadHappened")'

If I take the pure keyword out of my non-test code the function reverts correctly, but even though it compiles OK (just get a warning about should use pure), the non-test function which calculates and returns a number went crazy haywire.

├── @nomiclabs/[email protected]
├── @nomiclabs/[email protected]
├── @openzeppelin/[email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]
3
  • why do you think that the errors are in the "state". Those are constants and probably stored in the contract code .not sure though
    – Majd TL
    May 30, 2022 at 20:13
  • @MajdTL is right, custom error codes collapse to function identifier allowing to identify the error type, there is no state access here. The whole function can be evaluated knowing only the source code, so pure is allowed and advised. What version of hardhat do you use ? Your test works fine on my side (hardhat 2.9.1 and 2.9.7).
    – hroussille
    May 30, 2022 at 20:16
  • thanks for the info. After reading your comments I've tried some other tests and re-worded the question. I couldn't recreate the issue on remix. I can recreate the problem without chai, so it looks like I'm having a local hardhat issue. I upgraded all the packages but same result with [email protected]. Any other ideas?
    – sola24
    May 31, 2022 at 11:26

1 Answer 1

2

That is due to how Ethers dynamically handles transactions.

If you need to call a method that does not change the state of a smart contract (i.e. test1 and test3), Ethers uses a call. Calls are used to read the smart contract's state, and they follow a specific execution path that leads to particular results or errors (https://docs.ethers.io/v5/api/utils/logger/#errors--call-exception).

In particular, the tx is not sent to the blockchain - it's a read, it's not needed - so the execution result is returned directly to the client. In your case, test1 and test3 both return: Error: call revert exception; ...

When calling a method that can potentially change the blockchain's state, a tx is actually sent to the blockchain, it is mined, and then the result is read from the tx's receipt. There you can find the custom error.

And this is why only test2 reverts with Error: VM Exception while processing transaction: reverted with custom error 'aCustomError("BadHappened")'

If you want the 3rd test to pass, you can use:

await expect(rpContract.test3()).to.be.revertedWith("BadHappened")

Please note that to.be.revertedWith(myString) searches for myString inside the error, so all these check pass:

await expect(rpContract.test3()).to.be.revertedWith("Happened")
await expect(rpContract.test3()).to.be.revertedWith("Bad")
await expect(rpContract.test3()).to.be.revertedWith("B")
1
  • some interesting info in there. thanks. it doesn't quite track with the results I got though, nor explain why I get it on hardhat, someone else says they don't, and I cant recreate the issue on remix. The function should be a pure function and works fine on remix. I guess it's a local issue on my machine.
    – sola24
    Jun 2, 2022 at 15:44

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.