Commit graph

4 commits

Author SHA1 Message Date
openhands
78246ed399 fix: fix: Debug failing staking-safe attack in evolution fitness (#596)
Stake.nextPositionId starts at 654_321, so attack files cannot use literal
on-chain IDs (e.g. positionId=1 always reverts with PositionNotFound).

Fix AttackRunner to treat the JSONL positionId field as a 1-based index into
the list of positions created by stake ops during the current run:
- Add IStake.snatch returns (uint256) to the interface so the returned ID is
  captured.
- Track returned IDs in _stakedPositionIds[] (inserted in creation order).
- _executeUnstake resolves positionId to _stakedPositionIds[positionId-1]
  before calling exitPosition, matching the natural "unstake position 1"
  semantics in the attack DSL.

KRK approval for Stake was already present in _setup(); no other changes needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 07:10:13 +00:00
openhands
d6ca28ae32 fix: AttackRunner round-3 review findings
- **Bug**: Fix JSON malformation in _snapshotPositions — closing literal was '"}}}' (three
  braces) but only '"}}'  is needed (close discovery{} + positions{}). The third brace
  prematurely closed the root object, making every snapshot unparseable downstream.

- **Nit**: _executeStake local variable renamed taxRateIndex → taxRate to match the
  IStake interface and Stake.sol. JSONL field key '.taxRateIndex' is kept for backward
  compatibility with existing attack files; the comment and NatDoc header now say so.

- **Nit**: recenter_is_up now emits JSON null (not false) before the first recenter call,
  via a new _hasRecentered flag. Downstream parsers can distinguish "no recenter yet"
  from "last recenter moved price down" (false). _hasRecentered is set to true alongside
  _lastRecenterIsUp in the recenter handler.

- **Nit**: Added a comment to _logSnapshot explaining that pool.slot0() is a view call
  and forge-std finalises broadcast state before executing it, so tick/sqrtPrice are
  always post-broadcast accurate.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 17:51:18 +00:00
openhands
297442083d fix: AttackRunner review findings — TVL accuracy, recenter capture, discovery ethValue
- **Bug**: `_positionEthValue` now sums both the ETH component and the KRK component
  (converted to ETH via `FullMath.mulDiv` at current sqrtPriceX96) so `lm_eth_total`
  correctly reflects LM TVL for all price ranges (below/in/above range).

- **Bug**: `recenter()` return value (`bool isUp` — price direction) is now captured in
  `_lastRecenterIsUp` state variable and emitted as `"recenter_is_up"` in every snapshot.
  Note: `recenter()` reverts on failure; `false` means price moved *down*, not a no-op.

- **Bug**: Discovery position now emits `"ethValue"` in its snapshot JSON object,
  matching the floor and anchor fields for symmetric automated parsing.

- **Warning**: `IStake.snatch` interface parameter renamed `taxRateIndex` → `taxRate` to
  match the actual `Stake.sol` signature (the value is a raw rate, not a lookup index).

- **Warning**: Unknown op codes in the JSONL file now emit a `console.log` warning
  instead of silently skipping, catching typos in attack sequences.

- **Nit**: `_setup()` now wraps 9 000 ETH (up from 1 000) to cover heavy buy sequences
  that would otherwise exhaust the adversary's WETH.

- **Nit**: `_computeVwapTick` documents the int128 overflow guard and its tick=0 sentinel
  meaning so callers can distinguish "VWAP unavailable" from tick zero.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 17:14:34 +00:00
openhands
c8453f6a33 fix: Backtesting: replay red-team attack sequences against optimizer candidates (#536)
- Add AttackRunner.s.sol: structured forge script that reads attack ops from a
  JSONL file (ATTACK_FILE env), executes them against the local Anvil deployment,
  and emits full state snapshots (tick, positions, VWAP, optimizer output,
  adversary balances) as JSON lines after every recenter and at start/end.

- Add 5 canonical attack files in onchain/script/backtesting/attacks/:
  * il-crystallization-15.jsonl  — 15 buy-recenter cycles + sell (extraction)
  * il-crystallization-80.jsonl  — 80 buy-recenter cycles + sell (extraction)
  * fee-drain-oscillation.jsonl  — buy-recenter-sell-recenter oscillation
  * round-trip-safe.jsonl        — 20 full round-trips (regression: safe)
  * staking-safe.jsonl           — staking manipulation (regression: safe)

- Add scripts/harb-evaluator/export-attacks.py: parses red-team-stream.jsonl
  for tool_use Bash blocks containing cast send commands and converts them to
  AttackRunner-compatible JSONL (buy/sell/recenter/stake/unstake/mint_lp/burn_lp).

- Update scripts/harb-evaluator/red-team.sh: after each agent run, automatically
  exports the attack sequence via export-attacks.py and replays it with
  AttackRunner to capture structured snapshots in tmp/red-team-snapshots.jsonl.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 02:08:06 +00:00