Ethers.js allows you to watch events on Solidity that are emitted from blockchains.
Let's say you have the SimpleAuction
contract that emits HighestBidIncreased
event when bids happen:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.21 <0.9.0;
contract SimpleAuction {
event HighestBidIncreased(address bidder, uint amount); // Event
function bid() public payable {
// ...
emit HighestBidIncreased(msg.sender, msg.value); // Triggering event
}
}
In Ethers.js, you can use contract.on(event, listener)
to watch events as follows:
import { ethers } from 'ethers'
import contractArtifact from '../artifacts/contracts/SimpleAuction.sol/SimpleAuction.json'
const provider = new ethers.providers.Web3Provider(window.ethereum)
const { abi } = contractArtifact
const signer = provider.getSigner()
const contract = new ethers.Contract(contractAddress, abi, signer)
const filter = contract.filters.HighestBidIncreased(addressToFilter, null)
// Add an event listener here.
contract.on(filter, (bidder, amount) => {
// This is called when `HighestBidIncreased` event is emitted in the smart contract
console.log(`${bidder} bid ${amount} amount.`)
})
If you are using Ether.js v5, there is one tricky behaviour: Event listeners are fired on page load.
This sometimes introduces unexpected behaviours or software bugs. Every time pages get loaded, the event listener fires with the same transaction payloads.
In order to avoid this, you can utilize provider.once("block")
that add a listener for only a new block is detected.
provider.once("block", () => {
contract.on(filter, (bidder, amount) => {
console.log(`${bidder} bid ${amount} amount.`)
})
})
If you wrap callbacks as you can see in the above example with provider.once("block")
, now the event listener is only interested in new blocks.