Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cheatcodes): document new expectEmit behavior #896

Merged
merged 3 commits into from
May 12, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 33 additions & 4 deletions src/cheatcodes/expect-emit.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,34 @@ function expectEmit(

### Description

Assert a specific log is emitted before the end of the current function.
Assert a specific log is emitted during the next call.

1. Call the cheat code, specifying whether we should check the first, second or third topic, and the log data. Topic 0 is always checked.
2. Emit the event we are supposed to see before the end of the current function.
2. Emit the event we are supposed to see during the next call.
3. 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 signatures:

- **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.

> ℹ️ **Ordering matters**
> ℹ️ **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`.
>
> If we call `expectEmit` and emit an event, then the next event emitted **must** match the one we expect.
> `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).

### Examples

Expand Down Expand Up @@ -94,3 +106,20 @@ function testERC20EmitsBatchTransfer() public {
myToken.batchTransfer(users, 10);
}
```

This example fails, as the expected event is not emitted on the next call.
```solidity
event Transfer(address indexed from, address indexed to, uint256 amount);

function testERC20EmitsTransfer() 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);
}
```