harb/onchain/analysis/replay-scenario.sh
2025-08-23 16:10:05 +02:00

211 lines
No EOL
7.1 KiB
Bash
Executable file

#!/bin/bash
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
BOLD='\033[1m'
# Check arguments
if [ $# -lt 1 ]; then
echo "Usage: $0 <RUN_ID> [seed_number]"
echo ""
echo "Examples:"
echo " $0 241218-A7K9 # Replay all scenarios from run"
echo " $0 241218-A7K9 1 # Replay specific seed from run"
echo ""
echo "To find RUN_IDs, check fuzzing_results_recorded_* directories"
exit 1
fi
RUN_ID=$1
SEED=$2
echo -e "${GREEN}=== Scenario Replay Tool ===${NC}"
echo -e "Run ID: ${BOLD}${RUN_ID}${NC}"
# Find the results directory
RESULTS_DIR=$(find . -type d -name "*_*" 2>/dev/null | grep -E "fuzzing_results_recorded.*" | xargs -I {} sh -c 'ls -1 {}/scenario_'${RUN_ID}'_*.json 2>/dev/null && echo {}' | tail -1)
if [ -z "$RESULTS_DIR" ]; then
echo -e "${RED}Error: No results found for Run ID ${RUN_ID}${NC}"
echo ""
echo "Available Run IDs:"
find . -type f -name "scenario_*_seed*.json" 2>/dev/null | sed 's/.*scenario_\(.*\)_seed.*/\1/' | sort -u
exit 1
fi
echo "Found results in: $RESULTS_DIR"
echo ""
# If no seed specified, show available scenarios
if [ -z "$SEED" ]; then
echo -e "${YELLOW}Available scenarios for ${RUN_ID}:${NC}"
for summary in $RESULTS_DIR/summary_${RUN_ID}_seed*.txt; do
if [ -f "$summary" ]; then
SEED_NUM=$(echo $summary | sed "s/.*seed\(.*\)\.txt/\1/")
echo ""
echo -e "${BOLD}Seed $SEED_NUM:${NC}"
grep -E "Profit:|Discovery Reached:" "$summary" | head -2
fi
done
echo ""
echo "To replay a specific scenario, run:"
echo " $0 ${RUN_ID} <seed_number>"
exit 0
fi
# Check if specific scenario files exist
SCENARIO_FILE="$RESULTS_DIR/scenario_${RUN_ID}_seed${SEED}.json"
REPLAY_FILE="$RESULTS_DIR/replay_${RUN_ID}_seed${SEED}.sol"
SUMMARY_FILE="$RESULTS_DIR/summary_${RUN_ID}_seed${SEED}.txt"
if [ ! -f "$SCENARIO_FILE" ]; then
echo -e "${RED}Error: Scenario file not found for seed ${SEED}${NC}"
echo "Looking for: $SCENARIO_FILE"
exit 1
fi
echo -e "${GREEN}=== Scenario Details ===${NC}"
if [ -f "$SUMMARY_FILE" ]; then
cat "$SUMMARY_FILE" | head -20
echo ""
fi
# Create replay test file
# Replace hyphens with underscores for valid Solidity identifier
CONTRACT_SAFE_ID=$(echo $RUN_ID | tr '-' '_')
REPLAY_TEST="test/Replay_${RUN_ID}_Seed${SEED}.t.sol"
echo -e "${YELLOW}Creating replay test file...${NC}"
cat > $REPLAY_TEST << 'EOF'
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import {TestEnvironment} from "./helpers/TestBase.sol";
import {IUniswapV3Pool} from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import {IWETH9} from "../src/interfaces/IWETH9.sol";
import {Kraiken} from "../src/Kraiken.sol";
import {Stake} from "../src/Stake.sol";
import {LiquidityManager} from "../src/LiquidityManager.sol";
import "../analysis/helpers/SwapExecutor.sol";
import "../test/mocks/BullMarketOptimizer.sol";
contract Replay_CONTRACT_ID_Seed_SEED is Test {
TestEnvironment testEnv;
IUniswapV3Pool pool;
IWETH9 weth;
Kraiken kraiken;
Stake stake;
LiquidityManager lm;
bool token0isWeth;
address trader = makeAddr("trader");
address whale = makeAddr("whale");
address feeDestination = makeAddr("fees");
function setUp() public {
// Setup from recorded scenario
testEnv = new TestEnvironment(feeDestination);
BullMarketOptimizer optimizer = new BullMarketOptimizer();
(,pool, weth, kraiken, stake, lm,, token0isWeth) =
testEnv.setupEnvironmentWithOptimizer(SEED_PARITY, feeDestination, address(optimizer));
vm.deal(address(lm), 200 ether);
// Fund traders based on seed
uint256 traderFund = 50 ether + (uint256(keccak256(abi.encodePacked(uint256(SEED_NUM), "trader"))) % 150 ether);
uint256 whaleFund = 200 ether + (uint256(keccak256(abi.encodePacked(uint256(SEED_NUM), "whale"))) % 300 ether);
vm.deal(trader, traderFund * 2);
vm.prank(trader);
weth.deposit{value: traderFund}();
vm.deal(whale, whaleFund * 2);
vm.prank(whale);
weth.deposit{value: whaleFund}();
vm.prank(feeDestination);
lm.recenter();
}
function test_replay_CONTRACT_ID_seed_SEED() public {
console.log("=== Replaying Scenario RUN_ID Seed SEED ===");
uint256 initialBalance = weth.balanceOf(trader);
// INSERT_REPLAY_ACTIONS
uint256 finalBalance = weth.balanceOf(trader);
if (finalBalance > initialBalance) {
uint256 profit = finalBalance - initialBalance;
uint256 profitPct = (profit * 100) / initialBalance;
console.log(string.concat("[INVARIANT VIOLATED] Profit: ", vm.toString(profit / 1e18), " ETH (", vm.toString(profitPct), "%)"));
revert("Trader profited - invariant violated");
} else {
console.log("[OK] No profit");
}
}
function _executeBuy(address buyer, uint256 amount) internal {
if (weth.balanceOf(buyer) < amount) return;
SwapExecutor executor = new SwapExecutor(pool, weth, kraiken, token0isWeth, lm);
vm.prank(buyer);
weth.transfer(address(executor), amount);
try executor.executeBuy(amount, buyer) {} catch {}
}
function _executeSell(address seller, uint256 amount) internal {
if (kraiken.balanceOf(seller) < amount) {
amount = kraiken.balanceOf(seller);
if (amount == 0) return;
}
SwapExecutor executor = new SwapExecutor(pool, weth, kraiken, token0isWeth, lm);
vm.prank(seller);
kraiken.transfer(address(executor), amount);
try executor.executeSell(amount, seller) {} catch {}
}
}
EOF
# Replace placeholders
sed -i "s/CONTRACT_ID/${CONTRACT_SAFE_ID}/g" $REPLAY_TEST
sed -i "s/RUN_ID/${RUN_ID}/g" $REPLAY_TEST
sed -i "s/SEED_NUM/${SEED}/g" $REPLAY_TEST
sed -i "s/SEED_PARITY/$([ $((SEED % 2)) -eq 0 ] && echo "true" || echo "false")/g" $REPLAY_TEST
sed -i "s/_SEED/_${SEED}/g" $REPLAY_TEST
# Insert replay actions from the sol file
if [ -f "$REPLAY_FILE" ]; then
# Extract the function body from replay script
ACTIONS=$(sed -n '/function replayScenario/,/^}/p' "$REPLAY_FILE" | sed '1d;$d' | sed 's/^/ /')
# Use a temporary file for the replacement
awk -v actions="$ACTIONS" '/INSERT_REPLAY_ACTIONS/ {print actions; next} {print}' $REPLAY_TEST > ${REPLAY_TEST}.tmp
mv ${REPLAY_TEST}.tmp $REPLAY_TEST
fi
echo -e "${GREEN}Replay test created: $REPLAY_TEST${NC}"
echo ""
# Run the replay test
echo -e "${YELLOW}Running replay test...${NC}"
echo ""
forge test --match-contract Replay_${CONTRACT_SAFE_ID}_Seed_${SEED} -vv
echo ""
echo -e "${GREEN}=== Replay Complete ===${NC}"
echo ""
echo "To debug further:"
echo " 1. Edit the test file: $REPLAY_TEST"
echo " 2. Add console.log statements or assertions"
echo " 3. Run with more verbosity: forge test --match-contract Replay_${CONTRACT_SAFE_ID}_Seed_${SEED} -vvvv"
echo ""
echo "To visualize positions:"
echo " ./analysis/view-scenarios.sh $RESULTS_DIR"