A quick note is that eth_call revert reasons are already completely supported:

contract.someMethod(1, 2, 3).then((result) => {
}, (error) => {
    console.log(error);
    // error.reason - The Revert reason; this is what you probably care about. :)
    // Additionally:
    // - error.address - the contract address
    // - error.args - [ BigNumber(1), BigNumber(2), BigNumber(3) ] in this case
    // - error.method - "someMethod()" in this case
    // - error.errorSignature - "Error(string)" (the EIP 838 sighash; supports future custom errors)
    // - error.errorArgs - The arguments passed into the error (more relevant post EIP 838 custom errors)
    // - error.transaction - The call transaction used
});

@onetom That’s an interesting idea. I will have to experiment with it a bit. I don’t think it makes sense to always use eth_call, since that is an additional call with every transaction that is not necessarily going to return consistent results, but maybe on the error returned from a failed transaction receipt, there can be a checkCall method?

contract.transfer(someAddress, someValue).then((tx) => {
    return tx.wait().then((receipt) => {
        // This is entered if the transaction receipt indicates success
        return true;
    }, (error) => {
        // This is entered if the status of the receipt is failure
        return error.checkCall().then((error) => {
            console.log("Error", error);
            return false;
        });
    }
});

The main issue with consistency, is that things can change on the blockchain between an eth_call and a transaction being mined. Also, a lot of things are not meaningful during an eth_call (e.g. block hash) and the dangers of front-running can crop up.