Ref - https://book.getfoundry.sh/forge/cheatcodes
The ERC-20 contract emits events whenever a transfer/approval happens.
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol#L249
In Solidity, emits refers to the action of emitting an event. Events are a fundamental feature of the Ethereum smart contract system, allowing contracts to log important data that can be observed externally.
// Declaring an event
event Transfer(address indexed from, address indexed to, uint256 value);
// Emitting an event
emit Transfer(msg.sender, recipient, 100);
Event Log:
- Topics:
- from: 0x1234567890abcdef (address of the sender)
- to: 0xfedcba0987654321 (address of the recipient)
- Data:
- value: 1000 (value transferred in the transaction)
Indexed Parameters in Events
https://etherscan.io/tx/0x046c2609f21f3308d8f7f902a51ac14f86b9e6b9f54ab1b4f269575d09bc93e5#eventlog
In Solidity, events allow you to mark some of the parameters as indexed. Indexed parameters make the event log searchable, as they allow external listeners (like DApps or off-chain services) to filter events by those parameters more efficiently.
The EVM allows you to index up to 3 parameters per event.
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import {Test, console} from "forge-std/Test.sol";
import { MyToken } from "../src/Token.sol";
contract CounterTest is Test {
MyToken public token;
event Transfer(address indexed from, address indexed to, uint256 amount);
function setUp() public {
token = new MyToken();
}
function test_ExpectEmit() public {
token.mint(address(this), 100);
// Check that topic 1, topic 2, and data are the same as the following emitted event.
// Checking topic 3 here doesn't matter, because `Transfer` only has 2 indexed topics.
vm.expectEmit(true, true, false, true);
// The event we expect
emit Transfer(address(this), 0x075c299cf3b9FCF7C9fD5272cd2ed21A4688bEeD, 100);
// The event we get
token.transfer(0x075c299cf3b9FCF7C9fD5272cd2ed21A4688bEeD, 100);
}
function test_ExpectEmitApprove() public {
token.mint(address(this), 100);
vm.expectEmit(true, true, false, true);
emit Approval(address(this), 0x075c299cf3b9FCF7C9fD5272cd2ed21A4688bEeD, 100);
token.approve(0x075c299cf3b9FCF7C9fD5272cd2ed21A4688bEeD, 100);
vm.prank(0x075c299cf3b9FCF7C9fD5272cd2ed21A4688bEeD);
token.transferFrom(address(this), 0x075c299cf3b9FCF7C9fD5272cd2ed21A4688bEeD, 100);
}
}