Published on

Getting All Events Associated with an Account and Contract with Web3

Authors

When working on a dApp on Ethereum it is best practice to emit events in your contract when you make changes to the chain (add, update or delete). This generally occurs when there is a state modification as events cost gas to emit. Events cost gas as they are written to the chain but events are one of the cheapest forms of storage.

One thing you may want to do is get all the events for a given user against a contract. Doing this may seem simple but there are not very many examples on how to do this and the documentation does not give too much detail on what parameters are needed and how to do this. We cobbled this together after looking at different questions and answers as well as the documentation.

For our example we have:

  • YourContract: The contract we want to get events from.
  • TheEventYouWant: For illustrative purposes this event is simply fired when the user calls the fireEventOnSenderAddress function.
  • userAccountAssociatedWithEvent: This is the account we want to get the associated events for.

A simple contract for illustrative purposes has been included below.

pragma solidity ^0.4.24;

contract YourContract {

    event TheEventYouWant(address userAddress, uint8 someNumber);

    function fireEventOfSenderAddress() external {
      emit TheEventYouWant(msg.sender, random());
    }

    // based on https://medium.com/@promentol/lottery-smart-contract-can-we-generate-random-numbers-in-solidity-4f586a152b27
    // this gives us a random number between 0 to 251 inclusive
    function random() private view returns (uint8) {
      return uint8(uint256(keccak256(block.timestamp, block.difficulty))%251);
    }
}

To get all events in this contract related to this user use the following code:

YourContract.events.TheEventYouWant(
  {
    address: userAccountAssociatedWithEvent,
    fromBlock: 0,
    toBlock: 'latest',
    filter: { someNumber: [3, 6, 9] },
  },
  (error, event) => {
    if (error) {
      console.log('Error!')
      console.log(error)
    } else {
      console.log('Event :)')
      console.log(event)
    }
  }
)

Some key things to note in this piece of code:

  • filter: This is a JSON object that has the specific event parameters you are trying to match for with values you want.
    • In my case I said I want to match on any TheEventYouWant events that have someNumber with the value 3, 6 or 9.
  • fromBlock: This is the first block on the chain you want to match until
    • We set this to the first block ie. the first block since the inception of the chain.
  • toBlock: This is similar to fromBlock except that we specify the last block on the chain you want to match until.
    • We set this to latest so we get all recent events.
  • address: This is the address of the account we want to get all events for (in relation to this contract)
    • If you leave out the address portion it will give you all TheEventYouWant events from the YourContract irrespective of the user.

As we have no errors this will output something like:

Event :)
{
  "logIndex": 0,
  "transactionIndex": 0,
  "transactionHash": "0x84bc1f1ca064bd26ba738012f7eab5d33495614b7077a54fc402a365a98d612e",
  "blockHash": "0x21731db7c35879e637131a4492d207fec90cc3b4d208329ec39dc2d249df3421",
  "blockNumber": 7,
  "address": "0x097504E321b0e49113a8B53BaA35a47ca475a900",
  "type": "mined",
  "id": "log_69aa0356",
  "returnValues": {
    "0": "0x23aA8d66F6dc87B9514893D1637a629F53B4617B",
    "1": "3",
    "userAddress": "0x23aA8d66F6dc87B9514893D1637a629F53B4617B",
    "someNumber": "3"
  },
  "event": "TheEventYouWant",
  "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
  "raw": {
    "data": "0x0000000000000000000000000000000000000000000000000000000000002710",
    "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x00000000000000000000000023aA8d66F6dc87B9514893D1637a629F53B4617B"
    ]
  }
}

You can read up more on this here.