17 KiB
17 KiB
Agent Brief: Harb Stack
Core Concepts
- KRAIKEN couples Harberger-tax staking with a dominant Uniswap V3 liquidity manager to create asymmetric slippage, sentiment-driven pricing, and VWAP "price memory" safeguards.
- Liquidity dominance is mission-critical; treat any regression that weakens the LiquidityManager's control as a priority incident.
- Harberger staking supplies the sentiment oracle that drives Optimizer parameters, which in turn tune liquidity placement and supply expansion.
User Journey
- Buy - Acquire KRAIKEN on Uniswap.
- Stake - Declare a tax rate on kraiken.org to earn from protocol growth.
- Compete - Snatch undervalued positions to optimise returns.
Operating the Stack
Quick Start
nohup ./scripts/dev.sh start & # start (takes ~3-6 min first time)
tail -f nohup.out # watch progress
./scripts/dev.sh health # verify all services healthy
./scripts/dev.sh stop # stop and clean up
Do not launch services individually — dev.sh enforces phased startup with health gates.
Restart Modes
./scripts/dev.sh restart --light— Fast (~10-20s): only webapp + txnbot, preserves Anvil/Ponder state. Use for frontend changes../scripts/dev.sh restart --full— Full (~3-6min): redeploys contracts, fresh state. Use for contract changes.
Common Pitfalls
- Docker disk full:
dev.sh startrefuses to run if Docker disk usage exceeds 20GB. Fix:./scripts/dev.sh stop(auto-prunes) ordocker system prune -af --volumes. - Stale Ponder state: If Ponder fails with schema errors after contract changes, delete its state:
rm -rf services/ponder/.ponder/then./scripts/dev.sh restart --full. - kraiken-lib out of date: If services fail with import errors or missing exports, rebuild:
./scripts/build-kraiken-lib.sh. The dev script does this automatically onstart, but manual rebuilds are needed if you change kraiken-lib while the stack is already running. - Container not found errors:
dev.shexpects Docker Compose v2 container names (harb-anvil-1, hyphens not underscores). Verify withdocker compose version. - Port conflicts: The stack uses ports 8545 (Anvil), 5173 (webapp), 5174 (landing), 42069 (Ponder), 43069 (txnBot), 5100 (Otterscan), 8081 (Caddy). Check with
lsof -i :<port>if startup fails. - npm ci failures in containers: Named Docker volumes cache
node_modules/. If dependencies change and installs fail, remove the volume:docker volume rm harb_webapp_node_modules(or similar), then restart.
Environments
Supported: BASE_SEPOLIA_LOCAL_FORK (default Anvil fork), BASE_SEPOLIA, and BASE. Match contract addresses and RPCs accordingly.
Prerequisites
Docker Engine (Linux) or Colima (Mac). See docs/docker.md for installation.
Component Guides
onchain/- Solidity + Foundry contracts, deploy scripts, and fuzzing helpers (details).services/ponder/- Ponder indexer powering the GraphQL API (details).landing/- Vue 3 marketing + staking interface (details).kraiken-lib/- Shared TypeScript helpers for clients and bots (details).services/txnBot/- Automation bot forrecenter()andpayTax()upkeep (details).
Testing & Tooling
- Contracts: run
forge build,forge test, andforge snapshotinsideonchain/. - Fuzzing: scripts under
onchain/analysis/(e.g.,./analysis/run-fuzzing.sh [optimizer] debugCSV) generate replayable scenarios. - Integration: after the stack boots, inspect Anvil logs, hit
http://localhost:8081/api/graphqlfor Ponder, and pollhttp://localhost:8081/api/txn/statusfor txnBot health. - E2E Tests: Playwright-based full-stack tests in
tests/e2e/verify complete user journeys (mint ETH → swap KRK → stake). Run withnpm run test:e2efrom repo root. Tests use mocked wallet provider with Anvil accounts. In CI, the Woodpecker e2e pipeline runs these against pre-built service images.
Version Validation System
- Contract VERSION:
Kraiken.solexposes aVERSIONconstant (currently v1) that must be incremented for breaking changes to TAX_RATES, events, or core data structures. - Ponder Validation: On startup, Ponder reads the contract VERSION and validates against
COMPATIBLE_CONTRACT_VERSIONSinkraiken-lib/src/version.ts. Fails hard (exit 1) on mismatch to prevent indexing wrong data. - Frontend Check: Web-app validates
KRAIKEN_LIB_VERSIONat runtime (currently placeholder; future: query Ponder GraphQL for full 3-way validation). - CI Enforcement: Woodpecker
release.ymlpipeline validates that contract VERSION matchesCOMPATIBLE_CONTRACT_VERSIONSbefore release. - See
VERSION_VALIDATION.mdfor complete architecture, workflows, and troubleshooting.
Docker Installation & Setup
- Linux: Install Docker Engine via package manager or
curl -fsSL https://get.docker.com | sh, then add user to docker group:sudo usermod -aG docker $USER(logout/login required) - Mac: Use Colima (open-source Docker Desktop alternative):
brew install colima docker docker-compose colima start --cpu 4 --memory 8 --disk 100 docker ps # verify installation - Container Orchestration:
docker-compose.ymlhas NOdepends_ondeclarations. All service ordering is handled inscripts/dev.shvia phased startup with explicit health checks. - Startup Phases: (1) Start anvil+postgres and wait for healthy, (2) Start bootstrap and wait for exit, (3) Start ponder and wait for healthy, (4) Start webapp/landing/txn-bot, (5) Start caddy, (6) Smoke test via
scripts/wait-for-service.sh. - Shared Bootstrap: Contract deployment, seeding, and funding logic lives in
scripts/bootstrap-common.sh, sourced by bothcontainers/bootstrap.sh(local dev) andscripts/ci-bootstrap.sh(CI). Constants (FEE_DEST, WETH, SWAP_ROUTER, default keys) are defined once there. - Logging Configuration: All services have log rotation configured (max 10MB per file, 3 files max = 30MB per container) to prevent disk bloat. Logs are automatically rotated by Docker.
- Disk Management (Portable, No Per-Machine Setup Required):
- 20GB Hard Limit: The stack enforces a 20GB total Docker disk usage limit (images + containers + volumes + build cache).
- Pre-flight Checks:
./scripts/dev.sh startchecks Docker disk usage before starting and refuses to start if over 20GB. - Aggressive Auto-Cleanup on Stop:
./scripts/dev.sh stopautomatically prunes ALL unused Docker resources including build cache (the primary cause of bloat). - Named Volumes for node_modules: All Node.js services (ponder, webapp, landing, txnBot) use named Docker volumes for
node_modules/instead of writing to the host filesystem. This prevents host pollution (20-30GB savings) and ensuresdocker system prune --volumescleans them up. - npm Best Practices: All entrypoints use
npm ci(notnpm install) for reproducible builds andnpm cache clean --forceto remove ~50-100MB of cache per service. - PostgreSQL WAL Limits: Postgres configured with
wal_level=minimal,max_wal_size=128MB, andarchive_mode=offto prevent unbounded WAL file growth in the postgres volume. - Log Rotation: All containers limited to 30MB logs (10MB × 3 files) via docker-compose logging configuration.
- .dockerignore: Excludes
node_modules/, caches, and build outputs from Docker build context to speed up builds and reduce image size. - Monitoring: The stack displays current Docker disk usage on startup and warns at 80% (16GB).
- Note: Docker has no built-in portable disk quotas. All limits are enforced via aggressive pruning, bounded configurations, and isolation of dependencies to Docker volumes.
Guardrails & Tips
token0isWethflips amount semantics; confirm ordering before seeding or interpreting liquidity.- VWAP,
ethScarcity, and Optimizer outputs operate on price^2 (X96). Avoid "normalising" to sqrt inadvertently. - Fund the LiquidityManager with Base WETH (
0x4200...0006) before expectingrecenter()to succeed. - Ponder stores data in
.ponder/; drop the directory if schema changes break migrations. - Keep git clean before committing; never leave commented-out code or untested changes.
- ES Modules: The entire stack uses ES modules. kraiken-lib, txnBot, Ponder, and web-app all require
"type": "module"in package.json and useimportsyntax. - kraiken-lib Build: Run
./scripts/build-kraiken-lib.shbeforedocker-compose upso containers mount a freshkraiken-lib/distfrom the host. - Live Reload:
scripts/watch-kraiken-lib.shrebuilds on file changes (requires inotify-tools) and restarts dependent containers automatically.
Code Quality & Git Hooks
- Pre-commit Hooks: Husky runs lint-staged on all staged files before commits. Each component (onchain, kraiken-lib, ponder, txnBot, web-app, landing) has
.lintstagedrc.jsonconfigured for ESLint + Prettier. - Version Validation (Future): Pre-commit hook includes validation logic that will enforce version sync between
onchain/src/Kraiken.sol(contract VERSION constant) andkraiken-lib/src/version.ts(COMPATIBLE_CONTRACT_VERSIONS array). This validation only runs if both files exist and contain version information. - Husky Setup:
.husky/pre-commitorchestrates all pre-commit checks. Modify this file to add new validation steps. - To test hooks manually:
git add <files> && .husky/pre-commit
Handy Commands
foundryup- update Foundry toolchain.anvil --fork-url https://sepolia.base.org- manual fork when diagnosing outside the helper script.cast call <POOL> "slot0()"- inspect pool state.PONDER_NETWORK=BASE_SEPOLIA_LOCAL_FORK npm run dev(insideservices/ponder/) - focused indexer debugging when the full stack is already running.curl -X POST http://localhost:8081/api/graphql -d '{"query":"{ stats(id:\"0x01\"){kraikenTotalSupply}}"}'curl http://localhost:8081/api/txn/status
Woodpecker CI
Infrastructure
- Server: Woodpecker 3.10.0 runs as a systemd service (
woodpecker-server.service), NOT a Docker container. Binary at/usr/local/bin/woodpecker-server. - Host:
https://ci.sovraigns.network(port 8000 locally athttp://127.0.0.1:8000) - Forge: Codeberg (Gitea-compatible) — repo
johba/harb, forge remote ID800173 - Database: PostgreSQL at
127.0.0.1:5432, databasewoodpecker, userwoodpecker - Config:
/etc/woodpecker/server.env(contains secrets — agent secret, Gitea OAuth secret, DB credentials) - CLI: Downloaded to
/tmp/woodpecker-cli(v3.10.0). RequiresWOODPECKER_SERVERandWOODPECKER_TOKENenv vars. - Logs:
journalctl -u woodpecker-server -f(NOTdocker logs)
Pipeline Configs
.woodpecker/build-ci-images.yml— Builds Docker CI images using unifieddocker/Dockerfile.service-ci. Triggers on push tomasterorfeature/ciwhen files indocker/,.woodpecker/,containers/,kraiken-lib/,onchain/,services/,web-app/, orlanding/change..woodpecker/e2e.yml— Runs Playwright E2E tests. Bootstrap step sourcesscripts/bootstrap-common.shfor shared deploy/seed logic. Health checks usescripts/wait-for-service.sh. Triggers on pull_request tomaster.- Pipeline numbering: even = build-ci-images (push events), odd = E2E (pull_request events). This is not guaranteed but was the observed pattern.
Monitoring Pipelines via DB
Since the Woodpecker API requires authentication (tokens are cached in server memory; DB-only token changes don't work without a server restart), monitor pipelines directly via PostgreSQL:
# Latest pipelines
PGPASSWORD='<db_password>' psql -h 127.0.0.1 -U woodpecker -d woodpecker -c \
"SELECT number, status, branch, event, commit FROM pipelines
WHERE repo_id = (SELECT id FROM repos WHERE full_name = 'johba/harb')
ORDER BY number DESC LIMIT 5;"
# Step details for a specific pipeline
PGPASSWORD='<db_password>' psql -h 127.0.0.1 -U woodpecker -d woodpecker -c \
"SELECT s.name, s.state,
CASE WHEN s.finished > 0 AND s.started > 0 THEN (s.finished - s.started)::int::text || 's'
ELSE '-' END as duration, s.exit_code
FROM steps s WHERE s.pipeline_id = (
SELECT id FROM pipelines WHERE number = <N>
AND repo_id = (SELECT id FROM repos WHERE full_name = 'johba/harb'))
ORDER BY s.started NULLS LAST;"
Triggering Pipelines
- Normal flow: Push to Codeberg → Codeberg fires webhook to
https://ci.sovraigns.network/api/hook→ Woodpecker creates pipeline. - Known issue: Codeberg webhooks can stop firing if
ci.sovraigns.networkbecomes unreachable (DNS/connectivity). Check Codeberg repo settings → Webhooks to verify delivery history and re-trigger. - Manual trigger via API (requires valid token — see known issues):
WOODPECKER_SERVER=http://127.0.0.1:8000 WOODPECKER_TOKEN=<token> \ /tmp/woodpecker-cli pipeline create --branch feature/ci johba/harb - API auth limitation: The server caches user token hashes in memory. Inserting a token directly into the DB does not work without restarting the server (
sudo systemctl restart woodpecker-server).
CI Docker Images
docker/Dockerfile.service-ci— Unified parameterized Dockerfile for all service CI images (ponder, webapp, landing, txnBot). Uses--build-argfor service-specific configuration (SERVICE_DIR, SERVICE_PORT, ENTRYPOINT_SCRIPT, NEEDS_SYMLINKS, etc.).- sync-tax-rates: Builder stage runs
scripts/sync-tax-rates.mjsto sync tax rates fromStake.solinto kraiken-lib before TypeScript compilation. - Symlinks fix (webapp only,
NEEDS_SYMLINKS=true): Creates/web-app,/kraiken-lib,/onchainsymlinks to work around Vite'sremoveBase()stripping/app/prefix from filesystem paths. - CI env detection (
CI=true): Disables Vue DevTools plugin invite.config.tsto prevent 500 errors caused by path resolution issues with/app/base path. - HEALTHCHECK: Configurable via build args; webapp uses
--retries=84 --interval=5s= 420s (7 min), aligned withwait-for-stackstep timeout.
- sync-tax-rates: Builder stage runs
- Shared entrypoints: Each service uses a unified entrypoint script (
containers/<service>-entrypoint.sh) that branches onCI=trueenv var for CI vs local dev paths. Common helpers incontainers/entrypoint-common.sh. - Shared bootstrap:
scripts/bootstrap-common.shcontains shared contract deployment, seeding, and funding functions used by bothcontainers/bootstrap.sh(local dev) and.woodpecker/e2e.yml(CI). - CI images are tagged with git SHA and
latest, pushed to a local registry.
CI Agent & Registry Auth
- Agent: Runs as user
ci(uid 1001) onharb-staging, same host as the dev environment. Binary at/usr/local/bin/woodpecker-agent. - Registry credentials: The
ciuser must have Docker auth configured at/home/ci/.docker/config.jsonto pull private images fromregistry.niovi.voyage. If images fail to pull with "no basic auth credentials", fix with:sudo mkdir -p /home/ci/.docker sudo cp /home/debian/.docker/config.json /home/ci/.docker/config.json sudo chown -R ci:ci /home/ci/.docker sudo chmod 600 /home/ci/.docker/config.json - Shared Docker daemon: The
cianddebianusers share the same Docker daemon. Runningdocker system pruneasdebianremoves images cached for CI pipelines. If CI image pulls fail after a prune, either fix registry auth (above) or pre-pull images asdebian:docker pull registry.niovi.voyage/harb/ponder-ci:latestetc.
CI Debugging Tips
- If pipelines aren't being created after a push, check Codeberg webhook delivery logs first.
- The Woodpecker server needs
sudoto restart. Without it, you cannot: refresh API tokens, clear cached state, or recover from webhook auth issues. - E2E pipeline failures often come from
wait-for-stacktiming out. Check the webapp HEALTHCHECK alignment and Ponder indexing time. - The
web-app/vite.config.tsallowedHostsarray must include container hostnames (webapp,caddy) for health checks to succeed inside Docker networks. - Never use
bash -lcin Woodpecker pipeline commands — login shell resets PATH via/etc/profile, losing Foundry and other tools set by Docker ENV. Usebash -cinstead.
Codeberg API Access
- Auth: Codeberg API tokens are stored in
~/.netrc(standardcurl --netrcformat,chmod 600):
Themachine codeberg.org login johba password <api-token>passwordfield holds the API token — this is standard.netrcconvention, not an actual password. - Generate tokens at
https://codeberg.org/user/settings/applications. - Usage: Pass
--netrcto curl for authenticated Codeberg API calls:curl --netrc -s https://codeberg.org/api/v1/repos/johba/harb/issues | jq '.[0].title' - Note: The repo uses SSH for git push/pull (
ssh://git@codeberg.org), so.netrcis only used for REST API interactions (issues, PRs, releases).
References
- Deployment history:
onchain/deployments-local.json,onchain/broadcast/. - Deep dives:
TECHNICAL_APPENDIX.md,HARBERG.md, andonchain/UNISWAP_V3_MATH.md.