harb/onchain/src/OptimizerV3Push3.sol
openhands cfcf750084 fix: Backtesting #5: Position tracking + P&L metrics (#319)
- Add PositionTracker.sol: tracks position lifecycle (open/close per
  recenter), records tick ranges, liquidity, entry/exit blocks/timestamps,
  token amounts (via LiquidityAmounts math), fees (proportional to
  liquidity share), IL (LP exit value − HODL value at exit price), and
  net P&L per position. Aggregates total fees, cumulative IL, net P&L,
  rebalance count, Anchor time-in-range, and capital efficiency accumulators.
  Logs with [TRACKER][TYPE] prefix; emits cumulative P&L every 500 blocks.

- Modify StrategyExecutor.sol: add IUniswapV3Pool + token0isWeth to
  constructor (creates PositionTracker internally), call
  tracker.notifyBlock() on every block for time-in-range, and call
  tracker.recordRecenter() on each successful recenter. logSummary()
  now delegates to tracker.logFinalSummary().

- Modify BacktestRunner.s.sol: pass sp.pool and token0isWeth to
  StrategyExecutor constructor; log tracker address.

- forge fmt: reformat all backtesting scripts and affected src/test files
  to project style (number_underscore=thousands, multiline_func_header=all).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 11:23:18 +00:00

230 lines
18 KiB
Solidity

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.19;
/**
* @title OptimizerV3Push3
* @notice Auto-generated from optimizer_v3.push3 via Push3→Solidity transpiler.
* Implements the same isBullMarket logic as OptimizerV3.
* @dev This contract is an equivalence proof, not a deployable upgrade.
* It intentionally exposes only `isBullMarket` and does NOT implement
* the full optimizer interface (e.g. `getLiquidityParams`). Wiring it
* into the proxy upgrade path would require completing that interface first.
*/
contract OptimizerV3Push3 {
/**
* @notice Determines if the market is in bull configuration.
* @param percentageStaked Percentage of authorized stake in use (0 to 1e18).
* @param averageTaxRate Normalized average tax rate from Stake contract (0 to 1e18).
* @return bull True if bull config, false if bear.
*/
function isBullMarket(uint256 percentageStaked, uint256 averageTaxRate) public pure returns (bool bull) {
require(percentageStaked <= 1e18, "Invalid percentage staked");
require(averageTaxRate <= 1e18, "Invalid tax rate");
uint256 taxrate = uint256(averageTaxRate);
uint256 staked = uint256(((percentageStaked * 100) / 1_000_000_000_000_000_000));
bool b33;
if ((staked > 91)) {
uint256 deltas = uint256((100 - staked));
uint256 r28;
if ((taxrate <= 206_185_567_010_309)) {
r28 = uint256(0);
} else {
uint256 r27;
if ((taxrate <= 412_371_134_020_618)) {
r27 = uint256(1);
} else {
uint256 r26;
if ((taxrate <= 618_556_701_030_927)) {
r26 = uint256(2);
} else {
uint256 r25;
if ((taxrate <= 1_030_927_835_051_546)) {
r25 = uint256(3);
} else {
uint256 r24;
if ((taxrate <= 1_546_391_752_577_319)) {
r24 = uint256(4);
} else {
uint256 r23;
if ((taxrate <= 2_164_948_453_608_247)) {
r23 = uint256(5);
} else {
uint256 r22;
if ((taxrate <= 2_783_505_154_639_175)) {
r22 = uint256(6);
} else {
uint256 r21;
if ((taxrate <= 3_608_247_422_680_412)) {
r21 = uint256(7);
} else {
uint256 r20;
if ((taxrate <= 4_639_175_257_731_958)) {
r20 = uint256(8);
} else {
uint256 r19;
if ((taxrate <= 5_670_103_092_783_505)) {
r19 = uint256(9);
} else {
uint256 r18;
if ((taxrate <= 7_216_494_845_360_824)) {
r18 = uint256(10);
} else {
uint256 r17;
if ((taxrate <= 9_278_350_515_463_917)) {
r17 = uint256(11);
} else {
uint256 r16;
if ((taxrate <= 11_855_670_103_092_783)) {
r16 = uint256(12);
} else {
uint256 r15;
if ((taxrate <= 15_979_381_443_298_969)) {
r15 = uint256(13);
} else {
uint256 r14;
if ((taxrate <= 22_164_948_453_608_247)) {
r14 = uint256(14);
} else {
uint256 r13;
if ((taxrate <= 29_381_443_298_969_072)) {
r13 = uint256(15);
} else {
uint256 r12;
if ((taxrate <= 38_144_329_896_907_216)) {
r12 = uint256(16);
} else {
uint256 r11;
if ((taxrate <= 49_484_536_082_474_226)) {
r11 = uint256(17);
} else {
uint256 r10;
if ((taxrate <= 63_917_525_773_195_876)) {
r10 = uint256(18);
} else {
uint256 r9;
if ((taxrate <= 83_505_154_639_175_257)) {
r9 = uint256(19);
} else {
uint256 r8;
if ((taxrate <= 109_278_350_515_463_917)) {
r8 = uint256(20);
} else {
uint256 r7;
if ((taxrate <= 144_329_896_907_216_494)) {
r7 = uint256(21);
} else {
uint256 r6;
if ((taxrate <= 185_567_010_309_278_350)) {
r6 = uint256(22);
} else {
uint256 r5;
if ((taxrate <= 237_113_402_061_855_670)) {
r5 = uint256(23);
} else {
uint256 r4;
if ((taxrate <= 309_278_350_515_463_917)) {
r4 = uint256(24);
} else {
uint256 r3;
if ((taxrate <= 402_061_855_670_103_092)) {
r3 = uint256(25);
} else {
uint256 r2;
if ((taxrate <= 520_618_556_701_030_927)) {
r2 = uint256(26);
} else {
uint256 r1;
if (
(taxrate <= 680_412_371_134_020_618)
) {
r1 = uint256(27);
} else {
uint256 r0;
if (
(
taxrate
<= 886_597_938_144_329_896
)
) {
r0 = uint256(28);
} else {
r0 = uint256(29);
}
r1 = uint256(r0);
}
r2 = uint256(r1);
}
r3 = uint256(r2);
}
r4 = uint256(r3);
}
r5 = uint256(r4);
}
r6 = uint256(r5);
}
r7 = uint256(r6);
}
r8 = uint256(r7);
}
r9 = uint256(r8);
}
r10 = uint256(r9);
}
r11 = uint256(r10);
}
r12 = uint256(r11);
}
r13 = uint256(r12);
}
r14 = uint256(r13);
}
r15 = uint256(r14);
}
r16 = uint256(r15);
}
r17 = uint256(r16);
}
r18 = uint256(r17);
}
r19 = uint256(r18);
}
r20 = uint256(r19);
}
r21 = uint256(r20);
}
r22 = uint256(r21);
}
r23 = uint256(r22);
}
r24 = uint256(r23);
}
r25 = uint256(r24);
}
r26 = uint256(r25);
}
r27 = uint256(r26);
}
r28 = uint256(r27);
}
uint256 dup29 = uint256(r28);
uint256 r32;
if ((dup29 >= 14)) {
uint256 dup30 = uint256((dup29 + 1));
uint256 r31;
if ((dup30 > 29)) {
r31 = uint256(29);
} else {
r31 = uint256(dup30);
}
r32 = uint256(r31);
} else {
r32 = uint256(dup29);
}
uint256 effidx = uint256(r32);
b33 = (((((deltas * deltas) * deltas) * effidx) / 20) < 50);
} else {
b33 = false;
}
bull = b33;
}
}