Tells the VM to start recording all the emitted events. To access them, use getRecordedLogs.
vm.recordLogs(); // Start recording logsraffle.performUpkeep(""); // Call function that emits event logVm.Log[] memory entries = vm.getRecordedLogs(); // Store emitted log// Access stored log by knowing exactly which logs are emitted// .topics[0] would refer to the entire event// .topics[1] is for the first actual topic// All logs are recorded as bytes32 in foundrybytes32 requestId = entries[1].topics[1];
expectEmit
Assert a specific log is emitted during the next call.
Call the cheat code, specifying whether we should check the first, second or third topic, and the log data (expectEmit() checks them all). Topic 0 is always checked.
Emit the event we are supposed to see during the next call.
Perform the call.
You can perform steps 1 and 2 multiple times to match a sequence of events in the next call.
If the event is not available in the current scope (e.g. if we are using an interface, or an external smart contract), we can define the event ourselves with an identical event signature.
There are 2 varieties of expectEmit:
Without checking the emitter address: Asserts the topics match without checking the emitting address.
With address: Asserts the topics match and that the emitting address matches.
Matching sequences
In functions that emit a lot of events, it's possible to "skip" events and only match a specific sequence, but this sequence must always be in order. As an example, let's say a function emits events: A, B, C, D, E, F, F, G.
expectEmit will be able to match ranges with and without skipping events in between:
[A, B, C] is valid.
[B, D, F] is valid.
[G] or any other single event combination is valid.
[B, A] or similar out-of-order combinations are invalid (events must be in order).
[C, F, F] is valid.
[F, F, C] is invalid (out of order).
expectEmit Examples
Just check that an event happens but no details about it
// The first parameter: Whether to check the event signature.// The second parameter: Whether to check the indexed parameters (topics) of the event.// The third parameter: Whether to check the unindexed parameters (data) of the event.// The fourth parameter: Whether to check the event data's values.vm.expectEmit(true,true,true,false); // `false` for data means we don't care about the valueemit IAavePM.Rebalanced(0); // The data is a placeholder and not checked
This does not check the emitting address.
eventTransfer(addressindexed from, addressindexed to, uint256 amount);functiontestERC20EmitsTransfer() public { vm.expectEmit();// We emit the event we expect to see.emit MyToken.Transfer(address(this),address(1),10);// We perform the call. myToken.transfer(address(1),10);}
This does check the emitting address.
eventTransfer(addressindexed from, addressindexed to, uint256 amount);functiontestERC20EmitsTransfer() public {// We check that the token is the event emitter by passing the address. vm.expectEmit(address(myToken));emit MyToken.Transfer(address(this),address(1),10);// We perform the call. myToken.transfer(address(1),10);}
We can also assert that multiple events are emitted in a single call.
functiontestERC20EmitsBatchTransfer() public {// We declare multiple expected transfer eventsfor (uint256 i =0; i < users.length; i++) {// Here we use the longer signature for demonstration purposes. This call checks// topic0 (always checked), topic1 (true), topic2 (true), NOT topic3 (false), and data (true). vm.expectEmit(true,true,false,true);emitTransfer(address(this), users[i],10); }// We also expect a custom `BatchTransfer(uint256 numberOfTransfers)` event. vm.expectEmit(false,false,false,true);emitBatchTransfer(users.length);// We perform the call. myToken.batchTransfer(users,10);}
This example fails, as the expected event is not emitted on the next call.
eventTransfer(addressindexed from, addressindexed to, uint256 amount);functiontestERC20EmitsTransfer() public {// We check that the token is the event emitter by passing the address as the fifth argument. vm.expectEmit(true,true,false,true,address(myToken));emit MyToken.Transfer(address(this),address(1),10);// We perform an unrelated call that won't emit the intended event,// making the cheatcode fail. myToken.approve(address(this),1e18);// We perform the call, but it will have no effect as the cheatcode has already failed. myToken.transfer(address(1),10);}
envUint
Read an environment variable as uint256 or uint256[].