Commit graph

497 commits

Author SHA1 Message Date
johba
59d8364ef3 Merge pull request 'fix: Backtesting #6: Baseline strategies (HODL, full-range, fixed-width) + reporting (#320)' (#358) from fix/issue-320 into master 2026-02-27 15:15:58 +01:00
openhands
af86ca1226 fix: address review feedback on BaselineStrategies and Reporter
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 13:43:49 +00:00
openhands
77f0fd82fd fix: Backtesting #6: Baseline strategies (HODL, full-range, fixed-width) + reporting (#320)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 13:08:53 +00:00
johba
33c5244e53 Merge pull request 'fix: Backtesting #5: Position tracking + P&L metrics (#319)' (#354) from fix/issue-319 into master 2026-02-27 13:35:08 +01:00
openhands
cf8e7ee6ee fix: address review feedback on PositionTracker and StrategyExecutor
- 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>
2026-02-27 12:02:29 +00:00
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
johba
a491ecb7d9 Merge pull request 'fix: Get KRK: inline swap widget for local dev, Uniswap link for production (#136)' (#338) from fix/issue-136 into master 2026-02-27 12:03:02 +01:00
openhands
f80565499e ci: retrigger after infra failure 2026-02-27 10:41:46 +00:00
openhands
cf4e401d03 fix: address review feedback on LocalSwapWidget and CheatsView
- LocalSwapWidget: move useWallet() to top-level <script setup> (was
  incorrectly called inside async buyKrk() event handler)
- LocalSwapWidget + CheatsView: fix misleading toast — all transactions
  are fully confirmed at that point, so say 'Swap complete' not 'Swap
  submitted'
- LocalSwapWidget: add $KRK sigil to warning/hint text for consistency
  with GetKrkView
- LocalSwapWidget: add comment on amountOutMinimum: 0n explaining it is
  intentional for a no-MEV local anvil environment
- CheatsView: apply same useWallet() fix (pre-existing anti-pattern)
- docs/ENVIRONMENT.md: document VITE_ENABLE_LOCAL_SWAP and related
  VITE_ variables in a new webapp env-var table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 10:32:04 +00:00
openhands
1b647f844a ci: fix clone auth — move netrc creds from environment to settings
woodpeckerci/plugin-git reads credentials via PLUGIN_NETRC_* env vars
(set from settings:), not CI_NETRC_* (set from environment:). The
previous fix in 57deaaa put the secret under environment:, so the
plugin never populated .netrc and git fell back to prompting, which
fails with GIT_TERMINAL_PROMPT=0.

Fix both ci.yml and e2e.yml.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 09:41:51 +00:00
openhands
aef608b656 ci: retrigger after infra failure 2026-02-27 09:30:40 +00:00
johba
19df05843d Merge pull request 'fix: Backtesting #4: Deploy KrAIken contracts + recenter execution loop (#318)' (#349) from fix/issue-318 into master 2026-02-27 10:26:12 +01:00
johba
1f019ddacc Merge pull request 'fix: uint256ToBytesLittleEndian silently truncates above 2³²−1 (#294)' (#337) from fix/issue-294 into master 2026-02-27 10:20:02 +01:00
openhands
84203294af fix: Backtesting #4: Deploy KrAIken contracts + recenter execution loop (#318)
- Add BacktestKraiken.sol: extends MockToken with Kraiken-compatible interface
  (dual mint overloads — public mint(address,uint256) for EventReplayer and
  restricted mint(uint256) for LiquidityManager; peripheryContracts() stubs
  staking pool as address(0))

- Add KrAIkenDeployer.sol: library deploying OptimizerV3Push3 + LiquidityManager
  on the shadow pool, wiring BacktestKraiken permissions, setting fee destination,
  and funding LM with configurable initial mock-WETH capital (default 10 ETH)

- Add StrategyExecutor.sol: time-based recenter trigger (configurable block
  interval, default 100 blocks); logs block, pre/post positions (Floor/Anchor/
  Discovery tick ranges + liquidity), fees collected, and revert reason on skip;
  negligible-impact assumption documented as TODO(#319)

- Modify EventReplayer.sol: add overloaded replay() accepting an optional
  StrategyExecutor hook; maybeRecenter() called after each block advancement
  without halting replay on failure

- Modify BacktestRunner.s.sol: replace tokenA/B with MockWETH + BacktestKraiken,
  integrate KrAIkenDeployer + StrategyExecutor into broadcast block; configurable
  via RECENTER_INTERVAL and INITIAL_CAPITAL_WETH env vars; executor.logSummary()
  printed after replay

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 09:00:22 +00:00
johba
2ffdd55b4c Merge pull request 'fix: Backtesting #3: Replay historical Swap/Mint/Burn events against shadow pool (#317)' (#334) from fix/issue-317 into master 2026-02-27 09:40:03 +01:00
johba
b8e48a3d33 Merge pull request 'fix: Landing cleanup: 404 route, German comments, dead code, orphaned heading (#306)' (#346) from fix/issue-306 into master 2026-02-27 09:26:19 +01:00
openhands
17b100ef2a fix: address AI review feedback (round 2) for #317 event replay
- Guard final drift sample with `idx % LOG_INTERVAL != 0` to prevent
  double-counting stats when totalReplayed is an exact multiple of
  LOG_INTERVAL (the loop's _logCheckpoint already fired for that state)
- Hoist pool.slot0() before the guard and pass finalSqrtPrice/finalTick
  to _logSummary(), eliminating the redundant slot0 read inside it

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 07:55:53 +00:00
openhands
1e6f817cf4 fix: Landing cleanup: 404 route, German comments, dead code, orphaned heading (#306)
- Add /:pathMatch(.*)*  catch-all route that redirects to / so unknown
  URLs no longer render blank
- Replace German inline comments in scrollBehavior with English equivalents
- Remove seven dead `// group: "navbar"` comments from /docs route and its
  child routes (the live group: 'navbar' property on the parent is kept)
- HomeView.vue and HomeViewMixed.vue already carry the renamed
  "Verified On-Chain" heading with supporting copy; no changes needed there

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 07:53:42 +00:00
openhands
ac32a1849c ci: retrigger after infra failure 2026-02-27 07:30:34 +00:00
johba
8c336ae0f5 Merge pull request 'fix: Stake.sol: exitPosition guard order (owner check before existence) (#307)' (#336) from fix/issue-307 into master 2026-02-27 08:14:09 +01:00
openhands
cd065275be fix: address AI review feedback for #317 event replay
- Cache pool.tickSpacing() as immutable in EventReplayer constructor
  to avoid a repeated external call per _replayMint() invocation
- Rename driftCount → driftCheckpoints for consistency with log label
- Add sqrtDriftBps to the per-checkpoint progress log line, using the
  now-live lastExpectedSqrtPrice field (previously written but never read)
- Guard _replaySwap(): skip and count events where amountSpecified ≤ 0,
  which would silently flip exact-input into exact-output mode
- Add a final drift sample after the while-loop for trailing events not
  covered by the last LOG_INTERVAL checkpoint
- Move EventReplayer construction outside the broadcast block in
  BacktestRunner (it uses vm.* cheat codes incompatible with real RPC)
- Change second vm.closeFile() from try/catch to a direct call so errors
  surface rather than being silently swallowed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 07:09:29 +00:00
openhands
bce4059de9 fix: Get KRK: inline swap widget for local dev, Uniswap link for production (#136)
- Add `VITE_ENABLE_LOCAL_SWAP` env var to config.ts (defaults false)
- Create LocalSwapWidget.vue: inline ETH→KRK swap (wrap→approve→exactInputSingle)
- GetKrkView.vue: show LocalSwapWidget when VITE_ENABLE_LOCAL_SWAP=true, Uniswap link otherwise
- docker-compose.yml: set VITE_ENABLE_LOCAL_SWAP=true for webapp service

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 06:55:41 +00:00
openhands
49d7d708d1 fix: uint256ToBytesLittleEndian silently truncates above 2³²−1 (#294) 2026-02-27 06:43:08 +00:00
openhands
6eacfe1975 fix: \uint256ToBytesLittleEndian\ silently truncates above 2³²−1 (#294)
Expand the output buffer from 4 bytes to 32 bytes and iterate all 32
positions, so values ≥ 2³² are encoded correctly instead of silently
dropped. Update tests to assert 32-byte output and add coverage for
2³², 2¹²⁸, and max uint256 roundtrips.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 06:42:59 +00:00
openhands
24fdcd3dcd fix: Stake.sol: exitPosition guard order (owner check before existence) (#307)
Check pos.creationTime == 0 before pos.owner != msg.sender so that
calling exitPosition on a non-existent position correctly reverts with
PositionNotFound instead of the misleading NoPermission(caller, 0x0).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 06:33:32 +00:00
openhands
a884f8a5c9 ci: retrigger after infra failure 2026-02-27 06:27:58 +00:00
johba
9341673a1a Merge pull request 'fix: Ponder: fix mintNextHourProjected divisor, dead param, dead code (#308)' (#333) from fix/issue-308 into master 2026-02-27 07:20:02 +01:00
openhands
a3eb406e46 fix: Backtesting #3: Replay historical Swap/Mint/Burn events against shadow pool (#317)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 06:17:54 +00:00
openhands
896fffb2e8 fix: Backtesting #3: Replay historical Swap/Mint/Burn events against shadow pool (#317)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 06:12:03 +00:00
johba
00037dc713 Merge pull request 'fix: Backtesting #2: Foundry script skeleton + Uniswap V3 shadow pool deployment (#316)' (#332) from fix/issue-316 into master 2026-02-27 06:48:19 +01:00
openhands
a4a3a85fdc fix: Ponder: fix mintNextHourProjected divisor, dead param, dead code (#308) 2026-02-27 05:47:51 +00:00
openhands
70e49b2546 fix: suppress compiler warnings in BacktestRunner (#316)
- Add `view` to _parseSqrtPriceFromFile and _resolveSqrtPrice
- Remove unused IUniswapV3Pool import

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 05:12:45 +00:00
openhands
96b06bd9fe fix: Backtesting #2: Foundry script skeleton + Uniswap V3 shadow pool deployment (#316)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 05:08:27 +00:00
johba
c540d56d08 Merge pull request 'fix: Backtesting #1: Event fetcher (Infura → JSON Lines cache) (#315)' (#331) from fix/issue-315 into master 2026-02-27 00:12:51 +01:00
openhands
c33bdbaad5 fix: address review feedback on fetch-events.ts (#315)
- Replace hardcoded Infura API key with INFURA_API_KEY env var; fail fast
  with a helpful message if unset and no --rpc-url is given
- Add onchain/script/backtesting/.gitignore (cache/) instead of relying on
  the opaque root pattern; remove force-tracked cache/.gitkeep (mkdirSync
  creates the directory at runtime)
- Document resume constraint: reliable only when both --start-block and
  --end-block are explicit, or --output is set
- Fix batch-number display: derive batchNum inside the loop from the actual
  `from` block so it stays correct when resumeFromBlock isn't BATCH_SIZE-aligned
- Guard log.logIndex === null consistently with blockNumber/transactionHash
- console.warn on decode errors instead of silently discarding them

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 22:45:40 +00:00
openhands
df89b8c2da fix: Backtesting #1: Event fetcher (Infura → JSON Lines cache) (#315)
Add onchain/script/backtesting/fetch-events.ts — a tsx script that:
- Fetches Swap/Mint/Burn events from a Uniswap V3 pool via Infura (Base mainnet)
- Batches eth_getLogs in 2 000-block chunks with 100 ms inter-batch delay
- Decodes each log with viem and writes one JSON Line per event
- Supports resume: reads last block from existing cache file on re-run
- Retries with exponential back-off on 429 / rate-limit errors
- Prints per-batch progress: "Fetching blocks X-Y... N events (B/T batches)"

Also adds package.json, tsconfig.json, and cache/.gitkeep.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 22:04:43 +00:00
johba
52411e881a Merge pull request 'revert: Remove premature backtesting code (#320)' (#328) from revert/backtesting-320 into master
Reviewed-on: https://codeberg.org/johba/harb/pulls/328
2026-02-26 22:21:37 +01:00
johba
50f985ef6f Merge pull request 'fix: CollapseActive: null guard on total computed + remove redundant BigInt casts (#309)' (#327) from fix/issue-309 into master 2026-02-26 22:04:51 +01:00
openhands
4a6256b941 Revert "Merge pull request 'fix: Backtesting #6: Baseline strategies (HODL, full-range, fixed-width) + reporting (#320)' (#322) from fix/issue-320 into master"
This reverts commit 1e5ac0de80, reversing
changes made to 6526928b67.
2026-02-26 20:45:19 +00:00
openhands
63ddf14a5c fix: CollapseActive: null guard on total computed + remove redundant BigInt casts (#309)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 20:42:17 +00:00
johba
c73f0e8bc1 Merge pull request 'fix: Remove dead Optimizer V2/V3 — Push3 is the active optimizer (#312)' (#321) from fix/issue-312 into master 2026-02-26 20:57:52 +01:00
openhands
2a7afbf6d2 fix: Increase test stake amount to 1000 — base Optimizer wider anchor raises minStake 2026-02-26 19:37:12 +00:00
openhands
2d25200582 fix: Update E2E tests for Optimizer (base) — drop OptimizerV3 bear-market constants
- 01-acquire-and-stake: replace flat 3 s wait with a 30 s polling loop so
  Ponder indexing lag no longer causes a spurious positions.length=0 failure.

- 05-optimizer-integration test 1: replace hard-coded OptimizerV3 bear-market
  constants (anchorShare=3e17, anchorWidth=100, discoveryDepth=3e17) with
  Optimizer.sol invariant checks:
    capitalInefficiency + anchorShare == 1e18
    discoveryDepth == anchorShare
    anchorWidth ∈ [10, 80]

- 05-optimizer-integration test 2: decouple bootstrap-position assertion from
  current optimizer state.  Earlier tests change staking state, so the current
  optimizer anchorWidth differs from the one used at bootstrap time.  Instead,
  reverse-calculate the implied anchorWidth from the observed anchor spread and
  verify it lies within [10, 80].

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 19:37:12 +00:00
openhands
d9bfedcfcc ci: retrigger after infra failure 2026-02-26 19:37:12 +00:00
openhands
99d9c563d6 fix: Use Optimizer (base) in deploy scripts — Push3 lacks initialize/getLiquidityParams
OptimizerV3Push3 is an equivalence-proof contract with only isBullMarket().
It cannot serve as an ERC1967Proxy implementation because it has no initialize()
or getLiquidityParams(). The CI bootstrap was failing because the proxy
deployment reverted when calling initialize() on the Push3 implementation.

Switch deploy scripts to Optimizer.sol (the base UUPS contract) which has the
full interface required by ERC1967Proxy and LiquidityManager.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 19:37:12 +00:00
openhands
e925538309 fix: Remove dead Optimizer V2/V3 — Push3 is the active optimizer (#312)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 19:37:12 +00:00
johba
1e5ac0de80 Merge pull request 'fix: Backtesting #6: Baseline strategies (HODL, full-range, fixed-width) + reporting (#320)' (#322) from fix/issue-320 into master 2026-02-26 18:02:54 +01:00
openhands
9061f8e8f6 fix: Address AI review findings for backtesting baseline strategies (#320)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 16:39:47 +00:00
openhands
5205ea6f4a fix: Backtesting #6: Baseline strategies (HODL, full-range, fixed-width) + reporting (#320)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 16:11:15 +00:00
johba
6526928b67 Merge pull request 'fix: Landing copy: fix immutable overclaim + sync Mixed variant floor copy (#310)' (#311) from fix/issue-310 into master 2026-02-26 15:02:46 +01:00