36

I use the following JS code to get notified of Solidity events and it works well for incoming new events:

myContract.myEvent().watch((error, result) => {
  if (error)
    console.log('Error in myEvent event handler: ' + error);
  else
    console.log('myEvent: ' + JSON.stringify(result.args));
});

I would like to use the same code for initializing the JS app on startup. e.g. I start the JS app on block 100 but there were already some events fired at block 20 and 30. These two past events are not being processed with the code above. As alternatives, I also tried via

myContract.myEvent((error, result) => {

and

myContract.myEvent({fromBlock: 0, toBlock: 'latest'}, (error, result) => {

Still these two options don't give me past events.

3
  • You need an extra {} in the parameter as demonstrated in ethereum.stackexchange.com/a/4453/1268 Commented Feb 2, 2017 at 15:45
  • thanks, this gets me one step closer but still I only get a single result (the very first event that got fired) when using drelContract.PropertyAdded({}, { fromBlock: 0, toBlock: 'latest' }).get((error, result) => { console.log('!!! event handler: ' + JSON.stringify(result));});
    – SCBuergel
    Commented Feb 2, 2017 at 16:09
  • Somehow, I am not getting any data back when using "get". I tried "getPastEvents" in web3.js version 1 and that worked, but web3 version 1 conflicts with just about every other web3 and eth JavaScript library, so I couldn't use it in the application.
    – Greg S
    Commented Oct 22, 2017 at 23:34

6 Answers 6

11

Seeing as there isn't a detailed updated answer:

As @pors mentioned, web3.js has a getPastEvents function. You can have it run at startup, using a syntax like:

myContract.getPastEvents('MyEvent');

The docs for this function are here. You can also filter by a specific topic, set a range of blocks to check, and more. Here's an expanded example, taken straight from the docs linked above:

myContract.getPastEvents('MyEvent', {
    filter: {myIndexedParam: [20,23], myOtherIndexedParam: '0x123456789...'}, // Using an array means OR: e.g. 20 or 23
    fromBlock: 0,
    toBlock: 'latest'
}, function(error, events){ console.log(events); })
.then(function(events){
    console.log(events) // same results as the optional callback above
});

This will not continue listening for events to the best of my knowledge. You could do this with events, however:

MyContract.events.MyEvent()

The function takes an object with parameters as an argument, much like getPastEvents(), see the docs here for more details. Based on the question, this would seem to be the best fit for the OP's particular use case.

(There is a similar function called allEvents for subscribing to all events from a particular contract - docs)

@pors also suggests using subscribe to get past events, and to continue to listen for new events. The docs are here. Note that you'll need to provide the topics you want to listen for. (Here's an explainer for event topics, you can get the topic for your event by hashing the event signature (eg Transfer(address,address,uint256) of the event with keccak256).

1
  • 1
    This question was asked ages ago and web3.js changed a lot, I'm marking this as the correct answer given that most others are fairly outdated. Thanks for the details and references!
    – SCBuergel
    Commented Jul 8, 2021 at 20:54
29

I finally figured out how to properly use .get() mentioned in the answer by Roland:

myContract.myEvent({}, { fromBlock: 0, toBlock: 'latest' }).get((error, eventResult) => {
  if (error)
    console.log('Error in myEvent event handler: ' + error);
  else
    console.log('myEvent: ' + JSON.stringify(eventResult.args));
});

Worth mentioning that the eventResult object is an array containing one entry per event call:

[{
    "address": "0x80d346f14eb1bb47bc112b066f74ceb5e0a07c78",
    "blockNumber": 180173,
    "transactionIndex": 1,
    "transactionHash": "0x2c34b00a9b137a506afc6b80ccf159858415c48f403d357c35e509a03fe4c8bc",
    "blockHash": "0xc737758878120a70ed5f9d4fb412fc05231fbe5473e87e6f2194361537b85a4f",
    "logIndex": 2,
    "removed": false,
    "event": "myEvent",
    "args": {
        "id": "1"
    }
}, {
    "address": "0x80d346f14eb1bb47bc112b066f74ceb5e0a07c78",
    "blockNumber": 180179,
    "transactionIndex": 1,
    "transactionHash": "0x6372cc429ffe28c717f7e26c100da2e7395bd23ac466da20643299dfe57ed380",
    "blockHash": "0xcc6c13043ceeab8a3c5dbf4f4937b7e3d02c614256615cb8c3b63fdcb46f0d0a",
    "logIndex": 2,
    "removed": false,
    "event": "myEvent",
    "args": {
        "id": "2"
    }
}]
2
  • 4
    Trying to do the same for my contract and get nothing. Calling JSON-RPC directly works fine. Do I miss something? contract.NewSale({}, {fromBlock: 0, toBlock: 'latest'}).get((err, log) => {console.log(err, log)}) Commented Jul 13, 2017 at 22:04
  • how can i do this in version 0.18.2
    – shorif2000
    Commented Apr 24, 2018 at 19:47
12

Instead of .watch() use .get(). Can be lagging a bit, because events are not saved in the state-trie, behind the curtain it will scan all blocks, therefore you might give it a fromBlock

fromBlock: Number|String - The number of the earliest block (latest may be given to mean the most recent and pending currently mining, block). By default latest.

https://github.com/ethereum/wiki/wiki/JavaScript-API#parameters-29

1
  • same as in the comment above, gets me a single entry only. See code in my comment to BokkyPooBah's comment.
    – SCBuergel
    Commented Feb 2, 2017 at 16:12
5

Works on [email protected]:

  MyContract.events.MyEvent({}, { fromBlock: 0, toBlock: 'latest' }).on(
    'data', function(event) {
    console.log(event);
  }).on('error', console.error);
1
  • on my case it worked with: MyContract.events.MyEvent({ fromBlock: 10, toBlock: 200 }), that solution is not using fromBlock and toBlock i guess is using only lastest, because when i used it with old history it keep to receive the latest events.
    – tbem
    Commented Aug 19, 2021 at 17:59
1

With web3.js version 1.0 there are two more ways to get past events:

The first option keeps on listening for new events. If you are just looking for all past events, getPastLogs is sufficient.

0

If you get an array of objects as your result:

[object Object],[object Object],[object Object],[object Object],[object Object]...

then you need to extract the key value pair of "args" inside the objects:

    var event1;
    for(var i = 0; i < result.length ; i++){
      event1 = JSON.stringify(result[i].args);
      document.getElementById("TxAllEvents").innerHTML += event1;
    }

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.