Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 23 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,37 @@
# Local Dev

Run the full Moonlight stack locally: Stellar network, smart contracts, privacy provider, and browser wallet extensions.
Run the full Moonlight stack locally: Stellar network, smart contracts, privacy provider, consoles, and dashboards.

## Prerequisites

| Tool | Install |
|------|---------|
| Docker | [docker.com](https://docs.docker.com/get-docker/) |
| Rust/Cargo | `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \| sh` |
| Stellar CLI | `cargo install --locked stellar-cli --features opt` |
| Deno | `curl -fsSL https://deno.land/install.sh \| sh` |

Rust/Cargo, Stellar CLI, and Deno are auto-installed by `up.sh` if missing.

## Repos

Clone all repos to `~/repos/`:

```
~/repos/
├── local-dev/ # This repo (setup scripts, E2E infrastructure)
├── browser-wallet/ # Chrome extension
├── soroban-core/ # Smart contracts (channel-auth, privacy-channel)
├── moonlight-sdk/ # Privacy SDK (JSR: @moonlight/moonlight-sdk)
├── colibri/ # Soroban contract toolkit (JSR: @colibri/core)
└── provider-platform/ # Privacy provider server
├── provider-platform/ # Privacy provider server
├── provider-console/ # Provider dashboard
├── council-console/ # Council dashboard
└── network-dashboard/ # Network monitoring dashboard
```

Override repo paths with environment variables:

```bash
SOROBAN_CORE_PATH=~/repos/soroban-core \
PROVIDER_PLATFORM_PATH=~/repos/provider-platform \
WALLET_PATH=~/repos/browser-wallet \
PROVIDER_CONSOLE_PATH=~/repos/provider-console \
COUNCIL_CONSOLE_PATH=~/repos/council-console \
NETWORK_DASHBOARD_PATH=~/repos/network-dashboard \
./up.sh
```

Expand All @@ -40,32 +43,25 @@ WALLET_PATH=~/repos/browser-wallet \
./up.sh
```

This runs through 8 stages:
1. Checks prerequisites (Docker, Stellar CLI, Deno, Cargo)
2. Starts Jaeger for distributed tracing (UI at http://localhost:16686)
3. Starts a local Stellar network via Docker
4. Generates accounts (admin, provider, treasury) and funds them via Friendbot
5. Builds and deploys contracts (channel-auth, privacy-channel)
6. Registers the provider on the channel-auth contract
7. Starts the provider platform (PostgreSQL, migrations, server)
8. Builds wallet extensions for Chrome and Brave with dev seeds
This runs through 9 stages:
1. Checks prerequisites (Docker) — auto-installs Rust, Stellar CLI, Deno if missing
2. Starts a local Stellar network if not already running
3. Generates accounts (admin, provider, treasury) and funds them via Friendbot
4. Builds and deploys contracts (SAC, channel-auth, privacy-channel)
5. Starts PostgreSQL (Docker container on port 5442)
6. Starts provider-platform (generates `.env`, runs migrations, port 3010)
7. Builds and starts provider-console (port 3020)
8. Builds and starts council-console (port 3030)
9. Builds and starts network-dashboard (port 3040)

After it finishes, load `browser-wallet/dist/chrome/` or `dist/brave/` as unpacked extensions.
All configuration (`.env` files, `config.js` files) is generated automatically.

### Stop everything

```bash
./down.sh
```

### Rebuild wallet extensions

```bash
./rebuild.sh
```

Rebuilds the Chrome and Brave wallet extensions without restarting the network or provider.

### Run E2E tests

```bash
Expand All @@ -82,28 +78,6 @@ deno task verify-otel
open http://localhost:16686
```

### Run testnet E2E

Runs the same E2E flow against the live testnet provider and verifies traces in Grafana Cloud.

```bash
cd testnet

# Run E2E against testnet
OTEL_DENO=true OTEL_SERVICE_NAME=moonlight-e2e \
OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp-gateway-prod-ca-east-0.grafana.net/otlp \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic <base64 of stackId:token>" \
deno run --allow-all main.ts

# Verify traces arrived in Grafana Cloud Tempo
TEMPO_URL=https://tempo-prod-13-prod-ca-east-0.grafana.net/tempo \
TEMPO_AUTH="Basic <base64 of tempoInstanceId:token>" \
deno run --allow-all verify-otel.ts
```

The verify script uses trace-by-ID lookups (deterministic) for all SDK and provider request-path checks, and a targeted TraceQL search for background service spans only.

## E2E in CI

See [e2e/README.md](e2e/README.md) for the Docker compose setup that runs E2E tests in CI without any host dependencies.
Expand Down
33 changes: 24 additions & 9 deletions up.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ error() { echo -e "${RED}[ERROR]${NC} $*"; exit 1; }
section() { echo -e "\n${BLUE}=== $* ===${NC}"; }

# ============================================================
section "1/7 Prerequisites"
section "1/9 Prerequisites"
# ============================================================

command -v docker >/dev/null 2>&1 || error "Docker not found."
Expand Down Expand Up @@ -82,20 +82,35 @@ info "Deno: $($DENO_BIN --version | head -1)"
[ -d "$NETWORK_DASHBOARD_PATH" ] || error "network-dashboard not found at $NETWORK_DASHBOARD_PATH"

# ============================================================
section "2/7 Stellar Network (shared)"
section "2/9 Stellar Network (shared)"
# ============================================================

# Verify the shared Stellar network is running
# Start the shared Stellar network if not already running
if curl -sf "http://localhost:${STELLAR_RPC_PORT}/soroban/rpc" -X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"getHealth"}' 2>/dev/null | grep -q "healthy"; then
info "Stellar RPC on port $STELLAR_RPC_PORT is healthy (shared with local-dev)."
info "Stellar RPC on port $STELLAR_RPC_PORT is healthy (shared)."
else
error "Stellar RPC not running on port $STELLAR_RPC_PORT. Start local-dev first or run: stellar container start local"
info "Stellar RPC not running, starting local network..."
stellar container start local 2>/dev/null || true

info "Waiting for Stellar RPC to be ready..."
for i in $(seq 1 60); do
if curl -sf "http://localhost:${STELLAR_RPC_PORT}/soroban/rpc" -X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"getHealth"}' 2>/dev/null | grep -q "healthy"; then
info "Stellar RPC is ready."
break
fi
if [ "$i" -eq 60 ]; then
error "Stellar RPC did not become healthy after 60s. Check Docker logs."
fi
sleep 1
done
fi

# ============================================================
section "3/7 Accounts"
section "3/9 Accounts"
# ============================================================

generate_or_reuse() {
Expand Down Expand Up @@ -132,7 +147,7 @@ info "Provider: $PROVIDER_PK"
info "Treasury: $TREASURY_PK"

# ============================================================
section "4/7 Build & Deploy Contracts"
section "4/9 Build & Deploy Contracts"
# ============================================================

cd "$SOROBAN_CORE_PATH"
Expand Down Expand Up @@ -185,7 +200,7 @@ stellar contract invoke \
info "Provider registered."

# ============================================================
section "5/7 PostgreSQL (port $PG_PORT)"
section "5/9 PostgreSQL (port $PG_PORT)"
# ============================================================

if docker ps --format '{{.Names}}' | grep -q "^${PG_CONTAINER}$"; then
Expand Down Expand Up @@ -214,7 +229,7 @@ for i in $(seq 1 30); do
done

# ============================================================
section "6/7 Provider Platform (port $PROVIDER_PORT)"
section "6/9 Provider Platform (port $PROVIDER_PORT)"
# ============================================================

cd "$PROVIDER_PLATFORM_PATH"
Expand Down
Loading