Security
Audit delta one-pager
Last updated September 30, 2026
Baseline
Solidity baseline: Git ca33ab4 (pre–PR #108 mainnet-deployment). Pre–PR #108 mainnet-deployment Solidity baseline.
Mainnet today vs pending bytecode
The successor stack is fully deployed and live: vault 0.0.10824879, bridge 0.0.10824903, manager 0.0.10824897, LP strategy 0.0.10824909, composite staking, staking allocator, LP allocator 0.0.10826537, 4-phase keeper 0.0.10826535, governance, reused LYNX 0.0.9633601. Sourcify exact-match on Hedera mainnet (chain 295) at merge 164880a.
Paginated LP harvest (branch 106-lp-harvest-is-capped-at-50-txs, tip d043385) is the only pending mainnet bytecode change — not merged to main. Live LP strategy has no harvestPassActive.
LP Range Manager (release-gate-lp-range-manager) is not on main and not deployed — a separate tranche atop paginated harvest.
harvestSwapDustThreshold = 10000 was set via setHarvestSwapConfig after phase-0 consensus status 328 (29 Aug 2026) — config only, no redeploy.
Layered git deltas (from ca33ab4)
| Layer | Git ref | On main? | On mainnet? | Production .sol changed |
|---|---|---|---|---|
| A — Deploy / ops | mainnet-deployment → 164880a | Yes | Yes | LynxKeeperRouter.sol only (+ test mocks) |
| B — Paged harvest | 106-lp-harvest-is-capped-at-50-txs | No | No (pending deploy) | SaucerSwapLiquidityStrategy, LynxKeeperRouter, ILpHarvestPaged |
| C — LP Range Manager | release-gate-lp-range-manager | No | No | Layer B + LynxLpAllocator, LpRangeMath, TickMath, ILynxLpAllocator, rotateClosePosition |
Shipping B (or B+C) redeploys LP strategy + keeper (+ allocator for C), migrates SaucerSwap NFTs, and registers the new strategy on the manager. Vault, bridge, and manager are not redeployed.
Layer A — Deploy delta (ca33ab4 → 164880a)
Aug 2026 successor cutover + keeper phase-split redeploy (27 Aug 2026).
LynxKeeperRouter +76/−29 lines vs ca33ab4 (105 LOC churn; vault/bridge/manager unchanged).
- OPS_PHASE_COUNT = 4; opsPhase state machine; phaseGapSec.
- weeklyOps(): one phase per Hedera transaction, then schedule next (HIP-1215 status 328 mitigation).
- startWeeklyLoop / stopWeeklyLoop / retrySchedule updated for schedule recovery.
Unchanged: LynxVault, LynxHTSBridge, StrategyManager, SaucerSwapLiquidityStrategy, LynxLpAllocator, staking, governance.
Layer A is keeper orchestration only. ACL intent unchanged: onlyOpsExecutor, HSS targets weeklyOps() only, permissionless body-free retrySchedule. I1–I9 vault/bridge .sol paths are what is live today.
Layer B — Paginated harvest
Hedera caps transactions at 50 child records (consensus abort 328). Monolithic LP harvest() inside a single phase-0 weeklyOps exceeded the cap.
+285/−43 lines across keeper, LP strategy, and ILpHarvestPaged vs 164880a (328 LOC churn).
| Component | Change |
|---|---|
| SaucerSwapLiquidityStrategy | harvest() = one page per call (collect XOR swap); harvestPassActive; caps maxHarvestCollects / maxHarvestSwaps; default dust 10_000; HarvestPassInProgress; resetHarvestPass / abortHarvestPass |
| LynxKeeperRouter | Phase 0 holds while harvestPassPending(); MAX_LP_HARVEST_PAGES / MAX_PHASE0_FAILURES; unfinished pass aborted when phase 0 advances |
| ILpHarvestPaged | Keeper-facing views + abortHarvestPass |
Redeploy LP strategy + keeper; migrate NFTs. Manager/vault/bridge unchanged.
| Invariant | Effect |
|---|---|
| I1, I3, I6–I9 | No vault/bridge .sol change |
| I2, I4 | Indirect: harvest still onlyManager; per-page gain/loss must preserve NAV identity |
| I5 | Harvest ACL unchanged; new owner/keeper abort/reset on LP strategy |
| I10–I12 | Extend fuzz after multi-page harvest |
Layer C — LP Range Manager
Not merged to main; not on mainnet. Internal deep audit vs 164880a: router 24/24, allocator 19/19, LP strategy 29/29 entry points. Remediations PT-010–PT-030 on branch tip.
- LynxLpAllocator: RangePolicy, rebalanceOne, OOR gates, opsRangeFrozen, emergencyWiden / emergencyUnwind, pairToken tracking
- LynxKeeperRouter: OPS_PHASE_COUNT = 6; phase 3 _rangeOps(); oorDivertActive → phase 4 allocateSurplus may push 100% to staking (StrategyManager bytecode unchanged)
- SaucerSwapLiquidityStrategy: rotateClosePosition (automated rotate close)
- Libraries: LpRangeMath, TickMath linked into allocator
+2440/−139 lines on seven production paths vs 164880a (2579 LOC churn; branch only, not mainnet).
Live mainnet today runs 4 phases (Layer A only). Range/split deploy phases 3–5 do not apply on chain until Layer C ships.
| Phase | Action |
|---|---|
| 0 | Paged LP harvest; may stay on 0; leaving 0 aborts unfinished pass |
| 1 | Staking harvest |
| 2 | Refill buffer + one inactive LP drain + recovery pull |
| 3 | Range ops: freeze gate, OOR divert flag, ≤1 rebalanceOne |
| 4 | allocateSurplus (divert → 100% staking via push; else pushSplit) |
| 5 | deployLpIdle → wrap to phase 0 after weeklyIntervalSec |
| Contract | In delta? | Notes |
|---|---|---|
| LynxVault | No | Unchanged — I1–I3, I7, I9 |
| LynxHTSBridge | No | Unchanged — I1 |
| StrategyManager | No | Unchanged — I4, I8; existing push / pushSplit / reportGain only |
| LynxCompositeStakingStrategy | No | More WHBAR when OOR divert active (routing only) |
| SaucerSwapLiquidityStrategy | B + C | I2/I4 via harvest + rotate |
| LynxLpAllocator | C | New logic; no vault shares or LYNX supply key |
| LynxKeeperRouter | A + B + C | Orchestration; I5 ACL unchanged |
| Review unit | Layers | Redeploy to ship |
|---|---|---|
| LynxKeeperRouter | A live; B pending; C future | Yes when B/C ship |
| SaucerSwapLiquidityStrategy | B (+ C rotate/harvest) | Yes (NFTs bound to strategy address) |
| LynxLpAllocator | C only | Yes when C ships |
| Vault / bridge / manager / staking / gov | — | No |