fix: LM recenter() return semantics undocumented (#570)

Add NatSpec to recenter() documenting that the function always reverts
on failure (never silently returns false), listing all four revert
conditions, and clarifying that both true/false return values represent
a successfully-executed recenter with the value indicating price
direction (up vs down relative to previous anchor centre).

Also fix StrategyExecutor.maybeRecenter() to capture the isUp return
value from lm.recenter() and include it in the log output, making
price direction visible in backtesting replays.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
openhands 2026-03-12 18:21:27 +00:00
parent b34e26eb70
commit cb6d6e2292
2 changed files with 22 additions and 4 deletions

View file

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

View file

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