- Fix fee attribution: distribute fees only to positions whose tick range contains the active tick at close time (in-range weight), not by raw liquidity. FLOOR is priced far below current tick and rarely earns fees; the old approach would over-credit it and corrupt capital-efficiency and net-P&L numbers. Fallback to raw-liquidity weighting with a WARN log when no position is in range. - Warn on first-close skip: when _closePosition finds no open record (first recenter, before any tracking), log [TRACKER][WARN] instead of silently returning so the gap is visible in reports. - Add tick range assertion: require() that the incoming close snapshot tick range matches the stored open record — a mismatch would mean IL is computed across different ranges (apples vs oranges). - Fix finalBlock accuracy: logSummary now calls tracker.logFinalSummary(tracker.lastNotifiedBlock()) instead of lastRecenterBlock, so the summary reflects the actual last replay block rather than potentially hundreds of blocks early. - Initialize lastRecenterBlock = block.number in StrategyExecutor constructor to defer the first recenter attempt by recenterInterval blocks and document the invariant. - Extract shared FormatLib: _str(uint256) and _istr(int256) were copy-pasted in both PositionTracker and StrategyExecutor. Extracted to FormatLib.sol internal library; both contracts now use `using FormatLib`. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
33 lines
1 KiB
Solidity
33 lines
1 KiB
Solidity
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
pragma solidity ^0.8.19;
|
|
|
|
/**
|
|
* @title FormatLib
|
|
* @notice Shared integer-to-string formatting helpers for backtesting log output.
|
|
* Extracted to avoid copy-pasting the same logic across PositionTracker
|
|
* and StrategyExecutor.
|
|
*/
|
|
library FormatLib {
|
|
/// @notice Format an unsigned integer as a decimal string.
|
|
function str(uint256 v) internal pure returns (string memory) {
|
|
if (v == 0) return "0";
|
|
uint256 tmp = v;
|
|
uint256 len;
|
|
while (tmp != 0) {
|
|
len++;
|
|
tmp /= 10;
|
|
}
|
|
bytes memory buf = new bytes(len);
|
|
while (v != 0) {
|
|
buf[--len] = bytes1(uint8(48 + v % 10));
|
|
v /= 10;
|
|
}
|
|
return string(buf);
|
|
}
|
|
|
|
/// @notice Format a signed integer as a decimal string (prefixed with '-' if negative).
|
|
function istr(int256 v) internal pure returns (string memory) {
|
|
if (v >= 0) return str(uint256(v));
|
|
return string.concat("-", str(uint256(-v)));
|
|
}
|
|
}
|