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

100 lines
4.3 KiB
Solidity

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.19;
import { MockToken } from "./MockToken.sol";
import { BacktestKraiken } from "./BacktestKraiken.sol";
import { OptimizerV3Push3 } from "../../src/OptimizerV3Push3.sol";
import { LiquidityManager } from "../../src/LiquidityManager.sol";
/**
* @notice Deployment result for the KrAIken system on the shadow pool.
*/
struct KrAIkenSystem {
BacktestKraiken kraiken;
/// @dev OptimizerV3Push3 is used as the optimizer address. It does not implement
/// getLiquidityParams(), so LiquidityManager's try/catch falls back to safe
/// bear-mode defaults on every recenter. This is intentional for backtesting.
OptimizerV3Push3 optimizer;
LiquidityManager lm;
}
/**
* @title KrAIkenDeployer
* @notice Library that deploys the KrAIken protocol contracts on top of a shadow pool
* for backtesting purposes.
*
* Deployment order follows DeployLocal.sol:
* 1. Deploy OptimizerV3Push3 (no proxy — it only exposes isBullMarket(), so LM falls
* back to bear-mode defaults via try/catch on every recenter call).
* 2. Deploy LiquidityManager pointing at the shadow factory + mock WETH + BacktestKraiken.
* 3. Wire BacktestKraiken → LM (setLiquidityManager).
* 4. Set fee destination on LM.
* 5. Fund LM with mock WETH (initial capital).
*
* @dev All functions are `internal` so they are inlined into BacktestRunner.s.sol,
* keeping msg.sender consistent with the broadcaster throughout deployment.
*/
library KrAIkenDeployer {
uint256 internal constant DEFAULT_INITIAL_CAPITAL = 10 ether;
/**
* @notice Deploy the KrAIken system with default initial capital (10 ETH equivalent).
*/
function deploy(
address shadowFactory,
address mockWeth,
address krkToken,
address feeDestination
)
internal
returns (KrAIkenSystem memory sys)
{
return deploy(shadowFactory, mockWeth, krkToken, feeDestination, DEFAULT_INITIAL_CAPITAL);
}
/**
* @notice Deploy the KrAIken system with configurable initial capital.
*
* @param shadowFactory Factory that created the shadow pool.
* @param mockWeth Mock WETH token address (18-decimal ERC-20, freely mintable).
* @param krkToken BacktestKraiken token address (setLiquidityManager not yet called).
* @param feeDestination Address that will receive LP fees; also used as the caller
* for subsequent setRecenterAccess() calls.
* @param initialCapital Mock WETH minted to LM so recenter() has capital to deploy.
*/
function deploy(
address shadowFactory,
address mockWeth,
address krkToken,
address feeDestination,
uint256 initialCapital
)
internal
returns (KrAIkenSystem memory sys)
{
// 1. Deploy OptimizerV3Push3.
// LiquidityManager wraps getLiquidityParams() in a try/catch and falls back to
// safe bear-mode defaults when the call reverts. Since OptimizerV3Push3 only
// exposes isBullMarket(), every recenter uses bear defaults — conservative and
// correct for a baseline backtest.
OptimizerV3Push3 optimizer = new OptimizerV3Push3();
// 2. Deploy LiquidityManager. It computes the pool address from factory + WETH +
// KRK + FEE (10 000). The shadow pool must have been created with the same
// factory and the same fee tier (ShadowPoolDeployer.SHADOW_FEE == 10 000).
LiquidityManager lm = new LiquidityManager(shadowFactory, mockWeth, krkToken, address(optimizer));
// 3. Wire BacktestKraiken → LM so the restricted mint/burn functions work.
BacktestKraiken(krkToken).setLiquidityManager(address(lm));
// 4. Set fee destination (required before setRecenterAccess can be called).
lm.setFeeDestination(feeDestination);
// 5. Fund LM with mock WETH. recenter() uses _getEthBalance() which reads
// weth.balanceOf(address(this)). Pre-funding avoids calling weth.deposit()
// (which MockToken does not implement).
MockToken(mockWeth).mint(address(lm), initialCapital);
sys = KrAIkenSystem({ kraiken: BacktestKraiken(krkToken), optimizer: optimizer, lm: lm });
}
}