[Ethereum] Web3 error handling in React

ethereumjsreactweb3js

This is really a two part question.

First, the only way I can get the error message thrown by a Smart Contract require statement is to call the function first with a call rather than a send. send does not return the message thrown by a failed require statement whereas call does.

Example. In Solidity I might have the following:

require (org._isUser(_user),'Error: User not registered');

In my React frontend I want to be able to display 'Error: User not registered'.

My function call in React is as follows:

async function createPO(e) {
    e.preventDefault()
    const poeacct = e.target.elements[0].value
    const ponumber = e.target.elements[1].value
    const podate = e.target.elements[2].value
    let callOK = true
    try {
      await contract2.methods
        .createOrder('0xd2c4895e24095f23277df168f94a6c035813fe5d', poeacct, ponumber, podate)
        .call({ from: accounts[0] })
    } catch (err) {
      callOK = false
      setMess(err.message)
      console.log(err)
    }
    if (callOK) {
      await contract2.methods
        .createOrder('0xd2c4895e24095f23277df168f94a6c035813fe5d', poeacct, ponumber, podate)
        .send({ from: accounts[0] })

      setpouAcct(pouacct)
      setpoeAcct(poeacct)
      setpoNumber(ponumber)
      setpoDate(podate)
      setMess('Transaction successful')
    }
  }

This works but it's kind of klugey so I'm wondering if there's a better way.

Second. The error returned by the 'catch' in the Web3 call is JSON but there's a prefix:

Error: [object Object]
{
  "message": "VM Exception while processing transaction: revert Error: Order already exists",
  "code": -32000,
  "data": {
    "0x270bb8ddea630f3fc42a4f6196d7710cc50779a34994fd534a8ce139976b0ef5": {
      "error": "revert",
      "program_counter": 21219,
      "return": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001b4572726f723a204f7264657220616c7265616479206578697374730000000000",
      "reason": "Error: Order already exists"
    }

The Error: [object Object] prefix prevents me from parsing out the 'reason:' node. If I remove the prefix manually (i.e. hard code it) it works.

I've tried substring,slice and JSON.parse etc. but I can't find a solution.

Best Answer

Similar to JuliSmz answer, but I wasn't comfortable with the magic 56 character string position as I was worried it would be brittle. I wrote this little function which takes the error object returned by the catch

    function getRPCErrorMessage(err){
        var open = err.stack.indexOf('{')
        var close = err.stack.lastIndexOf('}')
        var j_s = err.stack.substring(open, close + 1);
        var j = JSON.parse(j_s);
        var reason = j.data[Object.keys(j.data)[0]].reason;
        return reason;
    }

Related Topic