fix: Catch block skips clamping that try block applies (#1019)
Add defence-in-depth assert statements in recenter()'s catch block to verify bear-mode constants (CI=0, AS=30%, AW=100, DD=0.3e18) satisfy the same bounds the try-path clamps to (MAX_PARAM_SCALE, MAX_ANCHOR_WIDTH). Add test verifying bear defaults are within clamping bounds and that the catch path deploys all three positions (floor, anchor, discovery). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
94309cd5a6
commit
bdc17645f9
2 changed files with 44 additions and 1 deletions
|
|
@ -249,7 +249,16 @@ contract LiquidityManager is ThreePositionStrategy, PriceOracle {
|
|||
|
||||
_setPositions(currentTick, params);
|
||||
} catch {
|
||||
// Fallback to safe bear-mode defaults if optimizer fails
|
||||
// Fallback to safe bear-mode defaults if optimizer fails.
|
||||
// Defence-in-depth: assert bear constants satisfy the same bounds
|
||||
// that the try-path clamps to. These are compile-time constants so
|
||||
// the asserts can never fire at runtime, but they guard against a
|
||||
// future edit to IOptimizer.sol that pushes a value out of range.
|
||||
assert(BEAR_CAPITAL_INEFFICIENCY <= MAX_PARAM_SCALE);
|
||||
assert(BEAR_ANCHOR_SHARE <= MAX_PARAM_SCALE);
|
||||
assert(BEAR_ANCHOR_WIDTH <= MAX_ANCHOR_WIDTH);
|
||||
assert(BEAR_DISCOVERY_DEPTH <= MAX_PARAM_SCALE);
|
||||
|
||||
PositionParams memory defaultParams = PositionParams({
|
||||
capitalInefficiency: BEAR_CAPITAL_INEFFICIENCY,
|
||||
anchorShare: BEAR_ANCHOR_SHARE,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import { ThreePositionStrategy } from "../src/abstracts/ThreePositionStrategy.so
|
|||
import "../src/helpers/UniswapHelpers.sol";
|
||||
import "../test/mocks/MockOptimizer.sol";
|
||||
import "../test/mocks/ConfigurableOptimizer.sol";
|
||||
import { BEAR_CAPITAL_INEFFICIENCY, BEAR_ANCHOR_SHARE, BEAR_ANCHOR_WIDTH, BEAR_DISCOVERY_DEPTH } from "../src/IOptimizer.sol";
|
||||
import { TestEnvironment } from "./helpers/TestBase.sol";
|
||||
import { UniSwapHelper } from "./helpers/UniswapTestBase.sol";
|
||||
|
||||
|
|
@ -1100,6 +1101,39 @@ contract LiquidityManagerTest is UniSwapHelper {
|
|||
assertGt(anchorLiq, 0, "ANCHOR position should have been created with fallback params");
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Catch-path clamping: verify bear defaults satisfy the same bounds
|
||||
* that the try-path clamps to, and that all three positions are deployed.
|
||||
* Covers issue #1019 — defence-in-depth assertions in catch block.
|
||||
*/
|
||||
function testOptimizerFallback_BearDefaultsWithinClampingBounds() public {
|
||||
// --- Static check: bear constants are within clamping ceilings ---
|
||||
uint256 MAX_PARAM_SCALE = 10 ** 18;
|
||||
uint24 MAX_ANCHOR_WIDTH = 1233;
|
||||
|
||||
assertLe(BEAR_CAPITAL_INEFFICIENCY, MAX_PARAM_SCALE, "BEAR_CAPITAL_INEFFICIENCY exceeds MAX_PARAM_SCALE");
|
||||
assertLe(BEAR_ANCHOR_SHARE, MAX_PARAM_SCALE, "BEAR_ANCHOR_SHARE exceeds MAX_PARAM_SCALE");
|
||||
assertLe(BEAR_ANCHOR_WIDTH, MAX_ANCHOR_WIDTH, "BEAR_ANCHOR_WIDTH exceeds MAX_ANCHOR_WIDTH");
|
||||
assertLe(BEAR_DISCOVERY_DEPTH, MAX_PARAM_SCALE, "BEAR_DISCOVERY_DEPTH exceeds MAX_PARAM_SCALE");
|
||||
|
||||
// --- Runtime check: catch block deploys all three positions ---
|
||||
RevertingOptimizer revertingOpt = new RevertingOptimizer();
|
||||
TestEnvironment env = new TestEnvironment(feeDestination);
|
||||
(,,,,, LiquidityManager _lm,,) = env.setupEnvironmentWithOptimizer(DEFAULT_TOKEN0_IS_WETH, address(revertingOpt));
|
||||
|
||||
vm.prank(RECENTER_CALLER);
|
||||
_lm.recenter();
|
||||
|
||||
// All three position stages must have non-zero liquidity
|
||||
(uint128 floorLiq,,) = _lm.positions(ThreePositionStrategy.Stage.FLOOR);
|
||||
(uint128 anchorLiq,,) = _lm.positions(ThreePositionStrategy.Stage.ANCHOR);
|
||||
(uint128 discoveryLiq,,) = _lm.positions(ThreePositionStrategy.Stage.DISCOVERY);
|
||||
|
||||
assertGt(floorLiq, 0, "FLOOR position missing in catch path");
|
||||
assertGt(anchorLiq, 0, "ANCHOR position missing in catch path");
|
||||
assertGt(discoveryLiq, 0, "DISCOVERY position missing in catch path");
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice When feeDestination == address(lm), recenter must not transfer fees externally
|
||||
* and _getOutstandingSupply must not double-subtract LM-held KRK.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue