0

In a foundry project I encountered a scenario where I need to test the emission of an event with specific conditions. My requirement is either to check if a field in the emitted event falls within a certain range or to completely ignore the value of a particular field while asserting the event's emission.

Here's a basic outline of what I am trying to achieve:

// Example Event
event MyEvent(uint indexed value1, address indexed addr, uint value2);

// In the test
vm.expectEmit(...);
// Code to trigger the event

In Foundry's vm.expectEmit function, I understand how to expect specific values for each field in the event. However, I am unsure how to:

  1. Specify that a field (like value2 in MyEvent) should fall within a certain range (e.g., 50 to 100).
  2. Ignore the value of a field completely while still asserting the event's emission.

Is there a built-in way in Foundry to handle such scenarios? If not, what would be the best practice or workaround to achieve this?

2
  • Foundry's vm.expectEmit may not directly support range checking or ignoring certain fields. However, you can capture the event using vm.emit, then manually assert the range or selectively ignore certain fields in your test assertions. Commented Nov 14, 2023 at 1:10
  • @AriSetiawan thanks, can you give an example of that in an answer that I can accept.
    – MShakeG
    Commented Nov 14, 2023 at 7:39

1 Answer 1

0

Foundry does have vm.recordLogs() to record events and vm.getRecordedLogs() to get all the emitted events data which I think is best for this kind of test case (refer docs here). Example : Here I have shown a foundry test which accepts fuzz inputs and emits it in MyEvent event. The test also shows how to assert for values that fall within a particular range. You can ignore assertions for values that are not a concern, which is also shown in the test.

// SPDX-License-Identifier: CAL
pragma solidity =0.8.19;

import {Test, console2} from "forge-std/Test.sol";
import {Vm} from "forge-std/Vm.sol";

contract TiggerEvent {
    // Example Event
    event MyEvent(uint256 indexed value1, address indexed addr, uint256 value2);

    // Function to tigger `MyEvent`
    function tiggerEvent(uint256 value1, address addr, uint256 value2) public {
        emit MyEvent(value1, addr, value2);
    }
}

contract ExpectEmit is TiggerEvent, Test {
    // Foundry test to get fuzz inputs.
    function testEventEmit(uint256 value1, address addr, uint256 value2) public {
        //Bound a value within a range to be emitted in event.
        value1 = bound(value1, 100, 1e36);

        //Start recording Logs
        vm.recordLogs();
        // Emit `MyEvent`
        tiggerEvent(value1, addr, value2);
        //Get recorded events
        Vm.Log[] memory entries = vm.getRecordedLogs();

        //Assert number of emitted events.
        console2.log(entries.length);

        //Decoded emitted values and addresses from topics and data.
        bytes memory topicsData = bytes.concat(entries[0].topics[1], entries[0].topics[2]);
        (uint256 emittedValue1, address emittedAddr) = abi.decode(topicsData, (uint256, address));
        uint256 emittedValue2 = abi.decode(entries[0].data, (uint256));

        // Assert values and addresses
        // Check a value for exact match
        assertEq(emittedAddr, addr);

        //Check a vaule for range
        assertGe(emittedValue1, 100);
        assertLe(emittedValue1, 1e36);

        //Ignore a value
        //assertEq(emittedValue2,value2);
    }
}
  • The only thing to note is that if your contract function emits multiple events you will have to get the index from the logs array. You can filter through the entries array by looping over it and checking for topics[0].Eg :
//Get recorded events
Vm.Log[] memory entries = vm.getRecordedLogs();
for(uint256 i = 0 ; i < entries.length ;i++){
    if(entries[i].topics[0] == keccak256("MyEvent(uint256,address,uint256)")){
        // Event found decode data
    }
} 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.