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 <noreply@anthropic.com>
This commit is contained in:
openhands 2026-03-12 15:41:39 +00:00
parent d84ff5f762
commit 9bb223cf95
2 changed files with 23 additions and 0 deletions

View file

@ -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);

View file

@ -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
*/