2

I want to get the revert massage from a send method call to a smart contract. So I use: receipt.logs[0].data that is a string containing a hexadecimal value.

Now I want to to decode this value to get the revert message. So I use web3.eth.abi.decodeParameter method. The main problem is how to give type parameter to get the proper message.

For example If I give:

    const data = '0x0000000000000000000000000000000000000000000000000000c51ccda68b0000000000000000000000000000000000000000000000000002774a57aab99b34000000000000000000000000000000000000000000003692f60f63a91b794ce70000000000000000000000000000000000000000000000000276853add131034000000000000000000000000000000000000000000003692f61028c5e91fd7e7';
    window.web3 = new Web3('https://rpc-mumbai.maticvigil.com');
    window.ethereum.enable();
    web3.eth.handleRevert = true;
    let revertType = [{
        type: 'string', 
        name: 'message'
    }];
    const reason = web3.eth.abi.decodeParameter(revertType, data);
    console.log(reason);

It logs:

Uncaught (in promise) Error: invalid type (argument="type", value="messanger", code=INVALID_ARGUMENT, version=abi/5.7.0)

And if I use:

    const data = '0x0000000000000000000000000000000000000000000000000000c51ccda68b0000000000000000000000000000000000000000000000000002774a57aab99b34000000000000000000000000000000000000000000003692f60f63a91b794ce70000000000000000000000000000000000000000000000000276853add131034000000000000000000000000000000000000000000003692f61028c5e91fd7e7';
    window.web3 = new Web3('https://rpc-mumbai.maticvigil.com');
    window.ethereum.enable();
    web3.eth.handleRevert = true;
    const reason = web3.eth.abi.decodeParameter('string', data);
    console.log(reason);

It logs:

index.ts:269 Uncaught (in promise) Error: data out-of-bounds (length=0, offset=32, code=BUFFER_OVERRUN, version=abi/5.7.0)

The txHash in this example is 0x074e91fe5c1535d9bdc2bbc8cbadc0378c93eb06318401b1f341d844185430fb on Mumbai Polygon testnet: https://mumbai.polygonscan.com/tx/0x074e91fe5c1535d9bdc2bbc8cbadc0378c93eb06318401b1f341d844185430fb

1 Answer 1

1

There's a better way to do this in Web3.js.


// index.js
const { Web3 } = require("web3");

const rpcProvider = 'https://rpc.ankr.com/polygon_mumbai'; // 'https://polygon-testnet.public.blastapi.io';
const web3Provider = new Web3.providers.HttpProvider(rpcProvider);
const web3 = new Web3(web3Provider);


web3.eth.getBlockNumber().then((result) => {
    console.log("Latest Ethereum Block is: ", result); // confirm that the HTTP RPC provider has been instantiated properly
});

const txHash = '0x074e91fe5c1535d9bdc2bbc8cbadc0378c93eb06318401b1f341d844185430fb';

web3.eth.handleRevert = true;

web3.eth.getTransaction(txHash).then(async (tx) => {
    if (tx.gasPrice) {
        delete tx.maxPriorityFeePerGas;
        delete tx.maxFeePerGas;
    }
    try {
        let result = await web3.eth.call(tx, tx.blockNumber); // mock a call to reproduce the tx, otherwise it's hard to get the revert error from just the past tx hash'es logs
    }
    catch (err) {
        // the following transformations are necessary to remove the extra strings from the error object (the ones that mess up with the normal object type access)
        let errFlat = JSON.stringify(err);
        let { innerError : { message } } = JSON.parse(errFlat);

        message = message.replace('execution reverted: ', '');
        console.log(message);
    }
});

The output after node index.js will be:

Latest Ethereum Block is:  46569344n
You cannot buy this package again.

The approach is the following:

  • Firstly, retrieve the original transaction (using the txHash)
  • Next, you should mock an RPC call (it will not update anything in the blockchain state, and is just a helper utility)
  • Finally then, catch the revert reason with the try { ... } catch (err) { ... } block

-> That way you get the revert error details, and eventually trim it to get the message thrown from the Solidity contract's code.


Here's the web (browser) version

const rpcProvider = 'https://rpc.ankr.com/polygon_mumbai';
const web3Provider = new Web3.providers.HttpProvider(rpcProvider);
const web3 = new Web3(web3Provider);


web3.eth.getBlockNumber().then((result) => {
    console.log("Latest Ethereum Block is: ", result); // confirm that the HTTP RPC provider has been instantiated properly
});

const txHash = '0x074e91fe5c1535d9bdc2bbc8cbadc0378c93eb06318401b1f341d844185430fb';

web3.eth.handleRevert = true;

web3.eth.getTransaction(txHash).then(async (tx) => {
    if (tx.gasPrice) {
        delete tx.maxPriorityFeePerGas;
        delete tx.maxFeePerGas;
    }
    try {
        let result = await web3.eth.call(tx, tx.blockNumber); // mock a call to reproduce the tx, otherwise it's hard to get the revert error from just the past tx hash'es logs

        console.log(result);
    }
    catch (err) {
        // the following transformations are necessary to remove the extra strings from the error object (the ones that mess up with the normal object type access)
        let errFlat = JSON.stringify(err);

        console.log(errFlat);

        const errParsed = JSON.parse(errFlat);

        message = errParsed.innerError ? errParsed.innerError?.message.replace('execution reverted: ', '') : errParsed.reason;
        console.log(message);
    }
});

The result is the following:

web3js-get-revert-message-of-from-the-past-transaction-transactions-browser-nodejs-web3


Conclusion:

  • In the NodeJS (server) environment, you should reference errObject.innerError.message to get the transaction's revert message
  • In the browser environment, just errObject.reason is sufficient :)

(Update) Taking a closer look, it's clear that the difference is due to that I used web3@ ^ 4.0.0 (4.5.0, to be specific), and Alireza has been using [email protected] via a CDN source. Hence the incompatible properties. https://docs.web3js.org/docs/guides/web3_migration_guide)

Therefore, the difference between the NodeJS and browser code snippet versions is that there's no difference if same versions are used across environments. 🙂

14
  • 1
    Thanks, It logs: x.html:120 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'message') Commented Mar 2 at 15:08
  • 1
    I am using Web3.js version 1.10.0, by this tag at the head of my html file: <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/web3.min.js"> After it I used all of your codes without the first line: const { Web3 } = require("web3"); Commented Mar 2 at 15:17
  • 1
    I used your RPC gateway: https://rpc.ankr.com/polygon_mumbai Commented Mar 2 at 15:18
  • 1
    Would you please to explain this command let { innerError : { message } } = ... so I can replace it with another code? What is innerError and message in this line? Commented Mar 2 at 15:24
  • 1
    - In the NodeJS (server) environment, you should reference errObject.innerError.message to get the transaction's revert message - In the browser environment, just errObject.reason is sufficient :)
    – Mila A
    Commented Mar 2 at 15:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.