#!/usr/bin/env bash set -euo pipefail # Install jq if not available if ! command -v jq >/dev/null 2>&1; then apk add --no-cache jq >/dev/null 2>&1 || apt-get update && apt-get install -y jq >/dev/null 2>&1 || true fi ROOT_DIR=/workspace GIT_BRANCH="${GIT_BRANCH:-}" # Checkout branch if specified if [[ -n "$GIT_BRANCH" ]]; then cd "$ROOT_DIR" git config --global --add safe.directory "$ROOT_DIR" 2>/dev/null || true CURRENT=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown") if [[ "$CURRENT" != "$GIT_BRANCH" ]]; then echo "[bootstrap] Switching to branch: $GIT_BRANCH" # Try local branch first, then remote if git rev-parse --verify "$GIT_BRANCH" >/dev/null 2>&1; then git checkout "$GIT_BRANCH" 2>/dev/null || echo "[bootstrap] WARNING: Could not checkout $GIT_BRANCH" else git fetch origin "$GIT_BRANCH" 2>/dev/null || true git checkout "$GIT_BRANCH" 2>/dev/null || echo "[bootstrap] WARNING: Could not checkout $GIT_BRANCH" fi fi fi STATE_DIR=$ROOT_DIR/tmp/containers LOG_DIR=$STATE_DIR/logs SETUP_LOG=$LOG_DIR/setup.log MNEMONIC_FILE=$ROOT_DIR/onchain/.secret.local mkdir -p "$LOG_DIR" : >"$SETUP_LOG" # ── Configure shared bootstrap variables ── ANVIL_RPC=${ANVIL_RPC:-"http://anvil:8545"} CONTRACT_ENV=$STATE_DIR/contracts.env LOG_FILE=$SETUP_LOG ONCHAIN_DIR=$ROOT_DIR/onchain TXNBOT_FUND_VALUE=${TXNBOT_FUND_VALUE:-1ether} # Source shared bootstrap functions # shellcheck source=../scripts/bootstrap-common.sh source "$ROOT_DIR/scripts/bootstrap-common.sh" # ── Local-only helpers ───────────────────────────────────────────────── maybe_set_deployer_from_mnemonic() { if [[ -n "$DEPLOYER_PK" && "$DEPLOYER_PK" != "$DEFAULT_DEPLOYER_PK" ]]; then return fi if [[ -f "$MNEMONIC_FILE" ]]; then local mnemonic pk addr mnemonic="$(tr -d '\n\r' <"$MNEMONIC_FILE")" if [[ -n "$mnemonic" ]]; then pk="$(cast wallet private-key --mnemonic "$mnemonic" --mnemonic-derivation-path "m/44'/60'/0'/0/0")" addr="$(cast wallet address --private-key "$pk")" DEPLOYER_PK=${pk} DEPLOYER_ADDR=${addr} fi fi } derive_txnbot_wallet() { if [[ -f "$MNEMONIC_FILE" ]]; then local mnemonic mnemonic="$(tr -d '\n\r' <"$MNEMONIC_FILE")" if [[ -n "$mnemonic" ]]; then TXNBOT_PRIVATE_KEY="$(cast wallet private-key --mnemonic "$mnemonic" --mnemonic-index 2)" TXNBOT_ADDRESS="$(cast wallet address --private-key "$TXNBOT_PRIVATE_KEY")" bootstrap_log "Derived txnBot wallet: $TXNBOT_ADDRESS (account index 2)" return fi fi # Fallback to hardcoded Anvil account 1 TXNBOT_PRIVATE_KEY=$DEFAULT_TXNBOT_PK TXNBOT_ADDRESS=$DEFAULT_TXNBOT_ADDR bootstrap_log "Using default txnBot wallet: $TXNBOT_ADDRESS" } write_ponder_env() { cat >"$ROOT_DIR/services/ponder/.env.local" <"$txnbot_env" </dev/null 2>&1; then bootstrap_log "Mined 5 blocks" else bootstrap_log "Batch mining failed, using individual evm_mine calls" for i in {1..5}; do cast rpc --rpc-url "$ANVIL_RPC" evm_mine >/dev/null 2>&1 || true done fi bootstrap_log "Pre-mining complete" } # ── Main ─────────────────────────────────────────────────────────────── main() { local start_time start_time=$(date +%s%3N) bootstrap_log "Waiting for Anvil" wait_for_rpc # Idempotency: if deployments-local.json exists and contracts have code, # bootstrap already ran against this Anvil instance — skip. local deploy_file="$ONCHAIN_DIR/deployments-local.json" if [[ -f "$deploy_file" ]]; then local krk_addr krk_addr=$(jq -r '.contracts.Kraiken // empty' "$deploy_file" 2>/dev/null || true) if [[ -n "$krk_addr" ]]; then local code code=$(cast call --rpc-url "$ANVIL_RPC" "$krk_addr" "decimals()(uint8)" 2>/dev/null || true) if [[ -n "$code" && "$code" != "0x" ]]; then bootstrap_log "Already bootstrapped (Kraiken at $krk_addr responds) — skipping" return 0 fi fi fi maybe_set_deployer_from_mnemonic # On forked networks, well-known addresses (Anvil mnemonic accounts) may # have code (e.g. ERC-4337 Account Abstraction proxies on Base Sepolia). # The feeDestination lock in LiquidityManager treats any address with code # as a contract and locks permanently. Strip code so they behave as EOAs. bootstrap_log "Clearing code from deployer + feeDest (fork safety)" cast rpc --rpc-url "$ANVIL_RPC" anvil_setCode "$DEPLOYER_ADDR" "0x" 2>/dev/null || true # 0xf6a3... carries 171 bytes of code on Base mainnet and may also carry code on Base # Sepolia. Clear it before setFeeDestination is called so LiquidityManager does not # permanently lock feeDestinationLocked (#760). cast rpc --rpc-url "$ANVIL_RPC" anvil_setCode "$FEE_DEST" "0x" 2>/dev/null || true derive_txnbot_wallet run_forge_script extract_addresses write_contracts_env bootstrap_vwap fund_liquidity_manager seed_application_state write_deployments_json write_ponder_env write_txn_bot_env fund_txn_bot_wallet prime_chain & local prime_pid=$! wait "$prime_pid" local end_time end_time=$(date +%s%3N) local elapsed_ms=$((end_time - start_time)) local elapsed_sec elapsed_sec=$(awk -v ms="$elapsed_ms" 'BEGIN { printf "%.3f", ms/1000 }') bootstrap_log "Bootstrap complete in ${elapsed_sec}s" bootstrap_log "Kraiken: $KRAIKEN" bootstrap_log "Stake: $STAKE" bootstrap_log "LiquidityManager: $LIQUIDITY_MANAGER" bootstrap_log "txnBot: $TXNBOT_ADDRESS" } main "$@"