diff --git a/onchain/script/backtesting/StrategyExecutor.sol b/onchain/script/backtesting/StrategyExecutor.sol index ed78b1d..14708f5 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,8 @@ contract StrategyExecutor { _logRecenter( blockNum, + isUp, + aLiqPre == 0, // bootstrap: no anchor existed before this recenter fLiqPre, fLoPre, fHiPre, @@ -228,6 +232,8 @@ contract StrategyExecutor { function _logRecenter( uint256 blockNum, + bool isUp, + bool isBootstrap, uint128 fLiqPre, int24 fLoPre, int24 fHiPre, @@ -252,7 +258,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=", isBootstrap ? "BOOTSTRAP" : (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 70eadac..6ece4ef 100644 --- a/onchain/src/LiquidityManager.sol +++ b/onchain/src/LiquidityManager.sol @@ -149,8 +149,23 @@ 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 KRK price in ETH rose since the last recenter + /// (buy event / net ETH inflow), regardless of token0/token1 ordering. + /// False if the KRK price fell, or if no anchor position existed prior + /// to this recenter (bootstrap case, no directional reference point). + /// Both values indicate a successful, fully-executed recenter. function recenter() external returns (bool isUp) { (, int24 currentTick,,,,,) = pool.slot0();