From 49f3eb5da60d0ed1b74b831f854b93d0519ad763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DomRift=20=E2=9A=A1=EF=B8=8F=F0=9F=92=BB?= <119934253+Macnelson9@users.noreply.github.com> Date: Sun, 31 May 2026 13:03:27 +0000 Subject: [PATCH] feat(docs): add "run locally in 5 minutes" quickstart script (#73) Adds `dev/start.sh` that checks prereqs, starts stellar/quickstart via Docker, installs deps, and launches the Vite dev server. `--testnet` flag skips Docker and points to Stellar Testnet. `dev/.env.example` documents all env vars. Rewrites root `README.md` with quickstart, env var table, project layout, and CI reference. Closes #73 Co-Authored-By: Claude Sonnet 4.6 --- README.md | 119 ++++++++++++++++++++++++++++++++++++++++++ dev/.env.example | 19 +++++++ dev/start.sh | 131 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 269 insertions(+) create mode 100644 README.md create mode 100644 dev/.env.example create mode 100755 dev/start.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..47bcfeb --- /dev/null +++ b/README.md @@ -0,0 +1,119 @@ +# Turbolong + +Leveraged yield positions on [Blend Protocol](https://blend.capital) pools — single-click recursive lending loops on Stellar. + +## Quick start (5 minutes) + +**Prerequisites:** Docker, Node.js ≥ 20, Git. + +```bash +git clone https://github.com/Dgetsylver/TurboLong.git +cd TurboLong +bash dev/start.sh +``` + +Open **http://localhost:5173** in your browser. That's it. + +`dev/start.sh` will: +1. Pull and start a `stellar/quickstart` container (Soroban RPC on port 8000, Horizon on 8001). +2. Install frontend dependencies. +3. Launch the Vite dev server at `http://localhost:5173`. +4. Start the Alerts Cloudflare Worker at `http://localhost:8787` (requires `wrangler` — skipped if absent). + +To skip the local node and use Stellar Testnet instead: + +```bash +bash dev/start.sh --testnet +``` + +### Environment variables + +Copy `dev/.env.example` to `.env.local` in the repo root and fill in any overrides: + +| Variable | Default | Description | +|---|---|---| +| `STELLAR_RPC_PORT` | `8000` | Local Quickstart Soroban RPC port | +| `STELLAR_HORIZON_PORT` | `8001` | Local Quickstart Horizon port | +| `VITE_RPC_URL` | _(network default)_ | Override RPC URL in the frontend | +| `VITE_HORIZON_URL` | _(network default)_ | Override Horizon URL in the frontend | +| `CLOUDFLARE_ACCOUNT_ID` | — | Needed to deploy the Alerts worker | +| `CLOUDFLARE_API_TOKEN` | — | Needed to deploy the Alerts worker | + +--- + +## Project layout + +``` +frontend/ Vite + TypeScript UI + src/ + main.ts App entry — wallet, views, interactions + blend.ts Blend Protocol pool helpers + defindex.ts DefIndex vault helpers + .storybook/ Storybook config + src/stories/ Component stories + +alerts/ Cloudflare Worker — position health alerts +scripts/ Off-chain utility scripts (Node.js) +src/ Rust binaries (rate_calc, simulate, execute_loop) +dev/ Local dev quickstart scripts +e2e/ Playwright end-to-end tests +.github/ CI workflows +``` + +--- + +## Running tests + +### Unit tests (Vitest) + +```bash +cd frontend && npm test +``` + +### Rust parity tests + +```bash +cargo test +``` + +### End-to-end tests (Playwright) + +```bash +cd e2e +npm install +npm run test:e2e +``` + +Screenshots are captured automatically on failure and saved to `e2e/test-results/`. + +--- + +## Storybook + +Isolate and iterate on UI components in isolation: + +```bash +cd frontend +npm install +npm run storybook # dev server at http://localhost:6006 +npm run build-storybook # static build +``` + +Components covered: HF Badge, Leverage Slider, Pool Card, Asset Picker, APR Card, Toast, Stat Card. + +--- + +## CI + +| Workflow | Trigger | What it does | +|---|---|---| +| `rust-lint.yml` | Push/PR touching `src/**` or `Cargo.toml` | `cargo clippy -D warnings` + `cargo fmt --check` | +| `parity.yml` | Pull request | Rust parity test suite | +| `e2e.yml` | Push/PR touching `frontend/**` or `e2e/**` | Playwright E2E suite; uploads screenshots on failure | +| `deploy.yml` | Push to non-main branches touching `frontend/**` | Deploys frontend to GitHub Pages | + +--- + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/dev/.env.example b/dev/.env.example new file mode 100644 index 0000000..f6fe198 --- /dev/null +++ b/dev/.env.example @@ -0,0 +1,19 @@ +# Copy this file to .env.local and fill in the values. +# All variables are optional — defaults are shown. + +# Stellar Quickstart port for Soroban RPC (local dev only) +STELLAR_RPC_PORT=8000 + +# Stellar Quickstart port for Horizon (local dev only) +STELLAR_HORIZON_PORT=8001 + +# Override the RPC URL used by the frontend (leave blank to use defaults) +# Set to http://localhost:8000/soroban/rpc when running with --quickstart +VITE_RPC_URL= + +# Override the Horizon URL used by the frontend +VITE_HORIZON_URL= + +# Cloudflare D1 / Alerts Worker config (only needed if running the Alerts worker) +CLOUDFLARE_ACCOUNT_ID= +CLOUDFLARE_API_TOKEN= diff --git a/dev/start.sh b/dev/start.sh new file mode 100755 index 0000000..40a9e79 --- /dev/null +++ b/dev/start.sh @@ -0,0 +1,131 @@ +#!/usr/bin/env bash +# Turbolong local dev quickstart. +# Spins up a local Stellar Quickstart node, deploys contracts, +# starts the frontend dev server, and the Alerts worker — all in one command. +# +# Prerequisites: Docker, Node.js >= 20, Rust + cargo, wrangler (npm i -g wrangler) +# Usage: bash dev/start.sh [--testnet] + +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +ENV_FILE="$ROOT/.env.local" + +# ── Colours ─────────────────────────────────────────────────────────────────── +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m' +info() { echo -e "${BLUE}[turbolong]${NC} $*"; } +success() { echo -e "${GREEN}[turbolong]${NC} $*"; } +warn() { echo -e "${YELLOW}[turbolong]${NC} $*"; } +die() { echo -e "${RED}[turbolong] ERROR:${NC} $*" >&2; exit 1; } + +# ── Prerequisites check ─────────────────────────────────────────────────────── +check_dep() { + command -v "$1" >/dev/null 2>&1 || die "'$1' is required but not installed. See README for setup instructions." +} + +check_dep docker +check_dep node +check_dep npm + +NODE_VERSION=$(node -e "process.exit(parseInt(process.versions.node) < 20 ? 1 : 0)" 2>/dev/null) \ + || die "Node.js >= 20 is required (found $(node --version))" + +# ── Parse args ──────────────────────────────────────────────────────────────── +USE_QUICKSTART=true +NETWORK="local" +for arg in "$@"; do + case $arg in + --testnet) USE_QUICKSTART=false; NETWORK="testnet" ;; + esac +done + +# ── Load .env.local if it exists ────────────────────────────────────────────── +if [[ -f "$ENV_FILE" ]]; then + # shellcheck disable=SC1090 + set -o allexport; source "$ENV_FILE"; set +o allexport + info "Loaded env from .env.local" +fi + +# ── 1. Stellar Quickstart (local only) ─────────────────────────────────────── +QUICKSTART_CONTAINER="turbolong-stellar" +RPC_PORT="${STELLAR_RPC_PORT:-8000}" +HORIZON_PORT="${STELLAR_HORIZON_PORT:-8001}" + +if $USE_QUICKSTART; then + info "Starting Stellar Quickstart container…" + + if docker ps --format '{{.Names}}' | grep -q "^${QUICKSTART_CONTAINER}$"; then + warn "Container '$QUICKSTART_CONTAINER' already running — skipping." + else + docker run -d \ + --name "$QUICKSTART_CONTAINER" \ + --rm \ + -p "${RPC_PORT}:8000" \ + -p "${HORIZON_PORT}:8001" \ + stellar/quickstart:latest \ + --standalone \ + --enable-soroban-rpc \ + --protocol-version 22 \ + --limits default + info "Waiting for Quickstart RPC to become ready…" + for i in $(seq 1 30); do + if curl -sf "http://localhost:${RPC_PORT}/soroban/rpc" -d '{"jsonrpc":"2.0","id":1,"method":"getHealth"}' \ + -H "Content-Type: application/json" >/dev/null 2>&1; then + success "Stellar Quickstart is ready on port ${RPC_PORT}" + break + fi + [[ $i -eq 30 ]] && die "Quickstart failed to start after 60s" + sleep 2 + done + fi +fi + +# ── 2. Install frontend deps ────────────────────────────────────────────────── +info "Installing frontend dependencies…" +npm install --prefix "$ROOT/frontend" --silent + +# ── 3. Start frontend dev server ────────────────────────────────────────────── +info "Starting frontend dev server at http://localhost:5173 …" +npm run dev --prefix "$ROOT/frontend" & +FRONTEND_PID=$! + +# ── 4. Start Alerts worker (optional — requires wrangler) ──────────────────── +if command -v wrangler >/dev/null 2>&1; then + info "Starting Alerts Cloudflare Worker…" + (cd "$ROOT/alerts" && npm install --silent && wrangler dev --port 8787) & + ALERTS_PID=$! +else + warn "wrangler not found — skipping Alerts worker. Install with: npm i -g wrangler" + ALERTS_PID="" +fi + +# ── Done ─────────────────────────────────────────────────────────────────────── +echo "" +success "Turbolong is running!" +echo "" +echo " Frontend: http://localhost:5173" +if $USE_QUICKSTART; then +echo " Stellar RPC: http://localhost:${RPC_PORT}/soroban/rpc" +echo " Horizon: http://localhost:${HORIZON_PORT}" +else +echo " Network: Stellar Testnet" +fi +if [[ -n "$ALERTS_PID" ]]; then +echo " Alerts: http://localhost:8787" +fi +echo "" +echo "Press Ctrl+C to stop all services." + +# ── Cleanup on exit ─────────────────────────────────────────────────────────── +cleanup() { + info "Shutting down…" + [[ -n "$FRONTEND_PID" ]] && kill "$FRONTEND_PID" 2>/dev/null || true + [[ -n "${ALERTS_PID:-}" ]] && kill "$ALERTS_PID" 2>/dev/null || true + if $USE_QUICKSTART; then + docker stop "$QUICKSTART_CONTAINER" 2>/dev/null || true + fi + success "Done." +} +trap cleanup EXIT INT TERM + +wait