From 9bb223cf95ebb47a9587e116c477748723cc2fa2 Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 12 Mar 2026 15:41:39 +0000 Subject: [PATCH] fix: Optimizer.sol also silently accepts negative mantissa inputs (#582) Add require(mantissa >= 0) guards in calculateParams before the uint256() casts on inputs[0] and inputs[1], preventing negative int256 values from wrapping to huge uint256 numbers and corrupting liquidity calculations. Add two regression tests covering the revert paths for both slots. Co-Authored-By: Claude Sonnet 4.6 --- onchain/src/Optimizer.sol | 3 +++ onchain/test/Optimizer.t.sol | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/onchain/src/Optimizer.sol b/onchain/src/Optimizer.sol index fe7687b..54db899 100644 --- a/onchain/src/Optimizer.sol +++ b/onchain/src/Optimizer.sol @@ -248,6 +248,9 @@ contract Optimizer is Initializable, UUPSUpgradeable { virtual returns (uint256 capitalInefficiency, uint256 anchorShare, uint24 anchorWidth, uint256 discoveryDepth) { + // Guard against negative mantissa — uint256() cast silently wraps negatives. + require(inputs[0].mantissa >= 0, "negative mantissa"); + require(inputs[1].mantissa >= 0, "negative mantissa"); // Extract slots 0 and 1 (shift=0 assumed — mantissa IS the value) uint256 percentageStaked = uint256(inputs[0].mantissa); uint256 averageTaxRate = uint256(inputs[1].mantissa); diff --git a/onchain/test/Optimizer.t.sol b/onchain/test/Optimizer.t.sol index d22eef6..2b5fff5 100644 --- a/onchain/test/Optimizer.t.sol +++ b/onchain/test/Optimizer.t.sol @@ -324,6 +324,26 @@ contract OptimizerTest is Test { assertEq(w, 10, "totalWidth < 10 should be clamped to minimum of 10"); } + /** + * @notice calculateParams reverts when inputs[0].mantissa is negative + */ + function testCalculateParamsRevertsOnNegativeMantissa0() public { + OptimizerInput[8] memory inputs; + inputs[0] = OptimizerInput({mantissa: -1, shift: 0}); + vm.expectRevert("negative mantissa"); + optimizer.calculateParams(inputs); + } + + /** + * @notice calculateParams reverts when inputs[1].mantissa is negative + */ + function testCalculateParamsRevertsOnNegativeMantissa1() public { + OptimizerInput[8] memory inputs; + inputs[1] = OptimizerInput({mantissa: -1, shift: 0}); + vm.expectRevert("negative mantissa"); + optimizer.calculateParams(inputs); + } + /** * @notice Non-admin calling upgradeTo should revert with UnauthorizedAccount */