harb/onchain/analysis/STORAGE_LAYOUT.md
openhands b7260b2eaf chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
  AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00

3.3 KiB

Storage Layout Verification: Optimizer → OptimizerV3 UUPS Upgrade

Date: 2026-02-13 Result: SAFE — storage layout is identical


Inheritance Chain (C3 Linearization)

Both contracts share the same inheritance:

Optimizer/OptimizerV3 → Initializable → UUPSUpgradeable → ERC1967Upgrade

Storage Slot Map

OpenZeppelin Infrastructure (Slot 0)

Offset Type Variable Size
0 uint8 _initialized 1 byte
0 bool _initializing 1 byte (packed)

ERC1967Upgrade uses named constant slots (not sequential):

  • _IMPLEMENTATION_SLOT = 0x360894... — proxy implementation pointer
  • _ADMIN_SLOT = 0xb53127... — proxy admin address
  • _ROLLBACK_SLOT = 0x4910fd... — upgrade rollback check

These do not conflict with sequential storage.

Contract State Variables

Slot Type Variable Optimizer.sol OptimizerV3.sol
1 Kraiken (address) kraiken Line 37 Line 29
2 Stake (address) stake Line 38 Line 30

Both contracts declare the same two state variables in the same order with the same types.


Comparison

Optimizer.sol (V1)                    OptimizerV3.sol
─────────────────────                 ─────────────────────
Slot 0: _initialized, _initializing   Slot 0: _initialized, _initializing
Slot 1: Kraiken private kraiken       Slot 1: Kraiken private kraiken
Slot 2: Stake private stake           Slot 2: Stake private stake
  • No new state variables added in V3
  • No variables removed or reordered
  • No type changes
  • No __gap arrays needed (both are final implementations, not base contracts)

Function Signature Compatibility

Function Optimizer OptimizerV3 Compatible
initialize(address,address) Yes Yes Yes
getLiquidityParams()(uint256,uint256,uint24,uint256) Yes Yes Yes
_authorizeUpgrade(address) Yes Yes Yes
calculateSentiment(uint256,uint256) Yes No (removed) N/A (internal)
isBullMarket(uint256,uint256) No Yes (new) N/A (additive)

The critical external interface (getLiquidityParams) is identical. New functions are additive and don't affect storage.


Upgrade Path

1. Deploy OptimizerV3 implementation contract
2. Call UUPSUpgradeable(proxy).upgradeTo(newImpl)
3. No re-initialization needed (storage persists)
4. Verify: call getLiquidityParams() through proxy → returns V3 binary bear/bull params

The UpgradeOptimizer.sol script at script/UpgradeOptimizer.sol implements this correctly and includes post-upgrade verification.


OptimizerV2 (Intermediate Version)

OptimizerV2.sol also has identical storage layout (same two variables: kraiken, stake). The full upgrade chain Optimizer → OptimizerV2 → OptimizerV3 is safe at every step.


Conclusion

UUPS Upgrade: APPROVED

  • Storage layout: identical across all optimizer versions
  • Proxy infrastructure: preserved (initialization flags, admin slot)
  • No re-initialization required
  • The only change is the algorithm inside getLiquidityParams() — from sentiment-score interpolation to direct 2D binary mapping