Ethers.js: Get the revert reason for failed transactions

Created on 7 Mar 2019  Â·  11Comments  Â·  Source: ethers-io/ethers.js

Hello, me again :slightly_smiling_face: , is there a way to caught require() descriptions when failed? For instance, I have the following for a send-like function:

require(security.userAllowed(msg.sender), "Operation Denied - User does not have the privileges to create Ledgers");
require(tokenContract.transferFrom(msg.sender, _admin, 1), "Operation Denied - User does not have enough tokens to operate"); 

I'd like to catch those descriptions ("Operation Denied - ..."), is it possible? Or just have to manage Events or maybe throw exceptions instead of require in the contract?

Thanks again!

discussion

All 11 comments

This is not possible in Ethereum currently. You also cannot use events, since a revert also rolls back event logs. And throw uses the same mechanism. :)

There isn't really a good solution to this right now. There are some proposal EIPs for ways to solve this, but none of them are currently ready for adoption, and I don't think they are very backward compatible.

If you really need this type of functionality, you can not throw, and simply log an error and return, but I think it may be worrying too much.

You could, for example easily check these two conditions before making the call to the contract. There is a slight consistency issue, if I make a tx sending all my tokens, but before it is mined, call those checks (which would return "ok"), then make the tx calling this operation. But that is not likely to be an issue unless the user is trying to make it an issue. Just call the blanceOf() on the target ERC-20 and userAllowed() on the security contract.

Best answer, there is not good solution, but there are various levels of non-terrible solutions. :)

Hehe I understand :) I was familiar with some of these solutions, but wanna to know if that was it. I’m very curious about everything actually, and learning what else is out there, despite not being a final (better-perfect-shining :P ) solution, it’s also amazing.

Thank you again por taking the time!

On Mar 7, 2019 at 2:18 pm,

This is not possible in Ethereum currently. You also cannot use events, since a revert also rolls back event logs. And throw uses the same mechanism. :)

There isn't really a good solution to this right now. There are some proposal EIPs for ways to solve this, but none of them are currently ready for adoption, and I don't think they are very backward compatible.

If you really need this type of functionality, you can not throw, and simply log an error and return, but I think it may be worrying too much.

You could, for example easily check these two conditions before making the call to the contract. There is a slight consistency issue, if I make a tx sending all my tokens, but before it is mined, call those checks (which would return "ok"), then make the tx calling this operation. But that is not likely to be an issue unless the user is trying to make it an issue. Just call the blanceOf() on the target ERC-20 and userAllowed() on the security contract.

Best answer, there is not good solution, but there are various levels of non-terrible solutions. :)

—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub (https://github.com/ethers-io/ethers.js/issues/446#issuecomment-470614846), or mute the thread (https://github.com/notifications/unsubscribe-auth/ASaeh90IMogTOYK_mQ7YNhffDrBdAEZlks5vUUnXgaJpZM4bi_Yo).

No worries. :)

Hopefully in the future there will be a better solution... I think adopting an error code status is another EIP out there somewhere.

You can also call the function using eth_call, which will give you the error code, but that is also subject to consistency issues.

Closing this now, but feel free to re-open or continue discussion (I monitor closed issues).

:)

@ricmoo Can you please clarify this assertion?

This is not possible in Ethereum currently. You also cannot use events, since a revert also rolls back event logs.

Support for error reason string was added to Solidity here: https://github.com/ethereum/solidity/releases/tag/v0.4.22. I understand that not all Ethereum client support it, but some do including Ganache. Web3 returns it in the reason attribute of the error object. Shouldn't Ethers do the same when supported by the blockchain client?

As far as I can tell, Web3 gets it from the receipt: https://github.com/ethereum/web3.js/blob/156f20962c26e2c0942386f2e6704b8c0b7edb96/packages/web3-core-method/lib/methods/transaction/AbstractObservedTransactionMethod.js

Oh, I believe you are correct for Ganache (although I have not used it for quite some time, I think there is a standards-compliant mode and another mode; I’m not sure which is the default).

But in Ethereum (e.g. homestead on Parity or Geth), a revert will roll back all state changes, including logs, which is how events are stored.

That is very much a Ganache-only feature, and changes wildly. There is certainly room for someone to build a GancheProvider, who will maintain it (ideally the creators of Ganache would do this, so they can keep the feature set in sync and keep it up to date, as often they change internal structures). I have most of a replacement for Ganache complete (which is what I generally use) and will be releasing, which has a more standards-compliant method to retrieve this.

But no transaction should result in an error stack. When a transaction is sent to the network, it is mined. Any errors should only appear in the receipt. Tracking this for Ganache would add error-prone code to an otherwise generic provider.

Make sense?

Yes, thanks for the clarification! I've researched this further and it looks like what Ganache implemented amounts to the original EIP-658 proposal which included the return value in the receipt, but was later dropped in favor of a binary status code. Ganache's standards compliant mode is --noErrorsOnVMResponse and I believe that it's not the default. I understand that Geth is addressing this issue by implementing EIP-758, and that Parity exposes trace_replayTransaction (to allow callers to get the return value by replaying the tx).

So I do understand the rationale for not including non-standard constructs in Ethers. This actually helped me avoid making faulty assumptions.

Having said that, the revert reason is useful when unit testing contracts. Will this Ganache replacement module that you speak of be released as part of etherlime or is it a separate project? I apologize for my lack of familiarity with the Ethers stack.

No worries. :)

It will be its own thing, part of ethers. I am working on an @ethersproject/evm package, and the Ganache replacement will be part of the @ethersproject/cli package. The new version of ethers is made up of smaller packages, managed by Lerna, which will make it easier to include an EVM for only those who need it, rather than bloating the library for those (most people) who don't need it. :)

Somewhat related: Support for revert reasons was just released in web3.js 1.x, in case something analogous to their strategy would make sense in ethers.js.

Oh, revert reasons have been supported in ethers for quite a while, but that only works when the error bubbles up through the call.

In this case, they were being trapped and converted to a return of a string. :)

(if interested, it was added here)

Ah, got it. Good to know, thanks!

Was this page helpful?
0 / 5 - 0 ratings