How to capture an event value with web3 js

I have this contract:

// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity 0.7.4;

contract CoinFlip {
  uint public contractBalance;
  address owner;

  constructor() {
    owner = msg.sender;
    contractBalance = 0;
  }

  modifier onlyOwner {
    require(msg.sender == owner);
    _;
  }

  event WinOrLose(bytes4 coinSide);

  // 0 is HEADS and 1 is TAILS
  function bet(uint chosenSide) public payable {
    // Must be no less than 0.01 ETH and no more than 10 ETH in value
    require(msg.value >= 10000000000000000 && msg.value <= 10000000000000000000, "Improper amount entered.");

    // Contract must have enough funds to cover paying the bet, if won - plus some extra for gas
    contractBalance += msg.value;
    require(contractBalance >= msg.value * 2 + 100000000000000000, "Sorry, the contract cannot cover this bet.");

    uint side = block.timestamp % 2;
    bytes4 result;

    if (side == chosenSide) {
      result = "won";
      uint winnings = msg.value * 2;
      contractBalance -= winnings;
      (bool success, ) = msg.sender.call{value: winnings}("");
      require(success, "Ether send failed");
    } else {
      result = "lost";
    }
    emit WinOrLose(result);
  }

  fallback() external payable {}
  receive() external payable { contractBalance += msg.value; }

  function withdrawAll() public onlyOwner returns(uint) {
      uint toSend = address(this).balance;
      contractBalance = 0;
      (bool success, ) = msg.sender.call{value: toSend}("");
      require(success, "Ether send failed");
      return toSend;
  }

}

And this is the JS file I am using to interact with it.

var web3 = new Web3(Web3.givenProvider);
var contractInstance;

$(document).ready(function() {
    window.ethereum.enable().then(function(accounts){
      contractInstance = new web3.eth.Contract(abi, "0x6B966608067c98A74c782e521e0d4f7FEd238250", {from: accounts[0]});
      console.log(contractInstance);
    });

    $(document).on("click", "#flip_button", function() {
      var amount = $("#amount_input").val();
      $("#amount_input").val(null);
      var choice = $("input[name='flipping']:checked").val();

      var config = {value: web3.utils.toWei(amount, "ether")};

      contractInstance.methods.bet(choice).send(config)
      .on('error', console.error);
    
    });
});

I am trying to figure out how to capture my emitted event value after the ‘methods.bet’ function is executed. Have tried several things but nothing seems to work.

1 Like

Hi @CryptoEatsTheWorld,

Front end is not an area of expertise for me.

I suggest having a look at the web3 documentation for listening for events:

As an aside, you may also want to look at the section on event logs: Falsehoods that Ethereum programmers believe

Yes I have been looking at that documentation and attempting to do this, but I am struggling with it, which Is why I was asking for some help.

1 Like

Here is my updated JS file showing what I am trying. No errors, but nothing shows up in the console.

var web3 = new Web3(Web3.givenProvider);
var contractInstance;

$(document).ready(function() {
    window.ethereum.enable().then(function(accounts){
      contractInstance = new web3.eth.Contract(abi, "0x6B966608067c98A74c782e521e0d4f7FEd238250", {from: accounts[0]});
      console.log(contractInstance);

    });

    $(document).on("click", "#flip_button", function() {
      var amount = $("#amount_input").val();
      $("#amount_input").val(null);
      var choice = $("input[name='flipping']:checked").val();

      var config = {value: web3.utils.toWei(amount, "ether")};

      contractInstance.methods.bet(choice).send(config)
      .on('error', console.error);

      contractInstance.events.WinOrLose({
      filter: {coinSide: ['won', 'lost'],}, // Using an array means OR: e.g. 20 or 23
      fromBlock: 0
      }, function(error, event){ console.log(event); })
      .on('data', function(event){
      console.log(event); // same results as the optional callback above
      })
      .on('changed', function(event){
      // remove event from local database
      })
      .on('error', console.error);

    });

});
1 Like

OK, I changed my event js code to this:

contractInstance.methods.bet(choice).send(config) .once('transactionHash', function(hash){ }) .once('receipt', function(receipt){ }) .on('confirmation', function(confNumber, receipt){ }) .on('error', function(error){ }) .then(function(receipt){ contractInstance.events.WinOrLose({}) .on('data', function(returnValues){ console.log("Result" + returnValues.coinSide); });

Don’t see anything in the console. Which I think means the event isn’t firing from the contract but not sure.

Any advice?

1 Like

Alright so I worked it out. First of all, I found comments on another forum that apparently web3js subscription functionality does not play well with http provider.

Second of all, my event wasn’t firing at all in Ganache. Not sure why.

So what I did was deploy my contract to Kovan testnet and then I could see the event firing. Then I used the following code to catch the event from the transaction receipt (instead of subscription).

contractInstance.methods.bet(choice).send(config)
        .once('transactionHash', function(hash){ })
        .once('receipt', function(receipt){ })
        .on('confirmation', function(confNumber, receipt){ })
        .on('error', function(error){})
        .then(function(receipt){
        
          var myevent = receipt.events.WinOrLose.raw.topics[1];
          var eventDecoded = web3.utils.hexToUtf8(myevent);
          if (eventDecoded == 'won') {
            alert('YOU HAVE WON!');
          } else {
            alert('SORRY, YOU LOST.');
          }
1 Like

Hi @CryptoEatsTheWorld,

Glad you got something working. I think medium term you may need to listen for events rather than using the transaction hash.

You may want to look at using https://github.com/PaulRBerg/create-eth-app to start your app.

You may also want to consider using a service such as The Graph to read events.

Unfortunately front end development isn’t an area of expertise.

Thanks, will check those out.

I actually moved on and completed phase 2 of the Coinflip project, in which I DID have to listen for events.

In phase 1 we used pseudo-randomness and so everything happened in one transaction, which is why I could grab the event from the receipt.

However in phase 2 the dapp was more complicated because we needed to use the Provable solidity contract/API to get a real random number. In that case the event didn’t come until later, after getting a callback from the oracle. So I had to work out how to listen for an actual event.

I eventually settled on this code for that. Perhaps someone else might find it helpful:

contractInstance.methods.bet(choice).send(config)
.once('transactionHash', function(hash){ })
.once('receipt', function(receipt){ })
.on('confirmation', function(confNumber, receipt){ })
.on('error', function(error){})
.then(function(){
  var account = web3.eth.accounts[0];
  contractInstance.once('WinOrLose', {
      filter: {user: account},
      fromBlock: "latest"
  }, function(error, event){
      if (error) {console.log(error)}
      else {
        var eventDecoded = web3.utils.hexToUtf8(event.returnValues.flipResult);
        if (eventDecoded == 'won') {
          alert('YOU HAVE WON!');
        } else {
          alert('SORRY, YOU LOST.');
        }
      }
  });
});
1 Like