I made an NPM package to help with this: eth-revert-reason
It is hard to decode the revert reason in a generalized manner. Many different factors, such as web3.js vs. ethers, Geth vs. Parity, etc. will result in different results for all the answers posted here. Some issues are:
- For a Kovan transaction, you need a custom provider that exposes Parity
- Transactions may result in different messages depending on the context of the block they are called from. Because of this, you may need to be running a full-archival node in order to retrieve the correct error message.
In a happy-path case, the code to retrieve the revert reason is:
const provider = customProvider || ethers.getDefaultProvider(network)
const tx = await provider.getTransaction(txHash)
const code = await provider.call(tx)
While the code to generate the revert reason in the normal case is simple, the non-happy-path cases are surprisingly difficult to handle, however this package attempts to appease this.