Skip to content
Advertisement

How to configure to handle CORS errors in web3 connecting to ganache

I have a react project I am running at http:\localhost:3000 which connects to ganache running at http:\localhost:7545.

I deploy a small smart contract onto ganache which increments a counter and emits an event, like this…

// SPDX-License-Identifier: MIT
pragma solidity >0.8.0;
contract Pong {
    uint public pong_count;
    function ping() public returns (uint){
        pong_count++;
        emit Pinged(this, pong_count);
        return pong_count;
    }
    event Pinged(Pong indexed me, uint count);
    function pong() public returns (uint){
        pong_count++;
        emit Ponged(this, pong_count);
        return pong_count;
    }
    event Ponged(Pong indexed me, uint count);
}

I want to listen to the Pinged and Ponged events from my contract.

As this is just a helper project for something else I am working on I embed the private key from a ganache account and make an account from it…

var pk_account = w3.eth.accounts.privateKeyToAccount(pk);

Then elsewhere in my code I create an instance of my Pong contract called ponger and store it on a context object in my react app, and invoke the ping() contract method using send like this…

            ctx.ponger.methods
            .ping()
            .send({from:ctx.pk_account.address})
            .then((result,err)=>{
                if (err){
                    console.log("pong error: ", err);
                }
                else {
                    console.log("pong : ", result);
                    result.gas = 200000;
                    ctx.pk_account.signTransaction(result, sent);
                }
            });

This works like a charm and the local callback sent gets invoked correctly.

I add event listeners to my ponger instance…

function ev_Pong(ev, err){
    console.log("got pong event", ev);
}
function ev_Ping(ev, err){
    console.log("got ping event", ev);
}

ctx.ponger.events.Pinged(ev_Ping);
ctx.ponger.events.Ponged(ev_Pong);

This is where the fun starts. The message I receive back in ev_Ping is…

got ping event Error: The current provider doesn't support subscriptions: HttpProvider
    at subscription.js:176:1

So, duh, I need to use websockets instead of HTTP, right? That means I just connect to ws:\localhost:7545 instead of http:\localhost:7545.

(Aside: I do not have any of these issues if I use MetaMask to deliver me web3…)

However I then get a CORS error like this…

Access to XMLHttpRequest at 'ws://localhost:7545/' from origin 'http://localhost:3000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.

So my question is how do I overcome the CORS error? I am not sure if this is a ganache question or an old fashioned CORS question, or what.

I don’t want to give up on event listening and having to parse through event logs just yet – although I realise there probably is a long route to a different solution.

Advertisement

Answer

I figured out what was wrong and it was my fault. The web3 websocket provider does not enforce CORS so it can be used in my use case.

The issue I was having was that even though I change the protocol in the URI I sent web3, I was still asking for an HTTPProvider instead of a WebsocketProvider.

I made a few changes to getWeb3.js for my purposes like this…

const getWeb3 = (url) => {

...

      if (url){
        if (url.substring(0,2) === 'ws'){
          const provider = new Web3.providers.WebsocketProvider(url);
          const web3 = new Web3(provider);
          console.log("Using WS URL for web3: ", url);
          resolve(web3);  
        }
        else {
          const provider = new Web3.providers.HttpProvider(url);
          const web3 = new Web3(provider);
          console.log("Using HTTP URL for web3: ", url);
          resolve(web3);  
        }
      }

...
}

This worked fine.

On the plus side it made me understand CORS a lot better. I really don’t like disabling anything in the browser.

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement