refactor: consolidate CI and local dev orchestration (#108)

## Summary
- Extract shared bootstrap functions into `scripts/bootstrap-common.sh` (eliminates ~120 lines of duplicated forge/cast commands from e2e.yml)
- Create reusable `scripts/wait-for-service.sh` for health checks (replaces 60-line inline wait-for-stack)
- Merge dev and CI entrypoints into unified scripts branching on `CI` env var (delete `docker/ci-entrypoints/`)
- Replace 4 per-service CI Dockerfiles with parameterized `docker/Dockerfile.service-ci`
- Add `sync-tax-rates.mjs` to CI image builder stage
- Fix: CI now grants txnBot recenter access (was missing)
- Fix: txnBot funding parameterized (CI=10eth, local=1eth)
- Delete 5 obsolete migration docs and 4 DinD integration files

Net: -1540 lines removed

Closes #107

## Test plan
- [ ] E2E pipeline passes (bootstrap sources shared script, services use old images with commands override)
- [ ] build-ci-images pipeline builds all 4 services with unified Dockerfile
- [ ] Local dev stack boots via `./scripts/dev.sh start`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/harb/pulls/108
This commit is contained in:
johba 2026-02-03 12:07:28 +01:00
parent 4277f19b68
commit e5e1308e72
45 changed files with 882 additions and 2627 deletions

View file

@ -26,48 +26,30 @@ if [[ -n "$GIT_BRANCH" ]]; then
fi
fi
fi
STATE_DIR=$ROOT_DIR/tmp/containers
LOG_DIR=$STATE_DIR/logs
SETUP_LOG=$LOG_DIR/setup.log
CONTRACT_ENV=$STATE_DIR/contracts.env
TXNBOT_ENV=$STATE_DIR/txnBot.env
MNEMONIC_FILE=$ROOT_DIR/onchain/.secret.local
mkdir -p "$LOG_DIR"
: >"$SETUP_LOG"
# ── Configure shared bootstrap variables ──
ANVIL_RPC=${ANVIL_RPC:-"http://anvil:8545"}
FEE_DEST=0xf6a3eef9088A255c32b6aD2025f83E57291D9011
WETH=0x4200000000000000000000000000000000000006
SWAP_ROUTER=0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4
MAX_UINT=0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
DEFAULT_DEPLOYER_PK=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
DEFAULT_DEPLOYER_ADDR=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
DEPLOYER_PK=${DEPLOYER_PK:-$DEFAULT_DEPLOYER_PK}
DEPLOYER_ADDR=${DEPLOYER_ADDR:-$DEFAULT_DEPLOYER_ADDR}
CONTRACT_ENV=$STATE_DIR/contracts.env
LOG_FILE=$SETUP_LOG
ONCHAIN_DIR=$ROOT_DIR/onchain
TXNBOT_FUND_VALUE=${TXNBOT_FUND_VALUE:-1ether}
log() {
echo "[bootstrap] $*"
}
# Source shared bootstrap functions
# shellcheck source=../scripts/bootstrap-common.sh
source "$ROOT_DIR/scripts/bootstrap-common.sh"
BOOTSTRAP_START=$(date +%s%3N)
wait_for_rpc() {
for _ in {1..120}; do
if cast chain-id --rpc-url "$ANVIL_RPC" >/dev/null 2>&1; then
return 0
fi
sleep 1
done
log "Timed out waiting for Anvil at $ANVIL_RPC"
return 1
}
# ── Local-only helpers ─────────────────────────────────────────────────
maybe_set_deployer_from_mnemonic() {
if [[ -n "$DEPLOYER_PK" && -n "$DEPLOYER_ADDR" ]]; then
if [[ -n "$DEPLOYER_PK" && "$DEPLOYER_PK" != "$DEFAULT_DEPLOYER_PK" ]]; then
return
fi
if [[ -f "$MNEMONIC_FILE" ]]; then
@ -76,12 +58,10 @@ maybe_set_deployer_from_mnemonic() {
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=${DEPLOYER_PK:-$pk}
DEPLOYER_ADDR=${DEPLOYER_ADDR:-$addr}
DEPLOYER_PK=${pk}
DEPLOYER_ADDR=${addr}
fi
fi
DEPLOYER_PK=${DEPLOYER_PK:-$DEFAULT_DEPLOYER_PK}
DEPLOYER_ADDR=${DEPLOYER_ADDR:-$DEFAULT_DEPLOYER_ADDR}
}
derive_txnbot_wallet() {
@ -91,115 +71,14 @@ derive_txnbot_wallet() {
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")"
log "Derived txnBot wallet: $TXNBOT_ADDRESS (account index 2)"
bootstrap_log "Derived txnBot wallet: $TXNBOT_ADDRESS (account index 2)"
return
fi
fi
# Fallback to hardcoded Anvil account 1
TXNBOT_PRIVATE_KEY=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
TXNBOT_ADDRESS=0x70997970C51812dc3A010C7d01b50e0d17dc79C8
log "Using default txnBot wallet: $TXNBOT_ADDRESS"
}
run_forge_script() {
log "Deploying contracts to fork"
pushd "$ROOT_DIR/onchain" >/dev/null
forge script script/DeployLocal.sol --fork-url "$ANVIL_RPC" --broadcast >>"$SETUP_LOG" 2>&1
popd >/dev/null
}
extract_addresses() {
local run_file
run_file="$(ls -t "$ROOT_DIR/onchain/broadcast/DeployLocal.sol"/*/run-latest.json 2>/dev/null | head -n1)"
if [[ -z "$run_file" ]]; then
log "Deployment artifact not found"
exit 1
fi
log "Using artifact ${run_file#$ROOT_DIR/}"
LIQUIDITY_MANAGER="$(jq -r '.transactions[] | select(.contractName=="LiquidityManager") | .contractAddress' "$run_file" | head -n1)"
KRAIKEN="$(jq -r '.transactions[] | select(.contractName=="Kraiken") | .contractAddress' "$run_file" | head -n1)"
STAKE="$(jq -r '.transactions[] | select(.contractName=="Stake") | .contractAddress' "$run_file" | head -n1)"
DEPLOY_BLOCK="$(jq -r '.receipts[0].blockNumber' "$run_file" | xargs printf "%d")"
if [[ -z "$LIQUIDITY_MANAGER" || "$LIQUIDITY_MANAGER" == "null" ]]; then
log "LiquidityManager address missing"
exit 1
fi
cat >"$CONTRACT_ENV" <<EOCONTRACTS
LIQUIDITY_MANAGER=$LIQUIDITY_MANAGER
KRAIKEN=$KRAIKEN
STAKE=$STAKE
EOCONTRACTS
}
fund_liquidity_manager() {
log "Funding LiquidityManager"
cast send --rpc-url "$ANVIL_RPC" --private-key "$DEPLOYER_PK" \
"$LIQUIDITY_MANAGER" --value 0.1ether >>"$SETUP_LOG" 2>&1
}
grant_recenter_access() {
log "Granting recenter access"
cast rpc --rpc-url "$ANVIL_RPC" anvil_impersonateAccount "$FEE_DEST" >>"$SETUP_LOG" 2>&1
cast send --rpc-url "$ANVIL_RPC" --from "$FEE_DEST" --unlocked \
"$LIQUIDITY_MANAGER" "setRecenterAccess(address)" "$DEPLOYER_ADDR" >>"$SETUP_LOG" 2>&1
cast rpc --rpc-url "$ANVIL_RPC" anvil_stopImpersonatingAccount "$FEE_DEST" >>"$SETUP_LOG" 2>&1
if [[ -n "$TXNBOT_ADDRESS" ]]; then
cast rpc --rpc-url "$ANVIL_RPC" anvil_impersonateAccount "$FEE_DEST" >>"$SETUP_LOG" 2>&1
cast send --rpc-url "$ANVIL_RPC" --from "$FEE_DEST" --unlocked \
"$LIQUIDITY_MANAGER" "setRecenterAccess(address)" "$TXNBOT_ADDRESS" >>"$SETUP_LOG" 2>&1
cast rpc --rpc-url "$ANVIL_RPC" anvil_stopImpersonatingAccount "$FEE_DEST" >>"$SETUP_LOG" 2>&1
fi
}
call_recenter() {
local recenter_pk="$DEPLOYER_PK"
local recenter_addr="$DEPLOYER_ADDR"
if [[ -n "$TXNBOT_ADDRESS" ]]; then
recenter_pk="$TXNBOT_PRIVATE_KEY"
recenter_addr="$TXNBOT_ADDRESS"
fi
log "Calling recenter() via $recenter_addr"
cast send --rpc-url "$ANVIL_RPC" --private-key "$recenter_pk" \
"$LIQUIDITY_MANAGER" "recenter()" >>"$SETUP_LOG" 2>&1
}
seed_application_state() {
log "Wrapping ETH to WETH"
cast send --rpc-url "$ANVIL_RPC" --private-key "$DEPLOYER_PK" \
"$WETH" "deposit()" --value 0.02ether >>"$SETUP_LOG" 2>&1
log "Approving router"
cast send --rpc-url "$ANVIL_RPC" --private-key "$DEPLOYER_PK" \
"$WETH" "approve(address,uint256)" "$SWAP_ROUTER" "$MAX_UINT" >>"$SETUP_LOG" 2>&1
log "Executing initial KRK swap"
cast send --legacy --gas-limit 300000 --rpc-url "$ANVIL_RPC" --private-key "$DEPLOYER_PK" \
"$SWAP_ROUTER" "exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))" \
"($WETH,$KRAIKEN,10000,$DEPLOYER_ADDR,10000000000000000,0,0)" >>"$SETUP_LOG" 2>&1
}
prime_chain() {
log "Pre-mining 5 blocks (minimal warmup for fast Ponder sync)..."
# Mine just 5 blocks - enough for Ponder to have some history but keeps sync fast
if cast rpc --rpc-url "$ANVIL_RPC" anvil_mine "0x5" "0x1" >/dev/null 2>&1; then
log "Mined 5 blocks"
else
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
log "Pre-mining complete"
}
write_deployments_json() {
cat >"$ROOT_DIR/onchain/deployments-local.json" <<EODEPLOYMENTS
{
"contracts": {
"Kraiken": "$KRAIKEN",
"Stake": "$STAKE",
"LiquidityManager": "$LIQUIDITY_MANAGER"
}
}
EODEPLOYMENTS
TXNBOT_PRIVATE_KEY=$DEFAULT_TXNBOT_PK
TXNBOT_ADDRESS=$DEFAULT_TXNBOT_ADDR
bootstrap_log "Using default txnBot wallet: $TXNBOT_ADDRESS"
}
write_ponder_env() {
@ -215,9 +94,10 @@ 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
cat >"$txnbot_env" <<EOTXNBOT
ENVIRONMENT=BASE_SEPOLIA_LOCAL_FORK
PROVIDER_URL=$provider_url
PRIVATE_KEY=$TXNBOT_PRIVATE_KEY
@ -229,26 +109,32 @@ PORT=43069
EOTXNBOT
}
fund_txn_bot_wallet() {
if [[ -z "$TXNBOT_ADDRESS" ]]; then
return
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
log "Funding txnBot wallet $TXNBOT_ADDRESS"
cast send --rpc-url "$ANVIL_RPC" --private-key "$DEPLOYER_PK" \
"$TXNBOT_ADDRESS" --value "$TXNBOT_FUND_VALUE" >>"$SETUP_LOG" 2>&1 || true
local wei hex
wei="$(cast --to-unit "$TXNBOT_FUND_VALUE" wei)"
hex="$(cast --to-hex "$wei")"
cast rpc --rpc-url "$ANVIL_RPC" anvil_setBalance "$TXNBOT_ADDRESS" "$hex" >>"$SETUP_LOG" 2>&1
bootstrap_log "Pre-mining complete"
}
# ── Main ───────────────────────────────────────────────────────────────
main() {
log "Waiting for Anvil"
local start_time
start_time=$(date +%s%3N)
bootstrap_log "Waiting for Anvil"
wait_for_rpc
maybe_set_deployer_from_mnemonic
derive_txnbot_wallet
run_forge_script
extract_addresses
write_contracts_env
fund_liquidity_manager
grant_recenter_access
call_recenter
@ -260,14 +146,17 @@ main() {
prime_chain &
local prime_pid=$!
wait "$prime_pid"
BOOTSTRAP_END=$(date +%s%3N)
elapsed_ms=$((BOOTSTRAP_END - BOOTSTRAP_START))
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 }')
log "Bootstrap complete in ${elapsed_sec}s"
log "Kraiken: $KRAIKEN"
log "Stake: $STAKE"
log "LiquidityManager: $LIQUIDITY_MANAGER"
log "txnBot: $TXNBOT_ADDRESS"
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 "$@"

59
containers/entrypoint-common.sh Executable file
View file

@ -0,0 +1,59 @@
#!/usr/bin/env bash
# Shared helpers for service entrypoints (local dev mode).
# Source this file in each entrypoint script.
# Checkout a git branch if GIT_BRANCH is set.
# Args: $1 = root directory, $2 = log prefix
entrypoint_checkout_branch() {
local root_dir="$1"
local prefix="$2"
local git_branch="${GIT_BRANCH:-}"
if [[ -z "$git_branch" ]]; then
return
fi
cd "$root_dir"
git config --global --add safe.directory "$root_dir" 2>/dev/null || true
local current
current=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
if [[ "$current" != "$git_branch" ]]; then
echo "[$prefix] Switching to branch: $git_branch"
if git rev-parse --verify "$git_branch" >/dev/null 2>&1; then
git checkout "$git_branch" 2>/dev/null || echo "[$prefix] WARNING: Could not checkout $git_branch"
else
git fetch origin "$git_branch" 2>/dev/null || true
git checkout "$git_branch" 2>/dev/null || echo "[$prefix] WARNING: Could not checkout $git_branch"
fi
fi
}
# Validate kraiken-lib dist exists.
# Args: $1 = root directory, $2 = log prefix
entrypoint_require_kraiken_lib() {
local root_dir="$1"
local prefix="$2"
local required_dist="$root_dir/kraiken-lib/dist/index.js"
if [[ ! -f "$required_dist" ]]; then
echo "[$prefix] ERROR: Run ./scripts/build-kraiken-lib.sh before starting containers" >&2
exit 1
fi
}
# Install node_modules if needed (named volume may be empty).
# Args: $1 = log prefix
entrypoint_install_deps() {
local prefix="$1"
if [[ ! -d node_modules/.bin ]]; then
echo "[$prefix] Installing dependencies..."
npm ci --loglevel error && npm cache clean --force 2>&1 || {
echo "[$prefix] npm ci failed, trying npm install"
npm install --no-save --loglevel error && npm cache clean --force
}
else
echo "[$prefix] Using cached node_modules from volume"
fi
}

View file

@ -0,0 +1,5 @@
#!/usr/bin/env bash
# Minimal CI entrypoint for landing — just starts the dev server.
set -euo pipefail
cd /app/landing
exec npm run dev -- --host 0.0.0.0 --port 5174

View file

@ -1,50 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
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 "[landing-entrypoint] 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 "[landing-entrypoint] WARNING: Could not checkout $GIT_BRANCH"
else
git fetch origin "$GIT_BRANCH" 2>/dev/null || true
git checkout "$GIT_BRANCH" 2>/dev/null || echo "[landing-entrypoint] WARNING: Could not checkout $GIT_BRANCH"
fi
fi
fi
LANDING_DIR=$ROOT_DIR/landing
REQUIRED_DIST="$ROOT_DIR/kraiken-lib/dist/index.js"
if [[ ! -f "$REQUIRED_DIST" ]]; then
echo "[landing-entrypoint] ERROR: Run ./scripts/build-kraiken-lib.sh before starting containers" >&2
exit 1
fi
cd "$LANDING_DIR"
# Check if node_modules is populated (named volume may be empty on first run)
if [[ ! -d node_modules/.bin ]]; then
echo "[landing-entrypoint] Installing dependencies..."
npm ci --loglevel error && npm cache clean --force 2>&1 || {
echo "[landing-entrypoint] npm ci failed, trying npm install"
npm install --no-save --loglevel error && npm cache clean --force
}
else
echo "[landing-entrypoint] Using cached node_modules from volume"
fi
export CHOKIDAR_USEPOLLING=${CHOKIDAR_USEPOLLING:-1}
export HOST=0.0.0.0
export PORT=${PORT:-5174}
exec npm run dev -- --host 0.0.0.0 --port 5174

View file

@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR=/workspace
# shellcheck source=entrypoint-common.sh
source "$ROOT_DIR/containers/entrypoint-common.sh"
entrypoint_checkout_branch "$ROOT_DIR" "landing-entrypoint"
entrypoint_require_kraiken_lib "$ROOT_DIR" "landing-entrypoint"
cd "$ROOT_DIR/landing"
entrypoint_install_deps "landing-entrypoint"
export CHOKIDAR_USEPOLLING=${CHOKIDAR_USEPOLLING:-1}
export HOST=0.0.0.0
export PORT=${PORT:-5174}
exec npm run dev -- --host 0.0.0.0 --port 5174

View file

@ -1,27 +1,42 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR=/workspace
GIT_BRANCH="${GIT_BRANCH:-}"
if [[ "${CI:-}" == "true" ]]; then
# ── CI path ────────────────────────────────────────────────────────
cd /app/services/ponder
# 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")
echo "[ponder-ci] Starting Ponder indexer..."
if [[ "$CURRENT" != "$GIT_BRANCH" ]]; then
echo "[ponder-entrypoint] 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 "[ponder-entrypoint] WARNING: Could not checkout $GIT_BRANCH"
else
git fetch origin "$GIT_BRANCH" 2>/dev/null || true
git checkout "$GIT_BRANCH" 2>/dev/null || echo "[ponder-entrypoint] WARNING: Could not checkout $GIT_BRANCH"
fi
fi
: "${DATABASE_URL:?DATABASE_URL is required}"
: "${PONDER_RPC_URL_1:?PONDER_RPC_URL_1 is required}"
export PONDER_RPC_TIMEOUT=${PONDER_RPC_TIMEOUT:-20000}
export HOST=${HOST:-0.0.0.0}
export PORT=${PORT:-42069}
cat > .env.local <<EOF
DATABASE_URL=${DATABASE_URL}
PONDER_RPC_URL_1=${PONDER_RPC_URL_1}
DATABASE_SCHEMA=${DATABASE_SCHEMA:-ponder_ci}
START_BLOCK=${START_BLOCK:-0}
EOF
echo "[ponder-ci] Environment configured:"
echo " DATABASE_URL: ${DATABASE_URL}"
echo " PONDER_RPC_URL_1: ${PONDER_RPC_URL_1}"
echo " START_BLOCK: ${START_BLOCK:-0}"
exec npm run dev
fi
# ── Local dev path ─────────────────────────────────────────────────
ROOT_DIR=/workspace
# shellcheck source=entrypoint-common.sh
source "$ROOT_DIR/containers/entrypoint-common.sh"
entrypoint_checkout_branch "$ROOT_DIR" "ponder-entrypoint"
CONTRACT_ENV=$ROOT_DIR/tmp/containers/contracts.env
PONDER_WORKDIR=$ROOT_DIR/services/ponder
@ -59,22 +74,8 @@ if [[ -n "$START_BLOCK" ]]; then
fi
fi
REQUIRED_DIST="$ROOT_DIR/kraiken-lib/dist/index.js"
if [[ ! -f "$REQUIRED_DIST" ]]; then
echo "[ponder-entrypoint] ERROR: Run ./scripts/build-kraiken-lib.sh before starting containers" >&2
exit 1
fi
# Check if node_modules is populated (named volume may be empty on first run)
if [[ ! -d node_modules/.bin ]]; then
echo "[ponder-entrypoint] Installing dependencies..."
npm ci --loglevel error && npm cache clean --force 2>&1 || {
echo "[ponder-entrypoint] npm ci failed, trying npm install"
npm install --no-save --loglevel error && npm cache clean --force
}
else
echo "[ponder-entrypoint] Using cached node_modules from volume"
fi
entrypoint_require_kraiken_lib "$ROOT_DIR" "ponder-entrypoint"
entrypoint_install_deps "ponder-entrypoint"
# Load and export all environment variables from .env.local
if [[ -f .env.local ]]; then

View file

@ -1,56 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
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 "[txn-bot-entrypoint] 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 "[txn-bot-entrypoint] WARNING: Could not checkout $GIT_BRANCH"
else
git fetch origin "$GIT_BRANCH" 2>/dev/null || true
git checkout "$GIT_BRANCH" 2>/dev/null || echo "[txn-bot-entrypoint] WARNING: Could not checkout $GIT_BRANCH"
fi
fi
fi
TXNBOT_ENV_FILE=$ROOT_DIR/tmp/containers/txnBot.env
BOT_DIR=$ROOT_DIR/services/txnBot
REQUIRED_DIST=$ROOT_DIR/kraiken-lib/dist/index.js
while [[ ! -f "$TXNBOT_ENV_FILE" ]]; do
echo "[txn-bot-entrypoint] waiting for env file"
sleep 2
done
if [[ ! -f "$REQUIRED_DIST" ]]; then
echo "[txn-bot-entrypoint] ERROR: Run ./scripts/build-kraiken-lib.sh before starting containers" >&2
exit 1
fi
cd "$BOT_DIR"
# Check if node_modules is populated (named volume may be empty on first run)
if [[ ! -d node_modules/.bin ]]; then
echo "[txn-bot-entrypoint] Installing txn-bot dependencies..."
npm ci --loglevel error && npm cache clean --force 2>&1 || {
echo "[txn-bot-entrypoint] npm ci failed, trying npm install"
npm install --no-save --loglevel error && npm cache clean --force
}
else
echo "[txn-bot-entrypoint] Using cached node_modules from volume"
fi
echo "[txn-bot-entrypoint] Building TypeScript..."
npm run build
export TXN_BOT_ENV_FILE="$TXNBOT_ENV_FILE"
exec npm run start

62
containers/txnbot-entrypoint.sh Executable file
View file

@ -0,0 +1,62 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ "${CI:-}" == "true" ]]; then
# ── CI path ────────────────────────────────────────────────────────
echo "[txnbot-ci] Starting Transaction Bot..."
: "${TXNBOT_PRIVATE_KEY:?TXNBOT_PRIVATE_KEY is required}"
: "${RPC_URL:?RPC_URL is required}"
: "${KRAIKEN_ADDRESS:?KRAIKEN_ADDRESS is required}"
: "${STAKE_ADDRESS:?STAKE_ADDRESS is required}"
: "${LIQUIDITY_MANAGER_ADDRESS:?LIQUIDITY_MANAGER_ADDRESS is required}"
cat > /tmp/txnBot.env <<EOF
TXNBOT_PRIVATE_KEY=${TXNBOT_PRIVATE_KEY}
RPC_URL=${RPC_URL}
KRAIKEN_ADDRESS=${KRAIKEN_ADDRESS}
STAKE_ADDRESS=${STAKE_ADDRESS}
LIQUIDITY_MANAGER_ADDRESS=${LIQUIDITY_MANAGER_ADDRESS}
POOL_ADDRESS=${POOL_ADDRESS:-}
WETH_ADDRESS=${WETH_ADDRESS:-0x4200000000000000000000000000000000000006}
EOF
export TXN_BOT_ENV_FILE=/tmp/txnBot.env
echo "[txnbot-ci] Environment configured:"
echo " RPC_URL: ${RPC_URL}"
echo " KRAIKEN_ADDRESS: ${KRAIKEN_ADDRESS}"
echo "[txnbot-ci] Building TypeScript..."
npm run build
exec npm run start
fi
# ── Local dev path ─────────────────────────────────────────────────
ROOT_DIR=/workspace
# shellcheck source=entrypoint-common.sh
source "$ROOT_DIR/containers/entrypoint-common.sh"
entrypoint_checkout_branch "$ROOT_DIR" "txnbot-entrypoint"
TXNBOT_ENV_FILE=$ROOT_DIR/tmp/containers/txnBot.env
BOT_DIR=$ROOT_DIR/services/txnBot
while [[ ! -f "$TXNBOT_ENV_FILE" ]]; do
echo "[txnbot-entrypoint] waiting for env file"
sleep 2
done
entrypoint_require_kraiken_lib "$ROOT_DIR" "txnbot-entrypoint"
cd "$BOT_DIR"
entrypoint_install_deps "txnbot-entrypoint"
echo "[txnbot-entrypoint] Building TypeScript..."
npm run build
export TXN_BOT_ENV_FILE="$TXNBOT_ENV_FILE"
exec npm run start

View file

@ -1,68 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
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 "[webapp-entrypoint] 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 "[webapp-entrypoint] WARNING: Could not checkout $GIT_BRANCH"
else
git fetch origin "$GIT_BRANCH" 2>/dev/null || true
git checkout "$GIT_BRANCH" 2>/dev/null || echo "[webapp-entrypoint] WARNING: Could not checkout $GIT_BRANCH"
fi
fi
fi
CONTRACT_ENV=$ROOT_DIR/tmp/containers/contracts.env
APP_DIR=$ROOT_DIR/web-app
SWAP_ROUTER=0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4
while [[ ! -f "$CONTRACT_ENV" ]]; do
echo "[frontend-entrypoint] waiting for contracts env"
sleep 2
done
REQUIRED_DIST="$ROOT_DIR/kraiken-lib/dist/index.js"
if [[ ! -f "$REQUIRED_DIST" ]]; then
echo "[frontend-entrypoint] ERROR: Run ./scripts/build-kraiken-lib.sh before starting containers" >&2
exit 1
fi
# shellcheck disable=SC1090
source "$CONTRACT_ENV"
cd "$APP_DIR"
# Check if node_modules is populated (named volume may be empty on first run)
if [[ ! -d node_modules/.bin ]]; then
echo "[frontend-entrypoint] Installing dependencies..."
npm ci --loglevel error && npm cache clean --force 2>&1 || {
echo "[frontend-entrypoint] npm ci failed, trying npm install"
npm install --no-save --loglevel error && npm cache clean --force
}
else
echo "[frontend-entrypoint] Using cached node_modules from volume"
fi
export VITE_DEFAULT_CHAIN_ID=${VITE_DEFAULT_CHAIN_ID:-31337}
export VITE_LOCAL_RPC_URL=${VITE_LOCAL_RPC_URL:-/api/rpc}
export VITE_LOCAL_RPC_PROXY_TARGET=${VITE_LOCAL_RPC_PROXY_TARGET:-http://anvil:8545}
export VITE_LOCAL_GRAPHQL_PROXY_TARGET=${VITE_LOCAL_GRAPHQL_PROXY_TARGET:-http://ponder:42069}
export VITE_LOCAL_TXN_PROXY_TARGET=${VITE_LOCAL_TXN_PROXY_TARGET:-http://txn-bot:43069}
export VITE_KRAIKEN_ADDRESS=$KRAIKEN
export VITE_STAKE_ADDRESS=$STAKE
export VITE_SWAP_ROUTER=$SWAP_ROUTER
export VITE_PONDER_BASE_SEPOLIA_LOCAL_FORK=${VITE_PONDER_BASE_SEPOLIA_LOCAL_FORK:-/api/graphql}
export VITE_TXNBOT_BASE_SEPOLIA_LOCAL_FORK=${VITE_TXNBOT_BASE_SEPOLIA_LOCAL_FORK:-/api/txn}
export CHOKIDAR_USEPOLLING=${CHOKIDAR_USEPOLLING:-1}
exec npm run dev -- --host 0.0.0.0 --port 5173 --base /app/

70
containers/webapp-entrypoint.sh Executable file
View file

@ -0,0 +1,70 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ "${CI:-}" == "true" ]]; then
# ── CI path ────────────────────────────────────────────────────────
cd /app/web-app
echo "[webapp-ci] Starting Web App..."
: "${VITE_KRAIKEN_ADDRESS:?VITE_KRAIKEN_ADDRESS is required}"
: "${VITE_STAKE_ADDRESS:?VITE_STAKE_ADDRESS is required}"
# Disable Vue DevTools in CI to avoid path resolution issues
export CI=true
export VITE_DEFAULT_CHAIN_ID=${VITE_DEFAULT_CHAIN_ID:-31337}
export VITE_LOCAL_RPC_URL=${VITE_LOCAL_RPC_URL:-/api/rpc}
export VITE_LOCAL_RPC_PROXY_TARGET=${VITE_LOCAL_RPC_PROXY_TARGET:-http://anvil:8545}
export VITE_LOCAL_GRAPHQL_PROXY_TARGET=${VITE_LOCAL_GRAPHQL_PROXY_TARGET:-http://ponder:42069}
export VITE_LOCAL_TXN_PROXY_TARGET=${VITE_LOCAL_TXN_PROXY_TARGET:-http://txn-bot:43069}
export VITE_SWAP_ROUTER=${VITE_SWAP_ROUTER:-0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4}
export VITE_PONDER_BASE_SEPOLIA_LOCAL_FORK=${VITE_PONDER_BASE_SEPOLIA_LOCAL_FORK:-/api/graphql}
export VITE_TXNBOT_BASE_SEPOLIA_LOCAL_FORK=${VITE_TXNBOT_BASE_SEPOLIA_LOCAL_FORK:-/api/txn}
echo "[webapp-ci] Environment configured:"
echo " VITE_KRAIKEN_ADDRESS: ${VITE_KRAIKEN_ADDRESS}"
echo " VITE_STAKE_ADDRESS: ${VITE_STAKE_ADDRESS}"
echo " VITE_DEFAULT_CHAIN_ID: ${VITE_DEFAULT_CHAIN_ID}"
exec npm run dev -- --host 0.0.0.0 --port 5173 --base /app/
fi
# ── Local dev path ─────────────────────────────────────────────────
ROOT_DIR=/workspace
SWAP_ROUTER=0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4
# shellcheck source=entrypoint-common.sh
source "$ROOT_DIR/containers/entrypoint-common.sh"
entrypoint_checkout_branch "$ROOT_DIR" "webapp-entrypoint"
CONTRACT_ENV=$ROOT_DIR/tmp/containers/contracts.env
APP_DIR=$ROOT_DIR/web-app
while [[ ! -f "$CONTRACT_ENV" ]]; do
echo "[webapp-entrypoint] waiting for contracts env"
sleep 2
done
entrypoint_require_kraiken_lib "$ROOT_DIR" "webapp-entrypoint"
# shellcheck disable=SC1090
source "$CONTRACT_ENV"
cd "$APP_DIR"
entrypoint_install_deps "webapp-entrypoint"
export VITE_DEFAULT_CHAIN_ID=${VITE_DEFAULT_CHAIN_ID:-31337}
export VITE_LOCAL_RPC_URL=${VITE_LOCAL_RPC_URL:-/api/rpc}
export VITE_LOCAL_RPC_PROXY_TARGET=${VITE_LOCAL_RPC_PROXY_TARGET:-http://anvil:8545}
export VITE_LOCAL_GRAPHQL_PROXY_TARGET=${VITE_LOCAL_GRAPHQL_PROXY_TARGET:-http://ponder:42069}
export VITE_LOCAL_TXN_PROXY_TARGET=${VITE_LOCAL_TXN_PROXY_TARGET:-http://txn-bot:43069}
export VITE_KRAIKEN_ADDRESS=$KRAIKEN
export VITE_STAKE_ADDRESS=$STAKE
export VITE_SWAP_ROUTER=$SWAP_ROUTER
export VITE_PONDER_BASE_SEPOLIA_LOCAL_FORK=${VITE_PONDER_BASE_SEPOLIA_LOCAL_FORK:-/api/graphql}
export VITE_TXNBOT_BASE_SEPOLIA_LOCAL_FORK=${VITE_TXNBOT_BASE_SEPOLIA_LOCAL_FORK:-/api/txn}
export CHOKIDAR_USEPOLLING=${CHOKIDAR_USEPOLLING:-1}
exec npm run dev -- --host 0.0.0.0 --port 5173 --base /app/