Skip to content

Commit d1b7162

Browse files
committed
test: lock in nested-OR rejection, symmetrize OR revert
1 parent 4132035 commit d1b7162

2 files changed

Lines changed: 56 additions & 1 deletion

File tree

contracts/ComposableExecutionLib.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ library ComposableExecutionLib {
205205
++j;
206206
}
207207
}
208-
if (!anyMet) revert ConstraintNotMet(ConstraintType.OR);
208+
if (!anyMet) revert ConstraintNotMet(c.constraintType);
209209
} else {
210210
if (!_checkConstraint(value, c)) revert ConstraintNotMet(c.constraintType);
211211
}

test/unit/ComposableExecution_ConstraintsReverts.sol

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,13 @@ contract ComposableExecutionTestConstraintsAndReverts is ComposabilityTestBase {
471471
_inputParamUsingOrWithSignedConstraints(address(mockAccountDelegateCaller), address(mockAccountDelegateCaller));
472472
}
473473

474+
function test_Nested_Or_Reverts_With_InvalidConstraintType() public {
475+
_nestedOrReverts(address(mockAccount), address(mockAccount));
476+
_nestedOrReverts(address(mockAccountFallback), address(composabilityHandler));
477+
_nestedOrReverts(address(mockAccountCaller), address(composabilityHandler));
478+
_nestedOrReverts(address(mockAccountDelegateCaller), address(mockAccountDelegateCaller));
479+
}
480+
474481
// -----------------------------------------------------------------------
475482
// GTE_SIGNED: checks that int256(-5) is the lower bound.
476483
// value = int256(-10) => fails (below bound)
@@ -949,4 +956,52 @@ contract ComposableExecutionTestConstraintsAndReverts is ComposabilityTestBase {
949956

950957
vm.stopPrank();
951958
}
959+
960+
// -----------------------------------------------------------------------
961+
// Nested OR is intentionally rejected to keep the signed payload flat and
962+
// easy to display. An OR whose sub-array contains another OR must revert
963+
// with InvalidConstraintType when _checkConstraint encounters the inner OR.
964+
// -----------------------------------------------------------------------
965+
function _nestedOrReverts(address account, address caller) internal {
966+
// Inner OR with two leaf alternatives
967+
Constraint[] memory innerSubs = new Constraint[](2);
968+
innerSubs[0] = Constraint({ constraintType: ConstraintType.EQ, referenceData: abi.encode(bytes32(uint256(1))) });
969+
innerSubs[1] = Constraint({ constraintType: ConstraintType.EQ, referenceData: abi.encode(bytes32(uint256(2))) });
970+
971+
// Outer OR whose second alternative is the inner OR (nesting)
972+
Constraint[] memory outerSubs = new Constraint[](2);
973+
outerSubs[0] = Constraint({ constraintType: ConstraintType.EQ, referenceData: abi.encode(bytes32(uint256(0))) });
974+
outerSubs[1] = Constraint({ constraintType: ConstraintType.OR, referenceData: abi.encode(innerSubs) });
975+
976+
Constraint[] memory constraints = new Constraint[](1);
977+
constraints[0] = Constraint({ constraintType: ConstraintType.OR, referenceData: abi.encode(outerSubs) });
978+
979+
vm.startPrank(ENTRYPOINT_V07_ADDRESS);
980+
981+
// value = 7: outer OR's first alternative (EQ(0)) fails for value=7, so it reaches the
982+
// nested inner OR, which triggers InvalidConstraintType inside _checkConstraint.
983+
InputParam[] memory inputParams = new InputParam[](3);
984+
inputParams[0] = InputParam({
985+
paramType: InputParamType.CALL_DATA, fetcherType: InputParamFetcherType.RAW_BYTES, paramData: abi.encode(uint256(7)), constraints: constraints
986+
});
987+
inputParams[1] = _createRawTargetInputParam(address(0));
988+
inputParams[2] = _createRawValueInputParam(0);
989+
990+
OutputParam[] memory outputParams = new OutputParam[](0);
991+
ComposableExecution[] memory executions = new ComposableExecution[](1);
992+
executions[0] = ComposableExecution({ functionSig: "", inputParams: inputParams, outputParams: outputParams });
993+
994+
bytes memory expectedRevert;
995+
if (address(account) == address(mockAccountFallback)) {
996+
expectedRevert = abi.encodeWithSelector(
997+
MockAccountFallback.FallbackFailed.selector, abi.encodeWithSelector(ComposableExecutionLib.InvalidConstraintType.selector)
998+
);
999+
} else {
1000+
expectedRevert = abi.encodeWithSelector(ComposableExecutionLib.InvalidConstraintType.selector);
1001+
}
1002+
vm.expectRevert(expectedRevert);
1003+
IComposableExecution(address(account)).executeComposable(executions);
1004+
1005+
vm.stopPrank();
1006+
}
9521007
}

0 commit comments

Comments
 (0)