Solidity Ethers.js – Adding All Revert Error Strings to Ethers.js Interface

errorethers.jsrevert-opcodesolidity

According to this tool if a contract call has a revert message that starts with the signature 0x08c379a0 then the error message is in the format Error(string) i.e. a standard revert error string(e.g. revert("error occurred")), however I cannot add error Error(string errorString) to my ethers Interface that has a list of custom errors, such that I can parse/decode both those custom errors and standard reverts with a string error messages.

My ethers interface:

import { Interface } from "@ethersproject/abi";

const iErrors = new Interface([
    "error Custom1()",
    "error Custom2()",

    "error Custom3(int errorCode, address account)",
    "error Custom4(int errorCode, uint number)",

    "error AccountLocked(address owner, uint256 balance)",

    // "error Error(string errorString)", // this does not work
]);

const standardErrorString = "0x08c379a0...."; // how to decode this
const accountLockedErrorData = "0xf7c3865a0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba720000000000000000000000000000000000000000000000000de0b6b3a7640000"

const customErrorDescription = iErrors.parseError(customErrorData); // parses AccountLocked error

How can I parse/decode both custom error messages and standard revert string messages?

Best Answer

I managed to get it working by first checking if it's a standard revert string and if not attempting to parse it as a custom solidity error.

In addition to Error(string) Solidity has another built-in error i.e. Panic(uint), hence I've added a decoding for that as well.

export const parseError = (errorData) => {

    if (errorData.startsWith('0x08c379a0')) { // decode Error(string)

        const content = `0x${errorData.substring(10)}`;
        const reason = utils.defaultAbiCoder.decode(["string"], content);

        return reason[0]; // reason: string; for standard revert error string
    }

    if (errorData.startsWith('0x4e487b71')) { // decode Panic(uint)
        const content = `0x${errorData.substring(10)}`;
        const code = utils.defaultAbiCoder.decode(["uint"], content);

        return code[0];
    }

    try {
        const errDescription = iErrors.parseError(errorData);
        return errDescription;
    } catch (e) {
        console.error(e);
    }
}