diff --git a/onchain/script/backtesting/StrategyExecutor.sol b/onchain/script/backtesting/StrategyExecutor.sol index ed78b1d..50f22b0 100644 --- a/onchain/script/backtesting/StrategyExecutor.sol +++ b/onchain/script/backtesting/StrategyExecutor.sol @@ -115,10 +115,12 @@ contract StrategyExecutor { lastRecenterBlock = blockNum; bool success; + bool isUp; string memory failReason; - try lm.recenter() { + try lm.recenter() returns (bool _isUp) { success = true; + isUp = _isUp; totalRecenters++; } catch Error(string memory reason) { failReason = reason; @@ -173,6 +175,7 @@ contract StrategyExecutor { _logRecenter( blockNum, + isUp, fLiqPre, fLoPre, fHiPre, @@ -228,6 +231,7 @@ contract StrategyExecutor { function _logRecenter( uint256 blockNum, + bool isUp, uint128 fLiqPre, int24 fLoPre, int24 fHiPre, @@ -252,7 +256,7 @@ contract StrategyExecutor { internal view { - console2.log(string.concat("=== Recenter #", totalRecenters.str(), " @ block ", blockNum.str(), " ===")); + console2.log(string.concat("=== Recenter #", totalRecenters.str(), " @ block ", blockNum.str(), " direction=", isUp ? "UP" : "DOWN", " ===")); console2.log(string.concat(" Floor pre: tick [", int256(fLoPre).istr(), ", ", int256(fHiPre).istr(), "] liq=", uint256(fLiqPre).str())); console2.log(string.concat(" Anchor pre: tick [", int256(aLoPre).istr(), ", ", int256(aHiPre).istr(), "] liq=", uint256(aLiqPre).str())); console2.log(string.concat(" Disc pre: tick [", int256(dLoPre).istr(), ", ", int256(dHiPre).istr(), "] liq=", uint256(dLiqPre).str())); diff --git a/onchain/src/LiquidityManager.sol b/onchain/src/LiquidityManager.sol index 91e2787..7041307 100644 --- a/onchain/src/LiquidityManager.sol +++ b/onchain/src/LiquidityManager.sol @@ -149,8 +149,22 @@ contract LiquidityManager is ThreePositionStrategy, PriceOracle { recenterAccess = address(0); } - /// @notice Adjusts liquidity positions in response to price movements - /// @return isUp True if price moved up (relative to token ordering) + /// @notice Adjusts liquidity positions in response to price movements. + /// This function either completes a full recenter (removing all positions, + /// recording VWAP where applicable, and redeploying liquidity) or reverts — + /// it never returns silently without acting. + /// + /// @dev Revert conditions (no silent false return for failure): + /// - "access denied" — recenterAccess is set and caller is not that address + /// - "recenter cooldown" — recenterAccess is unset and MIN_RECENTER_INTERVAL has not elapsed + /// - "price deviated from oracle" — recenterAccess is unset and price is outside TWAP bounds + /// - "amplitude not reached." — anchor position exists but price has not moved far enough + /// from the anchor centre to warrant repositioning + /// + /// @return isUp True if the current tick is above the previous anchor centre + /// (price moved up in pool terms); false if it moved down or if no anchor + /// position existed prior to this recenter (bootstrap case). + /// Both values indicate a successful, fully-executed recenter. function recenter() external returns (bool isUp) { (, int24 currentTick,,,,,) = pool.slot0();