bootstrap now discovers the Uniswap pool address from the factory contract and writes both LM_ADDRESS and POOL_ADDRESS to ponder .env.local. Without these, ponder watches hardcoded default addresses that dont exist on the local Anvil fork, causing all protocol stats except holder count to stay zero.
209 lines
7.1 KiB
Bash
Executable file
209 lines
7.1 KiB
Bash
Executable file
#!/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
|
|
|
|
# Derive NETWORK_NAME from FORK_URL if not explicitly set.
|
|
# Callers may override by exporting NETWORK_NAME before starting the stack.
|
|
# Chain ID 8453 = Base mainnet; anything else (including 84532 Base Sepolia) defaults to Sepolia fork.
|
|
if [[ -z "${NETWORK_NAME:-}" ]]; then
|
|
_fork_url="${FORK_URL:-}"
|
|
if [[ -n "$_fork_url" ]]; then
|
|
_chain_id=$(cast chain-id --rpc-url "$_fork_url" 2>/dev/null || echo "")
|
|
if [[ "$_chain_id" == "8453" ]]; then
|
|
NETWORK_NAME="BASE_MAINNET_LOCAL_FORK"
|
|
else
|
|
NETWORK_NAME="BASE_SEPOLIA_LOCAL_FORK"
|
|
fi
|
|
else
|
|
NETWORK_NAME="BASE_SEPOLIA_LOCAL_FORK"
|
|
fi
|
|
fi
|
|
|
|
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" <<EOPONDER
|
|
PONDER_NETWORK=$NETWORK_NAME
|
|
KRAIKEN_ADDRESS=$KRAIKEN
|
|
STAKE_ADDRESS=$STAKE
|
|
LM_ADDRESS=$LIQUIDITY_MANAGER
|
|
POOL_ADDRESS=$POOL_ADDRESS
|
|
START_BLOCK=$DEPLOY_BLOCK
|
|
PONDER_RPC_URL_${NETWORK_NAME}=$ANVIL_RPC
|
|
DATABASE_URL=postgresql://ponder:ponder_local@postgres:5432/ponder_local
|
|
DATABASE_SCHEMA=ponder_local_${DEPLOY_BLOCK}
|
|
EOPONDER
|
|
}
|
|
|
|
write_txn_bot_env() {
|
|
local txnbot_env=$STATE_DIR/txnBot.env
|
|
local provider_url=${TXNBOT_PROVIDER_URL:-$ANVIL_RPC}
|
|
local graphql_endpoint=${TXNBOT_GRAPHQL_ENDPOINT:-http://ponder:42069/graphql}
|
|
cat >"$txnbot_env" <<EOTXNBOT
|
|
ENVIRONMENT=$NETWORK_NAME
|
|
PROVIDER_URL=$provider_url
|
|
PRIVATE_KEY=$TXNBOT_PRIVATE_KEY
|
|
LM_CONTRACT_ADDRESS=$LIQUIDITY_MANAGER
|
|
STAKE_CONTRACT_ADDRESS=$STAKE
|
|
GRAPHQL_ENDPOINT=$graphql_endpoint
|
|
WALLET_ADDRESS=$TXNBOT_ADDRESS
|
|
PORT=43069
|
|
EOTXNBOT
|
|
}
|
|
|
|
prime_chain() {
|
|
bootstrap_log "Pre-mining 5 blocks (minimal warmup for fast Ponder sync)..."
|
|
if cast rpc --rpc-url "$ANVIL_RPC" anvil_mine "0x5" "0x1" >/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 "$@"
|