6

I'm experimenting with plugging Ethereum into a React web application, using this nice tutorial repo as a basis (thanks to uzyn): https://github.com/uzyn/ethereum-webpack-example-dapp

I'm connecting successfully to the local TestRPC 3.0.3 instance, have a Solidity 0.4.8 "MyToken" contract deployed and am mining a contract function called "transfer" successfully. I know the transfer is running just once from the updated account balances but I'm getting two instances of the "Transfer" event coming up in my browser console. If I take out the line emitting the event, I get nothing in the console.

Could anyone suggest why that is? Thanks!

I'm calling this contract function which emits an Event:

/* Send coins */
function transfer(address _to, uint256 _value) {

    if (balanceOf[msg.sender] < _value) throw;           // Check if the sender has enough
    if (balanceOf[_to] + _value < balanceOf[_to]) throw; // Check for overflows
    balanceOf[msg.sender] -= _value;                     // Subtract from the sender
    balanceOf[_to] += _value;                            // Add the same to the recipient

    Transfer(msg.sender, _to, _value);                   // Notify anyone listening that this transfer took place
}

With this code block:

  MyTokenContract.transfer.sendTransaction(
    web3.eth.accounts[1],
    100,
    (error, result) => {
      if (error) {
        console.log(`Error occurred: ${error}`);
        return;
      }

      const accountOneBalance = MyTokenContract.balanceOf(web3.eth.accounts[0]);
      const accountTwoBalance = MyTokenContract.balanceOf(web3.eth.accounts[1]);

      console.log(`accountOneBalance: ${accountOneBalance}`);
      console.log(`accountTwoBalance: ${accountTwoBalance}`);
    }
  );

And I have this Web3 code listening for contract events:

MyTokenContract.allEvents((error, event) => {
if (error) {
  console.log(`Event error: ${error}`);
  return;
}

const eventName = event.event;
const accountFrom = event.args.from;
const accountTo = event.args.to;
const amount = event.args.value;
console.log(`Event '${eventName}' from account ${accountFrom} to ${accountTo} of ${amount}`);

});

When it runs, I get two events logged in my Chrome console:

accountOneBalance: 249900
accountTwoBalance: 100
Event 'Transfer' from account 0xdd0efd8df206cb598bda146ae567f5d398436226 to 0x7497ac386ae2e1eb58210d08e6c401b56417e04d of 100

Event 'Transfer' from account 0xdd0efd8df206cb598bda146ae567f5d398436226 to 0x7497ac386ae2e1eb58210d08e6c401b56417e04d of 100
  • If you double the line in transfer where it creates the event (thus creating two events) how many events does it now log? Three? Four? I have a hunch this might help you debug. – Matthew Schmidt Apr 22 '17 at 20:06
  • Thanks for the suggestion, it's a good idea. I'm still hoping it's not a stupid logic bug :) So, when I add an extra event and make the logged values "1" and "2" respectively, it prints 1,2,1,2. Maybe it has something to do with the way React loads a page. I'll investigate further when I have time and post an update, unless there's another suggestion. Thanks! – John G Apr 23 '17 at 20:59
  • must be a web3 error, did u ever find a way around this? – 0TTT0 Mar 25 at 17:29
2

I had the same issue and the above solution didn't work in the case that if the testrpc is running and having already triggered some events, then starting the Web3 code the watch returns the latest event that was triggered. What solved the problem and get only new events is:

var latestBlock = web3.eth.blockNumber; //get the latest blocknumber
contractInstance.MyEvent({fromBlock: latestBlock}, (error, event) => { 
    if (error) {
     console.log(error); return; 
    } else {
        if(event.blockNumber != latestBlock) {   //accept only new events
        console.log(event);
        latestBlock = latestBlock + 1;   //update the latest blockNumber
        }
    }

Hope that helps!

1

this worked for me

MyTokenContract.allEvents({fromBlock:'latest'}, (error, event) => { if (error) { console.log(Event error: ${error}); return; }

Even though the docs say 'latest' is default, This fixed my duplicate events firing. I wasn't using allEvents. I was watching just one event on the contract.

hope it helps.

0

I did exactly what was done above. I was catching my original event like this:

  this.buyEvent = this.$store.state.web3contract.BuyTransaction({},{fromBlock: 0, toBlock: 'latest'});
          this.buyEvent.watch(function(err,res){
console.log(res);
console.log(err);
})

To fix double firing I put this extra piece of code and it solved my problem.

  this.$store.state.web3contract.allEvents({fromBlock:'latest'}, function (error,event){
    if (error) {
      console.log(error)
    } else {
      console.log("All Events")
      console.log(event);
    }
  })

It must be some bug in web3 or I don't know what it is. I am sure I don't register watch function twice. Would be great if somebody can confirm if this is a web3 bug.

0

I still had this happen in March of 2019, I solved it by making a Set in my javascript and adding blockNumbers to it in my callback to ensure no duplicates were allowed..

var eventBlocks = new Set()

listenCallback = async (error, event, type) => {
  if (error) { console.log(error); }
  else {
    let blockNumber = event.blockNumber;
    if (eventBlocks.has(blockNumber)) return;
    eventBlocks.add(blockNumber);
    //do everything else you want to do
  }
}
  • I test with ropsten testnet, and the blockNumber is not the same on 2 duplicate event: 5777243 and 5777244 – Justin Jun 12 at 4:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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