# ENVIRONMENT.md — Local Dev Stack How to start, stop, and verify the harb development environment. ## Stack Overview Docker Compose services (in startup order): | Service | Purpose | Port | Health Check | |---------|---------|------|-------------| | **anvil** | Local Ethereum fork (Base Sepolia by default; override with `FORK_URL`) | 8545 | JSON-RPC response | | **postgres** | Ponder database | 5432 | pg_isready | | **bootstrap** | Deploys contracts to anvil | — | One-shot, exits 0 | | **ponder** | On-chain indexer + GraphQL API | 42069 | HTTP /ready or GraphQL | | **landing** | Landing page (Vue 3 + Vite) | 5174 | HTTP response | | **webapp** | Staking app (Vue 3) | 5173 | HTTP response | | **txn-bot** | Automated recenter/tx bot | — | Process alive | | **caddy** | Reverse proxy / TLS | 80/443 | — | | **otterscan** | Block explorer | 5100 | — | ## Network Contexts Two network contexts are relevant: the dev-stack Anvil (docker-compose) and the backtesting tools that require Base mainnet. ### Dev stack Anvil (docker-compose) The `anvil` service in `docker-compose.yml` runs `containers/anvil-entrypoint.sh`, which forks: ``` ${FORK_URL:-https://sepolia.base.org} ``` **Default: Base Sepolia.** The `bootstrap` service deploys all KRAIKEN protocol contracts (Kraiken, Stake, Optimizer, LiquidityManager) and creates a new KRK/WETH pool using the existing Uniswap V3 Factory already present on the forked network. Addresses are written to `tmp/containers/contracts.env`. To fork Base mainnet instead (required for red-team / backtesting — see below): ```bash FORK_URL=https://mainnet.base.org docker compose up -d ``` ### Backtesting / red-team (`scripts/harb-evaluator/red-team.sh`) `red-team.sh` boots the docker-compose stack and then calls protocol operations using **Base mainnet** addresses for the Uniswap V3 periphery (V3_FACTORY, SwapRouter02, NonfungiblePositionManager). These addresses are only valid on a mainnet fork. `red-team.sh` calls `sudo docker compose up -d` internally, and `sudo` strips environment variables by default. Pass `FORK_URL` inline with `-E` to preserve it: ```bash FORK_URL=https://mainnet.base.org sudo -E bash scripts/harb-evaluator/red-team.sh ``` ### FitnessEvaluator (`onchain/test/FitnessEvaluator.t.sol`) `FitnessEvaluator.t.sol` does **not** use Anvil. It uses Foundry's native revm backend (`vm.createSelectFork`) to fork Base mainnet in-process — no docker-compose dependency: ```bash BASE_RPC_URL=https://mainnet.base.org \ FITNESS_MANIFEST_DIR=/tmp/manifest \ forge test --match-contract FitnessEvaluator --match-test testBatchEvaluate -vv ``` ## Quick Start ```bash cd /home/debian/harb # Start everything docker compose up -d # Wait for bootstrap (deploys contracts, ~60-90s) docker compose logs -f bootstrap # Check all healthy docker compose ps ``` ## Verify Stack Health ```bash # Anvil (local chain) curl -s http://localhost:8545 -X POST -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' | jq .result # Ponder (indexer + GraphQL) curl -s http://localhost:42069/graphql -X POST \ -H 'Content-Type: application/json' \ -d '{"query":"{ stats { id } }"}' | jq . # Landing page curl -sf http://localhost:5174 | head -5 # Staking app curl -sf http://localhost:5173 | head -5 ``` ## Container Network Services communicate on `harb-network` Docker bridge. Internal hostnames match service names (e.g., `ponder:42069`). Landing page container IP (for Playwright testing): check with ```bash docker inspect landing --format '{{.NetworkSettings.Networks.harb_harb-network.IPAddress}}' ``` ## Common URLs (for testing/review) - **Landing:** `http://172.18.0.6:5174` (container IP) or `http://localhost:5174` - **Staking app:** `http://localhost:5173/app/` - **Ponder GraphQL:** `http://localhost:42069/graphql` - **Anvil RPC:** `http://localhost:8545` ## Resource Notes - 8GB VPS — running full stack uses ~4-5GB RAM - npm install inside containers can OOM with all services running - Landing container takes ~2min to restart (npm install + vite startup) - 4GB swap is essential for CI + stack concurrency ## Staking App Passwords For testing login: `lobsterDao`, `test123`, `lobster-x010syqe?412!` (defined in `web-app/src/views/LoginView.vue`) ## Webapp Environment Variables | Variable | Default | Set in docker-compose | Purpose | |---|---|---|---| | `VITE_ENABLE_LOCAL_SWAP` | `false` (unset) | `true` | Show inline ETH→$KRK swap widget on Get KRK page instead of the Uniswap link. Enable for local dev; leave unset for production builds. | | `VITE_KRAIKEN_ADDRESS` | from `deployments-local.json` | via `contracts.env` + entrypoint | Override KRK token address. | | `VITE_STAKE_ADDRESS` | from `deployments-local.json` | via `contracts.env` + entrypoint | Override Stake contract address. | | `VITE_DEFAULT_CHAIN_ID` | auto-detected (31337 on localhost) | — | Force the default chain. | ## Contract Addresses After bootstrap, addresses are written to `/home/debian/harb/tmp/containers/contracts.env` with the following variable names (no `VITE_` prefix): ``` LIQUIDITY_MANAGER=0x... KRAIKEN=0x... STAKE=0x... ``` The entrypoint scripts read this file and re-export the addresses with `VITE_` prefixes for Vite builds: - `containers/landing-entrypoint.sh` exports `VITE_KRAIKEN_ADDRESS` and `VITE_STAKE_ADDRESS` - `containers/webapp-entrypoint.sh` exports `VITE_KRAIKEN_ADDRESS` and `VITE_STAKE_ADDRESS` ## E2E Test Environment Variables The Playwright test setup (`tests/setup/stack.ts`) reads stack coordinates from env vars, falling back to `onchain/deployments-local.json` when they are absent. | Variable | Purpose | |---|---| | `STACK_RPC_URL` | RPC endpoint (default: `http://localhost:8081/api/rpc`) | | `STACK_WEBAPP_URL` | Web app base URL (default: `http://localhost:8081`) | | `STACK_GRAPHQL_URL` | GraphQL endpoint (default: `http://localhost:8081/api/graphql`) | | `STACK_KRAIKEN_ADDRESS` | Kraiken contract address (overrides deployments-local.json) | | `STACK_STAKE_ADDRESS` | Stake contract address (overrides deployments-local.json) | | `STACK_LM_ADDRESS` | LiquidityManager contract address (overrides deployments-local.json) | | `STACK_OPTIMIZER_PROXY_ADDRESS` | OptimizerProxy address (optional; enables optimizer integration tests) | When all three of `STACK_KRAIKEN_ADDRESS`, `STACK_STAKE_ADDRESS`, and `STACK_LM_ADDRESS` are set, the deployments file is not read at all, which allows tests to run in containerised environments that have no local checkout. ## Playwright Testing ```bash # Chromium path /home/debian/.cache/ms-playwright/chromium-1209/chrome-linux64/chrome # Run against landing (block fonts for speed) NODE_PATH=$(npm root -g) node test-script.cjs ``` See `tmp/user-test-r4.cjs` for the most recent test script pattern.