Listen Solidity Events in Python

Listen to Solidity events in python

Events are used to inform a calling application about the current state of a smart contract. You can read more about the event by clicking on this link how to use events in solidity. In this post, we will talk about how to listen to solidity events in python. Let’s write some code.

				
					// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract CodiesAlert {
    
    event showData(address indexed addressId, uint indexed _age, string city);

    function display(address _addressId, uint _age, string memory _city) public {
        emit showData(_addressId, _age, _city);
    }
}
				
			

In our showdata event, addressId and age are indexed but the city variable is non-indexed because EVM will store the keccak256 hash of our city which is of no use for us. As we discussed in our events post, EVM will always store the hash of reference type variables instead of storing their original value. If you want to store the reference type like an array, string, bytes in events logs then you need to mark them non-indexed but we can still read them by using the indexed variable. 

Listen to Events

CodiesAlert contract is already deployed on rinkeby network and now we will see how to listen to the showData event. 

  1. First we need the contract address which is “0x0845d45E1D8b2e4c7583623Bed34b6D59Da0fBA3” in my case.  Since I have deployed the contract using the brownie framework so I can access the contract abi via brownie instead of using web3 but you can use any. If you want to use brownie here is the installation guide.
  2. The second step is to get the contract abi. Line numbers 20 to 25 is just to get the brownie contract object which is needed to get the contract abi.
  3. Create the web3 contract object in line number 27. Brownie contract and web3 contract objects are different here. We are using web3 to listen to the events.
  4. In line number 50, we are listening for all the events emitted by showData event. This will immediately print the event log as soon as someone calls the display function. There are various other filters that you can use apart from “latest”  block filer. You can read about them here
				
					from web3 import Web3
import asyncio
from brownie import network, Contract
import os
from dotenv import load_dotenv
# Load environment variables 
load_dotenv()

# Create Infura Connection
# define "INFURA_PROVIDER" in your .env file
web3 = Web3(Web3.HTTPProvider(os.getenv("INFURA_PROVIDER")))

# contract Address
contractAddress = '0x0845d45E1D8b2e4c7583623Bed34b6D59Da0fBA3'

# Connect to rinkeby network
# doing this step just to read the Contract abi 
# file but you can read the abi file manually with web3. py as well

try:
    network.connect('rinkeby')
except Exception as e:
    print(e)
    
token = Contract(contractAddress)

contract = web3.eth.contract(address=contractAddress, abi=token.abi)

# define function to handle events and print to the console
# You can also setup any action after listening to the event
def handle_event(event):
    print(Web3.toJSON(event))


# asynchronous defined function to loop
# this loop sets up an event filter and is looking for new entires for the "PairCreated" event
# this loop runs on a poll interval
async def log_loop(event_filter, poll_interval):
    while True:
        for PairCreated in event_filter.get_new_entries():
            handle_event(PairCreated)
        await asyncio.sleep(poll_interval)


# when main is called
# create a filter for the latest block and look for the "PairCreated" event for the uniswap factory contract
# run an async loop
# try to run the log_loop function above every 2 seconds
def main():
    event_filter = contract.events.showData.createFilter(fromBlock='latest')
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(
            asyncio.gather(
                log_loop(event_filter, 2)))
    finally:
        # close loop to free up system resources
        loop.close()


if __name__ == "__main__":
    main()
				
			

Now when someone calls display function you will be able to listen to the event. First, run the above script and it will start listening for the events. 

The next step is to call the display function with expected parameters. I am using brownie again to call the display function and here is the script. I am running scripts side by side so it was throwing a “Already connected to the network” error. You can either run it in try except block or comment it if you get the same error. 

				
					from brownie import Contract , accounts
from dotenv import load_dotenv
load_dotenv()

def main():
    account = accounts.add(os.getenv("PRIVATE_KEY"))
    # network.connect('rinkeby')
    token = Contract('0x0845d45E1D8b2e4c7583623Bed34b6D59Da0fBA3')
    print(token.display('0xF3cbcD528bb67C0EE3fCBE8e160828bF6fdbf92a', 30, "New York1", {"from":account}))
    # network.disconnect()
    
main()
   
				
			

Here are the event logs printed as soon as the display function was called. As you can see the city name “New York1” is printed instead of the hash because it was declared non-index. You can run a test by setting the city variable to indexed and you will get the hash of the city name instead of the string data.

Let me know the comment section below if you run across any issues.

				
					{"args": {"addressId": "0xF3cbcD528bb67C0EE3fCBE8e160828bF6fdbf92a",
"_age": 30, 
"city": "New York1"}, 
"event": "showData", 
"logIndex": 65, "transactionIndex": 43, "transactionHash": "0x1ae6b646ff681f0129c977fc4d2e60d81a79063ac027bff7879698e399b35250", "address": "0x0845d45E1D8b2e4c7583623Bed34b6D59Da0fBA3", "blockHash": "0x46a2c525357dd214edcad4ba6e85e54f673e43bc649079aeaede74cf7d62ef3f", "blockNumber": 10131181}
				
			

Leave a Reply

https://www.linkedin.com/company/77619036/admin/

welcome.

We connect you to a world of houseplants and urban gardening tailored to your home

Bloomer

Login to your account