How to emit and capture events in Solidity
Published
Table of contents
Events to interact with decentralized web apps
Solidity smart contracts can emit events to communicate that something has happened on the blockchain. Web applications or any kind of application (like a mobile app or a backend job) can listen to these events and take actions when they happen.
If you've used a decentralized exchange (or DEX) like Uniswap or Pancakeswap, or any other web3 application, you've probably seen events in action in loading buttons and popup messages when transactions are confirmed. These are usually events triggered from a smart contract and captured by the web application.
How to emit events from a smart contract
The first thing we need to do is to declare the event with the Event
keyword. Events can send multiple parameters so we have to include these in the event definition (don't forget to include the type as well!). The event definition below will just have a boolean variable as payload:
// declare an event that sends two parameters
event LotteryEvent(bool isWinner, address indexed player);
In the event definition you can also indicate if any of the parameters will be indexed with the indexed
keyword. Indexed parameters can be used to filter event logs.
To emit or send an event from our smart contract, we'll use the emit
keyword followed by the event name and the payload that it'll send. It's very similar to calling a function:
uint256 secretNumber = 99;
function playLottery(uint256 _number) public {
if(_number != secretNumber){
// send the event
emit LotteryEvent(false, msg.sender);
}else{
// send the event
emit LotteryEvent(true, msg.sender);
}
}
See below a full example of a very basic smart contract game. There is secret number stored in the contract and users would be able to guess it by calling the guessNumber()
method. The contract will trigger an event whether they correctly guess the number or not.
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;
contract LuckyNumber {
// state variable to store secret number
uint256 secretNumber;
// set the secret number on deploy
constructor() payable {
secretNumber = 33;
console.log("The secret number is %s", secretNumber);
}
// declare the event with the payload to send
event LotteryEvent(bool isWinner, address indexed player);
//
function guessNumber(uint256 _number) public payable {
if (_number != secretNumber) {
// EVENT
emit LotteryEvent(false, msg.sender);
}else{
// EVENT
emit LotteryEvent(true, msg.sender);
}
}
}
Capture events in web3 application
Once we have a smart contract that emit events, we can listen to them from a web3 application.
To interact with our smart contract from a web app, we'll need the contract address and the ABI. In the example below I'm using Metamask as a provider, and ethers.js to create a contract instance that points to my smart contract.
On this instance we can use the on()
method to handle the events:
// Contract information
const LuckyNumber = require('/artifacts/solidity/contracts/LuckyNumber.sol/LuckyNumber.json');
const contractAddress = '0xabc12345fecad67343434....';
const provider = new ethers.providers.Web3Provider(window.ethereum);
// Contract instance
const contract = new ethers.Contract(
contractAddress,
LuckyNumber.abi,
provider
);
console.log('contract :>> ', contract);
// handle event from contract
contract.on('LotteryEvent', function (event) {
console.log(`Result is ${event}`);
});
The on()
method receives the event name and a callback function with the payload sent in the event. In the example above we're just printing it in the console but we can use this event to display a popup message, a notification or whatever we need in our web app.
Conclusion
Events allow your smart contract to notify clients and other interested parties that something has happened in the blockchain. They are a very important tool in smart contract developement so make sure to use them wisely!
TAGS