hardhat icon indicating copy to clipboard operation
hardhat copied to clipboard

Wrong inferred error when a view-function of a library is called and it reverts

Open ivanzhelyazkov opened this issue 4 years ago • 15 comments

Deploying and calling a library's view function in a mainnet fork pinned at a certain block sometimes results in: Error: Transaction reverted: library was called directly.

That behaviour is unexpected and doesn't correlate to mainnet behaviour. Libraries pure and view functions should be callable from an external account. Interacting with the same library from an external account on mainnet returns a proper value when calling the same view function.

When changing the pinned block it seems that the issue is sometimes resolved. No exact steps to reproduce.

Minimal example: A library with one view function which returns a number and a script, which deploys the library, and calls the view function. Run with mainnet forking enabled and pinned at a block.

ivanzhelyazkov avatar Sep 10 '21 11:09 ivanzhelyazkov

A library with one view function which returns a number and a script, which deploys the library, and calls the view function. Run with mainnet forking enabled and pinned at a block.

I did this and couldn't reproduce the problem. Works fine with and without forking, and with and without a pinned block.

fvictorio avatar Sep 10 '21 12:09 fvictorio

After a bit more digging, turned out that the function really was reverted, but the error message was incorrect. Error message should have been "SafeMath: multiplication overflow"

ivanzhelyazkov avatar Sep 10 '21 13:09 ivanzhelyazkov

Oh, that's interesting. Is there a chance you can make a minimal example of that? It could be a bug in our tracer.

fvictorio avatar Sep 10 '21 13:09 fvictorio

Yeah, so basically you can do something like this:

function test() public view returns(uint256) {
        require(msg.sender == 0x0000000000000000000000000000000000000000, "Error");
        return 1;
}

And call that function on the library to receive the error: library was called directly

ivanzhelyazkov avatar Sep 10 '21 15:09 ivanzhelyazkov

Thanks!

fvictorio avatar Sep 10 '21 19:09 fvictorio

Which compiler version are you using, @ivanzhelyazkov?

alcuadrado avatar Sep 10 '21 23:09 alcuadrado

Which compiler version are you using, @ivanzhelyazkov?

0.7.6, @alcuadrado

ivanzhelyazkov avatar Sep 12 '21 11:09 ivanzhelyazkov

I'm also having this issue, but I haven't been able to work out the true reason for the revert.

Is this only occuring for "SafeMath: multiplication overflow"?

I"m confident it's an incorrect trace because I can run other functions from the same library just fine.

Thanks!

cj-clifton avatar Nov 15 '21 07:11 cj-clifton

This error will also be reported when running test case on the local network.

big-dam avatar Dec 13 '21 03:12 big-dam

Can you provide a reproduction repository? Thanks!

alcuadrado avatar Jan 03 '22 20:01 alcuadrado

Just ran into this issue recently, any update on a fix or any workaround?

0xdomrom avatar Feb 28 '22 10:02 0xdomrom

I'm experiencing this locally with a pure function in a library also. I'm attempting to write tests for the following function:

function push(RingBuffer calldata buf, int256 x) public pure returns (RingBuffer memory) {
    int256[] memory ys = buf.xs;

    if (buf.write == buf.n) {
        ys[0] = x;
        return RingBuffer(ys, buf.n, 1, buf.read);
    } else {
        ys[buf.write] = x;
        return RingBuffer(ys, buf.n, buf.write + 1, buf.read);
    }
}

In the test suite:

/* ... */

const actualBuffer = await library.push(initialBuffer, someElem)

/* ... */

This errors with:

     Error: Transaction reverted: library was called directly
      at PoolSwapLibrary.<unknown> (contracts/implementation/PoolSwapLibrary.sol:7)
      at processTicksAndRejections (internal/process/task_queues.js:97:5)
      at runNextTicks (internal/process/task_queues.js:66:3)
      at listOnTimeout (internal/timers.js:518:9)
      at processTimers (internal/timers.js:492:7)
      at async HardhatNode.runCall (node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:510:20)
      at async EthModule._callAction (node_modules/hardhat/src/internal/hardhat-network/provider/modules/eth.ts:353:9)
      at async HardhatNetworkProvider.request (node_modules/hardhat/src/internal/hardhat-network/provider/provider.ts:106:18)

sporejack avatar Mar 23 '22 00:03 sporejack

@sporejack see the above mentioned issue for calling library's pure functions using struct

ClementWalter avatar Apr 20 '22 09:04 ClementWalter

This issue was marked as stale because it didn't have any activity in the last 30 days. If you think it's still relevant, please leave a comment indicating so. Otherwise, it will be closed in 7 days.

github-actions[bot] avatar Jul 25 '22 14:07 github-actions[bot]

This issue was closed because it has been stalled for 7 days with no activity.

github-actions[bot] avatar Aug 01 '22 14:08 github-actions[bot]

Hey folks, any additional info on this one? I'm running into the same issue while converting an existing test suite over to hardhat

We are checking for expected reverts from the library methods, but instead seeing Transaction reverted: library was called directly

All valid calls (to the same methods) are working fine.

For example intentionally triggering this revert

    function userShareSeconds(
        address module,
        address addr,
        uint256 shares
    ) public view returns (uint256, uint256) {
        require(shares > 0, "crmi1");
        ...

yields the following error

Wrong kind of exception received
+ expected - actual

-Transaction reverted: library was called directly
+crmi1

devinaconley avatar Aug 14 '22 01:08 devinaconley

Hi @fvictorio @alcuadrado @ivanzhelyazkov has anyone found a solution for this? Currently my workaround is to just expect a generic revert

devinaconley avatar Aug 24 '22 17:08 devinaconley

I tried to reproduce this error with the suggestion from @ivanzhelyazkov at https://github.com/hiroshitash/hardhat-inferred-error, but I wasn't able to.

Instead, I receive the following error, which seems correct.

% npx hardhat run --network localhost scripts/deploy.js
Compiled 2 Solidity files successfully
Error: call revert exception; VM Exception while processing transaction: reverted with reason string "" [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="test()", data="0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", errorArgs=[""], errorName="Error", errorSignature="Error(string)", reason="", code=CALL_EXCEPTION, version=abi/5.7.0)
    at Logger.makeError (/Users/hirotashiro/hardhat-inferred-error/node_modules/@ethersproject/logger/src.ts/index.ts:269:28)
    at Logger.throwError (/Users/hirotashiro/hardhat-inferred-error/node_modules/@ethersproject/logger/src.ts/index.ts:281:20)
    at Interface.decodeFunctionResult (/Users/hirotashiro/hardhat-inferred-error/node_modules/@ethersproject/abi/src.ts/interface.ts:427:23)
    at Contract.<anonymous> (/Users/hirotashiro/hardhat-inferred-error/node_modules/@ethersproject/contracts/src.ts/index.ts:400:44)
    at step (/Users/hirotashiro/hardhat-inferred-error/node_modules/@ethersproject/contracts/lib/index.js:48:23)
    at Object.next (/Users/hirotashiro/hardhat-inferred-error/node_modules/@ethersproject/contracts/lib/index.js:29:53)
    at fulfilled (/Users/hirotashiro/hardhat-inferred-error/node_modules/@ethersproject/contracts/lib/index.js:20:58)
    at processTicksAndRejections (internal/process/task_queues.js:95:5) {
  reason: '',
  code: 'CALL_EXCEPTION',
  method: 'test()',
  data: '0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000',
  errorArgs: [ '' ],
  errorName: 'Error',
  errorSignature: 'Error(string)',
  address: '0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9',
  args: [],
  transaction: {
    data: '0xf8a8fd6d',
    to: '0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9',
    from: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'
  }
}

Hardhat version tested is 2.14.0

% npx hardhat --version
2.14.0

Check at this._isDirectLibraryCall(trace) looks suspicious, but it might be hard to reproduce without hardhat version and repo.

_isDirectLibraryCall is defined here.

  private _isDirectLibraryCall(trace: DecodedCallMessageTrace): boolean {
    return (
      trace.depth === 0 && trace.bytecode.contract.type === ContractType.LIBRARY
    );
  }

hiroshitashir avatar May 26 '23 22:05 hiroshitashir

Hey @hiroshitash thanks for the response. Here's an example that might be useful in reproducing the issue https://github.com/gysr-io/core/blob/614dfffb97cb136190594849c50b29766341f3cd/test/unit/erc20competitiverewardmoduleinfo.js#L127-L137

devinaconley avatar Jun 07 '23 15:06 devinaconley

@devinaconley I found the root cause of your error library was called directly. It's because ERC20CompetitiveRewardModuleInfo is library (not contract) here

library ERC20CompetitiveRewardModuleInfo {
    using GysrUtils for uint256;

If you change it to contract like below, the error disappears.

contract ERC20CompetitiveRewardModuleInfo {
    using GysrUtils for uint256;

Library calls are checked here with this._isDirectLibraryCall(trace).

The error can be reproduced at https://github.com/hiroshitash/hardhat-inferred-error

hiroshitashir avatar Jun 13 '23 21:06 hiroshitashir

I´m having the same issue. It was working fine when I was calling it before as a library w/o any issues until now recently. Problem is, it is not a contract but a genuine library. Please help!

Samboy76 avatar Jun 18 '23 06:06 Samboy76

@Samboy76 The error message library was called directly is hiding your original error so I suggest the followings:

  1. Temporarily change library to contract (in order to hide library was called directly error).
  2. Compile with yarn hardhat compile or npx hardhat compile. It should show your original error.
  3. Fix the original error, change back contract to library, and try compiling again.

As for the change in Hardhat, I think the lines below can be removed as it is hiding the original error message.

    if (this._isDirectLibraryCall(trace)) {
      return this._getDirectLibraryCallErrorStackTrace(trace);
    }

hiroshitashir avatar Jun 19 '23 23:06 hiroshitashir

@devinaconley I found the root cause of your error library was called directly. It's because ERC20CompetitiveRewardModuleInfo is library (not contract) here

thanks for the response and suggestiong @hiroshitash -- in our case, the libraries are designed to be stateless and called directly, so unfortunately switching to a contract is not a viable workaround

devinaconley avatar Jun 21 '23 11:06 devinaconley