[Ethereum] Web3.js eth.subscribe: on(‘changed’, function(event){}) doesn’t work with Metamask

chain-reorganizationdappsgo-ethereummetamaskweb3js

I write a demo DApp website with this javascript

    const web3 = new Web3(ethereum);
    const contractAddr = "0x0Aa27e4B13D5c08A8767B36a0ACb76ED4549B7EA";
    const abi = ...;

    let inst = new web3.eth.Contract(abi, contractAddr);
    web3.eth.subscribe('logs', {
        address: contractAddr,
    }, function (error, result) {
        if (!error)
            console.log(result);
        else
            console.log("default:", error);
    })
        .on("connected", function (subscriptionId) {
            console.log(subscriptionId);
        })
        .on("data", function (log) {
            console.log("data:", log);
        })
        .on("changed", function (log) {
            console.log("changed:", log)
        }).on("error", function (log) {
            console.log("err:", log);
        });

In the code I use ethereum (which is window.ethereum provided by MetaMask) as the Provider for Web3.js.

My MetaMask is connected to a private blockchain called node1 using Geth on localhost:8545. In the meantime I have another Geth node called node2.

At the beginning, node1 and node2 were not connected. I sent and mined a transaction to node1 to the contract at contractAddress which would emit events and I indeed got console logs in the browser as a result of my subscription to 'logs'.

Then I let node2 mine more blocks than node1 and after that, I connected them. This will trigger node1 chain reorganization. After reorg, the reverted transaction was left in the txPool and I didn't mine any more blocks.

As is specified in web3.js documentation, I expected console.logļ¼ˆ"changed:", log) to be executed but it didn't.

At the same time, I also used low-level Json-rpc method eth_getFilterChanges and did get a log with "removed": true field, which means the transaction was indeed reverted.

I think web3.js should have notice this and execute on('changed') callback. But why does web3.js not work here? Since web3.js cannot subscribe logs directly using HTTP ethereum provider, and MetaMask uses HTTP connection to ethereum, does this problem have something to do with MetaMask?

BTW: I'm using web3.js v1.2.6

Best Answer

for me this did also not work and I do not know why, but I found the following solution using web3.
As web3 from Metamask will be deprecated I get web3 not from Metamask, but through:
web3 = new Web3(Web3.givenProvider);

then setting up the event listener somewhere else later on in the code:
web3.eth.Contract(TokenABI, TokenAddress);

try {

eventHandlerTransfer = await contract.events.Transfer({ fromBlock: 0 }, function (err, data) {
//INFO: your data will be accessable at e.g.
data.returnValues._from
if(err) {
console.log(err);
}
});

}catch (error) {
console.log(error);
}

This is written using "async function() {" style....

Hope this helps. Happy async coding...