harb/onchain/script/backtesting/BacktestKraiken.sol
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

94 lines
3.6 KiB
Solidity

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.19;
import { MockToken } from "./MockToken.sol";
/**
* @title BacktestKraiken
* @notice Kraiken-compatible ERC-20 for backtesting purposes only.
*
* Dual mint interface:
* - MockToken.mint(address to, uint256 amount) — public, inherited from MockToken.
* Used by EventReplayer to seed historical pool positions without access checks.
* - mint(uint256 amount) — restricted to liquidityManager.
* Mirrors Kraiken.mint(uint256) so LiquidityManager operates unchanged.
*
* burn(uint256), setPreviousTotalSupply(), outstandingSupply(), and peripheryContracts()
* mirror the real Kraiken interface that LiquidityManager depends on.
*
* Omissions vs real Kraiken (acceptable for backtesting):
* - No staking pool proportional minting (no Stake.sol deployed).
* - No ERC20Permit extension.
* - setLiquidityManager() has no deployer-only guard (script context only).
*/
contract BacktestKraiken is MockToken {
address public liquidityManager;
uint256 public previousTotalSupply;
constructor() MockToken("Backtesting KRK", "bKRK", 18) { }
modifier onlyLiquidityManager() {
require(msg.sender == liquidityManager, "only liquidity manager");
_;
}
// -------------------------------------------------------------------------
// Wiring
// -------------------------------------------------------------------------
/**
* @notice Wire the LiquidityManager. Can only be called once.
*/
function setLiquidityManager(address lm) external {
require(liquidityManager == address(0), "already set");
liquidityManager = lm;
}
// -------------------------------------------------------------------------
// LM-restricted supply management (mirrors Kraiken interface)
// -------------------------------------------------------------------------
/**
* @notice Mint `amount` tokens to the LiquidityManager.
* Overloads MockToken.mint(address,uint256) — the two signatures
* have distinct ABI selectors and coexist without conflict.
*/
function mint(uint256 amount) external onlyLiquidityManager {
if (amount > 0) _mint(liquidityManager, amount);
if (previousTotalSupply == 0) previousTotalSupply = totalSupply();
}
/**
* @notice Burn `amount` tokens from the LiquidityManager's balance.
*/
function burn(uint256 amount) external onlyLiquidityManager {
if (amount > 0) _burn(liquidityManager, amount);
}
/**
* @notice Called by LM when isUp == true during recenter.
*/
function setPreviousTotalSupply(uint256 ts) external onlyLiquidityManager {
previousTotalSupply = ts;
}
// -------------------------------------------------------------------------
// View helpers (mirrors Kraiken interface)
// -------------------------------------------------------------------------
/**
* @notice Total supply minus the LM's own balance (trader-held supply).
*/
function outstandingSupply() external view returns (uint256) {
return totalSupply() - balanceOf(liquidityManager);
}
/**
* @notice Returns (liquidityManager, address(0)) — no staking pool in backtests.
* LiquidityManager._getOutstandingSupply() calls this to exclude staked KRK;
* returning address(0) for stakingPool skips that subtraction safely.
*/
function peripheryContracts() external view returns (address, address) {
return (liquidityManager, address(0));
}
}