From c59bb81a400b8cdbea45bdf0435f73fbba504d0f Mon Sep 17 00:00:00 2001 From: johba Date: Sun, 22 Mar 2026 12:11:03 +0000 Subject: [PATCH] fix: Overflow guard missing for slots 1-7 in both Optimizer.sol and OptimizerV3Push3.sol (#997) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add <= 1e18 upper-bound check for all 8 input slots in the validation loops of both Optimizer.calculateParams() and OptimizerV3Push3Lib.calculateParams(). Previously only slot 0 (percentageStaked) had an overflow guard — slots 1-7 (averageTaxRate and future indicators) could silently accept values > 1e18, violating the documented [0, 1e18] invariant. Co-Authored-By: Claude Opus 4.6 (1M context) --- onchain/src/Optimizer.sol | 4 +++- onchain/src/OptimizerV3Push3Lib.sol | 9 ++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/onchain/src/Optimizer.sol b/onchain/src/Optimizer.sol index 08b8769..1fd2e82 100644 --- a/onchain/src/Optimizer.sol +++ b/onchain/src/Optimizer.sol @@ -361,11 +361,13 @@ contract Optimizer is Initializable, UUPSUpgradeable, IOptimizer { virtual returns (uint256 capitalInefficiency, uint256 anchorShare, uint24 anchorWidth, uint256 discoveryDepth) { - // Guard against non-zero shift and negative mantissa. + // Guard against non-zero shift, negative mantissa, and overflow. + // All 8 slots must be in [0, 1e18] — the uniform dyadic range. // shift is reserved for future use; uint256() cast silently wraps negatives. for (uint256 k; k < 8; k++) { require(inputs[k].shift == 0, "shift not yet supported"); require(inputs[k].mantissa >= 0, "negative mantissa"); + require(inputs[k].mantissa <= 1e18, "mantissa overflow"); } // Extract slots 0 and 1 (shift=0 enforced above — mantissa IS the value) uint256 percentageStaked = uint256(inputs[0].mantissa); diff --git a/onchain/src/OptimizerV3Push3Lib.sol b/onchain/src/OptimizerV3Push3Lib.sol index da3774b..0a7f870 100644 --- a/onchain/src/OptimizerV3Push3Lib.sol +++ b/onchain/src/OptimizerV3Push3Lib.sol @@ -17,14 +17,13 @@ library OptimizerV3Push3Lib { pure returns (uint256 ci, uint256 anchorShare, uint24 anchorWidth, uint256 discoveryDepth) { - // Validate mantissa for percentageStaked - 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). + // Validate that shift is 0 (future-only field, not yet supported), + // that no mantissa is negative (uint256 cast silently wraps negatives), + // and that all slots are within the [0, 1e18] dyadic range. for (uint256 k = 0; k < 8; k++) { require(inputs[k].shift == 0, "shift not yet supported"); require(inputs[k].mantissa >= 0, "negative mantissa"); + require(inputs[k].mantissa <= 1e18, "mantissa overflow"); } uint256 percentagestaked = uint256(uint256(inputs[0].mantissa));