From 5c4ceaf78dcb835ed46850184879474026c80214 Mon Sep 17 00:00:00 2001 From: johba Date: Thu, 19 Mar 2026 11:30:18 +0100 Subject: [PATCH] fix: No negative-mantissa guard in OptimizerV3Push3 (#650) (#966) Fixes #650 ## Changes Add require(inputs[k].mantissa >= 0, 'negative mantissa') for all 8 input slots inside the existing validation loop in OptimizerV3Push3.sol, matching the guard pattern in Optimizer.sol lines 372-374. Added 3 tests covering slots 0, 1, and 5 to confirm revert on negative mantissa. Co-authored-by: openhands Reviewed-on: https://codeberg.org/johba/harb/pulls/966 Reviewed-by: Disinto_bot --- onchain/src/OptimizerV3Push3.sol | 2 ++ onchain/test/OptimizerV3Push3.t.sol | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/onchain/src/OptimizerV3Push3.sol b/onchain/src/OptimizerV3Push3.sol index 78a6dd1..a24578f 100644 --- a/onchain/src/OptimizerV3Push3.sol +++ b/onchain/src/OptimizerV3Push3.sol @@ -56,8 +56,10 @@ contract OptimizerV3Push3 is IOptimizer { require(inputs[0].mantissa <= 1e18, "mantissa overflow"); // Validate that shift is 0 (future-only field, not yet supported) + // and that no mantissa is negative (uint256 cast silently wraps negatives). for (uint256 k = 0; k < 8; k++) { require(inputs[k].shift == 0, "shift not yet supported"); + require(inputs[k].mantissa >= 0, "negative mantissa"); } uint256 percentagestaked = uint256(uint256(inputs[0].mantissa)); diff --git a/onchain/test/OptimizerV3Push3.t.sol b/onchain/test/OptimizerV3Push3.t.sol index aba1183..bae7169 100644 --- a/onchain/test/OptimizerV3Push3.t.sol +++ b/onchain/test/OptimizerV3Push3.t.sol @@ -200,6 +200,30 @@ contract OptimizerV3Push3Test is Test { _assertBull(ci, as_, aw, dd); } + // ---- Negative mantissa guards ---- + + function testNegativeMantissaSlot0Reverts() public { + OptimizerInput[8] memory inp; + inp[0] = OptimizerInput({mantissa: -1, shift: 0}); + vm.expectRevert("negative mantissa"); + push3.calculateParams(inp); + } + + function testNegativeMantissaSlot1Reverts() public { + OptimizerInput[8] memory inp; + inp[0] = OptimizerInput({mantissa: int256(_pct(95)), shift: 0}); + inp[1] = OptimizerInput({mantissa: -1, shift: 0}); + vm.expectRevert("negative mantissa"); + push3.calculateParams(inp); + } + + function testNegativeMantissaSlot5Reverts() public { + OptimizerInput[8] memory inp; + inp[5] = OptimizerInput({mantissa: -1, shift: 0}); + vm.expectRevert("negative mantissa"); + push3.calculateParams(inp); + } + // ---- Fuzz ---- function testFuzzNeverReverts(uint256 percentageStaked, uint256 averageTaxRate) public view {