🧰 Web3 [Serie Part 7/10] - Listen to Smart Contract Events
Henri Rion -
Introduction
What is an Event?
An event emits data from a Smart Contract, when a transaction occurs.
This is useful when you need to monitor certain transactions and update your Web App, for instance.
It’s important to note that events are inheritable, and when generated they are not accessible from within contracts, not even the one which has created and emitted them.
If you need more details, have a look to the Solidity's events doc, here.
In the next sections we will go through 3 methods to read/listen to events.
Method 1 - Trigger Emit Event via a Transaction
In our contracts directory, we create a new file called MyContract3.sol . Here is the Smart Contract we will be using. Comments are following.
In this solidity script, we are defining a function called Payment. This payment function is simulating a token transfer from an address to another, and will emit an Event when the function is called.
Thus, we define an event called MyPayment first. Each 'MyPayment' event will include 4 parameters:
Date: the date when the event occured (integer in Solidity)
"You can add the attribute indexed to up to three parameters which adds them to a special data structure known as “topics” instead of the data part of the log. [...] Topics allow you to search for events, for example when filtering a sequence of blocks for certain events."
Now, we can add the MyContract3.sol in our migration file 2_contract_deploy.js.
Here is the updated migration file:
Now, we can run the truffle migrate command to deploy our new MyContract3 to our local Blockchain.
We can see that our MyContract3.sol has been successfully migrated thanks to the output in terminal:
Now, we can move on with our JS Script. Let's create a new index, called index3.js. Here is the code to paste in. Comments are following.
First, we import our MyContract3. Then, create our web3, and contract instances.
Next, we get the accounts addresses from Ganache, and finally we call our new 'payment' method. As defined in our MyContract3.sol, we input the 2 required parameters (from and amount), and we send the transaction.
In our Terminal, we can see the following output, since we console.logged our receipt.events.
We can read the MyPayment event, the name of our event.
Then a few lines below, we can read the date, the from & to addresses, and finally the amount.
It works! Great!
👎 Limitations
Thus, this option works great, but it has a limit. You need to be the sender of the transaction to read the event. Most of the time, it will not happen this way.
In most cases, we will need to read events triggered by other people.
Let’s move on to the next method.
Method 2 - getPastEvents
This method allows us to read all the events that occurred from a Smart Contract. We will still using our MyContract3.sol for this method. The only changes are made in our index3.js file.
(Before going, further, we will restart our Ganache Local Blockchain. Otherwise we will have noises in the events we will display. Don't forget to perform the migration using truffle).
In this script, we call twice the payment methods, and thus we emitted twice an event.
At the end, we call the getPastEvents method. As we can see, we ask for 'allEvents', and we want to search from the block 0, i.e. since the beginning. The 'allEvents' could have been replaced by the name of our event, which would have been 'MyPayment' in this case. You can try to replace 'allEvents' by 'MyPayment', and you will see the same output, including 2 additional events.
More info about getPastEvents method in web3 docs here.
👎 Limitations
Asking to check events from block 0 on the Mainnet would take some time, since it has to scan all the blocks looking for our events.
By default, the getPastEvents method is looking in the ‘earliest’ block (cf. doc here). Thus, to retrieve all events, we have to check from the initial block (fromBlock: 0). If we don’t define the block parameter, we will get the events from the earliest block (you can try ;-)).
☝️Alternative
It’s possible to filter on specific event’s parameters, by adding the filter key to the getPastEvents method.
In that case, you will also need to indicate the name of the event.
Example including a filter on the 'to' parameter:
To be able to use specific parameters as filters, we need to add the ‘indexed’ key in our Smart Contract.
The indexed variables must be chosen widely since we are limited to a maximum of 3.
From the Solidity doc:
"You can add the attribute indexed to up to three parameters which adds them to a special data structure known as “topics” instead of the data part of the log".
"A WebSocket is a persistent connection between a client and server. WebSockets provide a bidirectional, full-duplex communications channel that operates over HTTP through a single TCP/IP socket connection. At its core, the WebSocket protocol facilitates message passing between a client and server".
I got this nice definition from this great article, which I recommend if you need more information about the subject.
The advantage of using WebSocket is that we can monitor events in real-time. To simulate this, we will use 2 different scripts. The first script will be listening to event in real-time, while the second script will trigger events.
What we will achieve:
Again, we will relaunch Ganache to get a clean blockchain (don't forget to migrate again using Truffle).
truffle migrate --reset
Script 1
We create the 'listener.js' script. Comments are following.
Instead of using new Web3( 'Ganache address' ), we know use the WebsocketProvider.
At the end, we launch a 'listener' console.logging events when they occur.
We launch listener.js in a Terminal 1. You should see a script waiting.
Script 2
Our second script 'events.js' will be quite similar as the one used in the 2 previous methods, since it will only trigger twice the same events.
Here is the code. Comments are following.
The only additional part is the 'sleep' method for 5 sec.
We are launching this script in a second terminal.
Now, we see the results: 1 event occurs live, then 5 sec later, the second one is displayed.
Hurra! It works! We successfully use 3 differents methods to listen to Smart Contract's events ! Congrats!