Gap
FlowInitialized(address sender, EvaluableV2 evaluable) is emitted at src/concrete/Flow.sol:225 for each registered flow during flowInit. The existing tests use this event to extract the resulting evaluables (test/abstract/FlowTest.sol:74-79) but never assert:
- The
sender field equals the expected msg.sender (the clone factory in the standard flow).
- The number of emitted events equals the number of evaluable configs.
- The emitted
evaluable matches the deployer's returned (interpreter, store, expression).
Flow.construction.t.sol::testFlowConstructionInitialize only asserts the Initialize event payload; it ignores FlowInitialized entirely.
Source
src/concrete/Flow.sol:110 (event declaration)
src/concrete/Flow.sol:225 (emit)
Existing related tests
test/src/concrete/Flow.construction.t.sol::testFlowConstructionInitialize — asserts Initialize, not FlowInitialized.
test/src/concrete/Flow.expression.t.sol::testFlowBasicShouldDeployExpression — extracts evaluables but only checks expression field.
Proposed test
Add to test/src/concrete/Flow.construction.t.sol:
import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol";
import {LibLogHelper} from "test/lib/LibLogHelper.sol";
using LibLogHelper for Vm.Log[];
function testFlowConstructionEmitsFlowInitializedPerConfig(
address[] memory expressions
) external {
uint256 length = bound(expressions.length, 1, 5);
assembly ("memory-safe") { mstore(expressions, length) }
EvaluableConfigV3[] memory flowConfig = new EvaluableConfigV3[](length);
for (uint256 i = 0; i < length; i++) {
// Distinct deployer mock per expression so each evaluable is unique.
expressionDeployerDeployExpression2MockCall(
new bytes(0), new uint256[](0), expressions[i], bytes(hex"0007")
);
flowConfig[i] = EvaluableConfigV3(DEPLOYER, new bytes(0), new uint256[](0));
}
vm.recordLogs();
address clone = I_CLONE_FACTORY.clone(deployFlowImplementation(), abi.encode(flowConfig));
Vm.Log[] memory logs = vm.getRecordedLogs();
Vm.Log[] memory initLogs = logs.findEvents(keccak256("FlowInitialized(address,(address,address,address))"));
assertEq(initLogs.length, length, "wrong FlowInitialized count");
for (uint256 i = 0; i < length; i++) {
(address sender, EvaluableV2 memory evaluable) =
abi.decode(initLogs[i].data, (address, EvaluableV2));
assertEq(sender, address(I_CLONE_FACTORY), "wrong sender");
assertEq(evaluable.expression, expressions[i], "wrong expression");
assertEq(address(evaluable.interpreter), address(INTERPRETER), "wrong interpreter");
assertEq(address(evaluable.store), address(STORE), "wrong store");
}
}
Gap
FlowInitialized(address sender, EvaluableV2 evaluable)is emitted atsrc/concrete/Flow.sol:225for each registered flow duringflowInit. The existing tests use this event to extract the resulting evaluables (test/abstract/FlowTest.sol:74-79) but never assert:senderfield equals the expectedmsg.sender(the clone factory in the standard flow).evaluablematches the deployer's returned(interpreter, store, expression).Flow.construction.t.sol::testFlowConstructionInitializeonly asserts theInitializeevent payload; it ignoresFlowInitializedentirely.Source
src/concrete/Flow.sol:110(event declaration)src/concrete/Flow.sol:225(emit)Existing related tests
test/src/concrete/Flow.construction.t.sol::testFlowConstructionInitialize— assertsInitialize, notFlowInitialized.test/src/concrete/Flow.expression.t.sol::testFlowBasicShouldDeployExpression— extracts evaluables but only checksexpressionfield.Proposed test
Add to
test/src/concrete/Flow.construction.t.sol: