Events

In Solidity, events are a way to emit a signal from a contract that something has happened. They are defined with the event keyword and can be emitted with the emit keyword. Events are used to inform clients (such as web applications) about important changes that occur within the contract. They are commonly used to log important data about contract interactions, such as successful transactions, errors, or user actions.
Events are stored on the blockchain and can be accessed through the transaction logs. Clients can listen for these events and react to them accordingly, updating their own state or user interface to reflect the changes that have occurred in the contract. Because events are stored on the blockchain, they provide a transparent and auditable record of contract interactions, making them an important tool for debugging and security analysis.
Once an event is defined in a Solidity contract and the contract is deployed, its definition cannot be changed. It is immutable, which means that it cannot be edited or removed.
If you need to change the definition of an event, you will need to make the changes in the contract's source code, recompile the contract, and redeploy it to the blockchain. Any external systems that interact with the contract's events would then need to be updated to reflect the new event definition.
Events in Ethereum are stored in the transaction receipts, which are generated after a transaction has been mined and added to a block. These receipts contain various pieces of information, including the events emitted by the transaction. The events are stored in a special section of the receipt called the "logs" or "log data", which is stored in the Merkle Patricia tree of the block's header.
Each event has its own log, and the log contains the indexed and non-indexed event data. The indexed event data is stored in a separate location within the log, which allows for efficient searching and filtering of events. When querying for events using the Ethereum node API or a blockchain explorer, the logs are scanned to find the events matching the specified criteria.

Example

pragma solidity ^0.8.0;
contract EventExample {
event LogDeposit(address indexed _from, uint256 _value);
function deposit() external payable {
emit LogDeposit(msg.sender, msg.value);
}
}
In this example, we define an event LogDeposit with two parameters _from and _value. The _from parameter is indexed which allows us to search for events based on this parameter. The deposit function emits this event every time it is called with the address of the caller and the value of ether transferred to the contract.
Here's an example of how to use ethers.js to listen to events emitted by a contract:
import { ethers } from "ethers";
// Create an instance of the contract
const contractAddress = "0x123...";
const abi = [...];
const provider = new ethers.providers.JsonRpcProvider();
const contract = new ethers.Contract(contractAddress, abi, provider);
// Listen for events emitted by the contract
contract.on("Winner", (winnerAddress) => {
console.log(`Winner: ${winnerAddress}`);
});
In this example, we first create an instance of the contract using the contract address and ABI. We then call the on method on the contract instance and pass in the name of the event we want to listen to (Winner) and a callback function that will be called when the event is emitted. The callback function will be passed any parameters emitted by the event (in this case, the address of the winner).
Note that you can also use the filters argument of the on method to listen for specific events that match certain criteria (e.g. events emitted by a specific address).