Goal: A new contributor should be able to set up NotifyChain from scratch on a clean machine without asking maintainers for help.
This guide walks you through setting up a local development environment for NotifyChain. By the end, you will have the listener service, the dashboard, the frontend analytics app, and the smart contracts building and running on your machine. This guide walks you through setting up a local development environment for NotifyChain. By the end, you will have the listener service, the dashboard, and the smart contracts building and running on your machine.
- Required Dependencies
- Clone the Repository
- Listener Service Setup
- Dashboard Setup
- Frontend (Next.js Analytics) Setup
- Smart Contracts Setup
- Environment Variables Reference
- Full-Stack Verification Checklist
- Running Tests
- VS Code Setup (Recommended)
- Troubleshooting & FAQ
- Smart Contracts Setup
- Environment Variables Reference
- Running Tests
- VS Code Setup (Recommended)
- Troubleshooting & FAQ
| Dependency | Minimum Version | Install Method | Used By |
|---|---|---|---|
| Rust | stable | rustup.rs | Smart contracts |
wasm32-unknown-unknown |
— | rustup target add wasm32-unknown-unknown |
Soroban contracts |
| Stellar CLI | latest | cargo install stellar-cli |
Contract build/deploy |
| Node.js | 18 (dashboard), 20 (listener) | nodejs.org or nvm |
Listener, Dashboard |
| npm | comes with Node | — | Package management |
| Git | — | Your package manager or git-scm.com | Version control |
- macOS: Install Xcode Command Line Tools (
xcode-select --install) before Rust. - Linux: Install
build-essential(sudo apt install build-essential) before Rust. - Windows: Use Visual Studio Build Tools with "C++ build tools" workload for native
sqlite3bindings.
The project uses two different Node.js versions across its components:
| Workspace | Node Version | CI Reference |
|---|---|---|
listener/ |
20 | .github/workflows/ci.yml — node-version: 20 |
dashboard/ |
18 | .github/workflows/ci.yml — node-version: 18 |
Recommendation: Use nvm (Node Version Manager) to switch between versions:
# Install nvm (macOS/Linux)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
# Restart your terminal, then install both versions
nvm install 18
nvm install 20
# Use Node 20 for the listener (the more demanding component)
nvm use 20For most local development, Node 20 is sufficient for both components. If you encounter CI-related issues, test against the specific version used in CI.
# ── Rust + WebAssembly + Stellar CLI ──
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
rustup target add wasm32-unknown-unknown
cargo install --locked stellar-cli --features opt
# Verify
rustc --version && cargo --version && stellar --versiongit clone https://github.com/CollinsC1O/Notify-Chain.git
git clone https://github.com/Core-Foundry/Notify-Chain.git
cd Notify-ChainIf you plan to contribute, fork the repository first, then clone your fork:
git clone https://github.com/YOUR-USERNAME/Notify-Chain.git
cd Notify-Chain
git remote add upstream https://github.com/CollinsC1O/Notify-Chain.git
git remote add upstream https://github.com/Core-Foundry/Notify-Chain.gitThe listener is the core off-chain service that polls the Stellar network, processes contract events, and delivers notifications.
cd listener
npm installNote: The
sqlite3package includes native bindings. If the install fails, see the Troubleshooting section.
cp .env.example .envOpen listener/.env in your editor. At minimum, set:
STELLAR_RPC_URL=https://soroban-testnet.stellar.org:443
CONTRACT_ADDRESSES=[{"address":"YOUR_CONTRACT_ID","events":["*"]}]If you plan to use Discord notifications, also set:
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_TOKEN
DISCORD_WEBHOOK_ID=YOUR_WEBHOOK_IDNote: Both
DISCORD_WEBHOOK_URLandDISCORD_WEBHOOK_IDare required together. If either is missing, Discord notifications are disabled.
For a full reference of every variable, see Environment Variables Reference. For a full reference of every variable, see Environment Variables Reference.
npm run migrateThis creates the SQLite database file (default location: listener/data/notifications.db) and runs all schema migrations.
npm run devThe listener starts and immediately begins polling the configured contracts. You should see log output showing poll cycles.
Verify it's running:
curl http://localhost:8787/health # Health check
curl http://localhost:8787/api/events # Event feed (may be empty initially)| Command | Purpose |
|---|---|
npm run dev |
Start in development mode (ts-node, hot reload) |
npm run build |
Compile TypeScript to JavaScript |
npm start |
Run the compiled production build |
npm test |
Run all tests |
npm run typecheck |
TypeScript type checking (no emit) |
npm run migrate |
Initialize or update the SQLite database schema |
npm run lint |
Alias for typecheck |
The dashboard is a React + Vite application that visualizes events from the listener's API.
cd dashboard
npm installcp .env.example .envThe default .env.example is pre-configured for local development:
VITE_EVENTS_API_URL=http://localhost:8787/api/events
VITE_STELLAR_NETWORK=TESTNETChange VITE_EVENTS_API_URL if your listener runs on a different port.
npm run devOpen http://localhost:5173 in your browser. The dashboard fetches events from the listener API and displays them in real-time.
| Command | Purpose |
|---|---|
npm run dev |
Start Vite dev server with hot module replacement |
npm run build |
TypeScript check + Vite production build |
npm test |
Run all tests |
npm run lint |
ESLint with zero-tolerance for warnings |
npm run preview |
Preview the production build locally |
npm run benchmark |
Run performance rendering benchmarks |
Note: The frontend is a legacy Next.js app for analytics visualization. Most contributors only need the Dashboard (section 4). Skip this section unless you are working on analytics features.
The frontend is a Next.js 14 application with Chart.js for analytics dashboards and Tailwind CSS for styling.
cd frontend
npm installThe frontend reads from the listener's API and does not require its own
.env file for basic operation. If you need to override defaults, create:
echo "NEXT_PUBLIC_API_URL=http://localhost:8787" > .env.localnpm run devOpens at http://localhost:3000.
| Command | Purpose |
|---|---|
npm run dev |
Start Next.js dev server |
npm run build |
Production build |
npm start |
Start production server |
npm run lint |
Run Next.js linting |
The project contains two Soroban smart contracts. Building them is optional — you only need to do this if you are modifying contracts or deploying your own instances.
The project contains two Soroban smart contracts. Building them is optional — you only need to do this if you are modifying contracts or deploying your own instances.
AutoShare Contract (contract/):
cd contract
stellar contract buildThe compiled .wasm file is written to contract/target/wasm32-unknown-unknown/release/.
TaskBounty Contract (Documents/Task Bounty/):
cd Documents/Task\ Bounty
stellar contract build# AutoShare
cd contract/contracts/hello-world
cargo test
# TaskBounty
cd Documents/Task\ Bounty
cargo testThis requires a funded Stellar testnet identity:
# Generate and fund a test identity
stellar keys generate my-identity --network testnet
stellar keys fund my-identity --network testnet
# Deploy the AutoShare contract
cd contract
stellar contract deploy \
--wasm target/wasm32-unknown-unknown/release/hello_world.wasm \
--source my-identity \
--network testnet
# The contract ID is printed after successful deploymentMost contracts require initialization after deployment. For the AutoShare contract:
# Find your wallet address
stellar keys address my-identity
# Initialize the contract with your admin address
stellar contract invoke \
--id YOUR_CONTRACT_ID \
--source my-identity \
--network testnet \
-- \
initialize_admin \
--admin YOUR_WALLET_ADDRESSFor the TaskBounty contract (see Documents/Task Bounty/SETUP.md for
detailed configuration):
stellar contract invoke \
--id YOUR_CONTRACT_ID \
--source my-identity \
--network testnet \
-- \
initializeAfter initializing, add the contract ID to your listener/.env
CONTRACT_ADDRESSES so the listener knows to monitor it.
| Command | Purpose |
|---|---|
stellar contract build |
Build all contracts |
cargo test |
Run contract tests |
stellar contract deploy --wasm <FILE> --source <ID> --network testnet |
Deploy to testnet |
stellar contract invoke --id <ID> --source <ID> --network testnet -- <FUNCTION> [ARGS] |
Call a contract function |
stellar contract optimize --wasm <FILE> |
Optimize Wasm for production |
stellar contract inspect --wasm <FILE> |
Inspect contract interface |
cargo fmt --all |
Format Rust code |
| Variable | Required | Default | Description |
|---|---|---|---|
| Stellar Network | |||
STELLAR_NETWORK |
No | testnet |
Network passphrase (testnet, pubnet, or custom) |
STELLAR_RPC_URL |
Yes | https://soroban-testnet.stellar.org:443 |
Soroban RPC endpoint to poll for events |
| Contracts | |||
CONTRACT_ADDRESSES |
Yes | [] |
JSON array of contract configs. Format: [{"address":"C...","events":["*"]}]. Each entry has address (string, the Stellar contract ID) and events (string array of event names to filter on, or ["*"] for all). |
| Polling | |||
POLL_INTERVAL_MS |
No | 30000 |
Time between RPC polls (milliseconds) |
MAX_RECONNECT_ATTEMPTS |
No | 5 |
Max consecutive RPC failures before stopping |
RECONNECT_DELAY_MS |
No | 5000 |
Base delay between reconnection attempts (exponential backoff) |
| API Server | |||
EVENTS_API_PORT |
No | 8787 |
HTTP server port for /health and /api/events |
EVENTS_API_CORS_ORIGIN |
No | http://localhost:5173 |
Allowed CORS origin (dashboard URL) |
WEBHOOK_SECRETS |
No | [] |
JSON array of webhook secrets for HMAC verification. Format: [{"id":"default","secret":"whsec_..."}] |
| Discord Notifications | |||
DISCORD_WEBHOOK_URL |
No | — | Discord webhook URL for sending notifications |
DISCORD_WEBHOOK_ID |
No | — | Discord webhook ID (required together with webhook URL) |
NOTIFICATION_DEDUPLICATION_WINDOW_MS |
No | 60000 |
In-memory dedup window for Discord notifications (ms) |
NOTIFICATION_DEDUPLICATION_MAX_SIZE |
No | 10000 |
Max entries in in-memory dedup cache |
DISCORD_WEBHOOK_ID |
No | — | Discord webhook ID (required if webhook URL is set) |
| Retry Queue | |||
RETRY_BASE_DELAY_MS |
No | 5000 |
Base delay for notification retry exponential backoff |
RETRY_MAX_RETRIES |
No | 5 |
Max retry attempts for failed Discord notifications |
| Event Processing Queue | |||
EVENT_QUEUE_MAX_CONCURRENCY |
No | 1 |
Max events to process concurrently (1 = ordered) |
EVENT_QUEUE_MAX_RETRIES |
No | 3 |
Max retry attempts per event before permanent failure |
EVENT_QUEUE_BASE_DELAY_MS |
No | 2000 |
Base delay for event retry exponential backoff |
EVENT_QUEUE_POLL_INTERVAL_MS |
No | 1000 |
How often the queue checks for due events (ms) |
| Database | |||
DATABASE_PATH |
No | ./data/notifications.db |
SQLite database file path |
| Scheduler | |||
SCHEDULER_ENABLED |
No | true |
Enable the notification scheduler |
SCHEDULER_POLL_INTERVAL_MS |
No | 10000 |
How often the scheduler polls for due notifications |
SCHEDULER_LOCK_TIMEOUT_MS |
No | 60000 |
Distributed lock timeout for scheduler |
SCHEDULER_PROCESSOR_ID |
No | auto-generated | Unique ID for this scheduler instance (multi-instance setups) |
SCHEDULER_BATCH_SIZE |
No | 10 |
Max notifications to process per poll cycle |
SCHEDULER_TIMING_BUFFER_MS |
No | 60000 |
Buffer to prevent premature notification delivery |
| Rate Limiting | |||
RATE_LIMIT_ENABLED |
No | true |
Enable HTTP API rate limiting |
RATE_LIMIT_WINDOW_MS |
No | 60000 |
Rate limit window (milliseconds) |
RATE_LIMIT_MAX_REQUESTS |
No | 60 |
Max requests per window per client |
RATE_LIMIT_CLIENT_OVERRIDES |
No | {} |
JSON object of per-client rate limit overrides |
| Cleanup | |||
CLEANUP_INTERVAL_MS |
No | 3600000 |
How often to run cleanup jobs (1 hour) |
NOTIFICATION_RETENTION_MS |
No | 604800000 |
Retain completed notifications (7 days) |
RATE_LIMIT_EVENT_RETENTION_MS |
No | 86400000 |
Retain rate limit audit events (1 day) |
EVENT_RETENTION_MS |
No | 86400000 |
Retain in-memory events (1 day) |
| Logging | |||
LOG_LEVEL |
No | info |
Winston log level (error, warn, info, debug) |
NODE_ENV |
No | — | Set to production for newline-delimited JSON log output |
| Variable | Required | Default | Description |
|---|---|---|---|
VITE_EVENTS_API_URL |
No | http://localhost:8787/api/events |
Listener API endpoint for fetching events |
VITE_STELLAR_NETWORK |
No | TESTNET |
Stellar network for wallet integration (TESTNET or MAINNET) |
To run the listener with no optional features:
STELLAR_RPC_URL=https://soroban-testnet.stellar.org:443
CONTRACT_ADDRESSES=[{"address":"C...","events":["*"]}]
EVENTS_API_PORT=8787
EVENTS_API_CORS_ORIGIN=http://localhost:5173
DATABASE_PATH=./data/notifications.dbTo add Discord notifications, also set:
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_TOKEN
DISCORD_WEBHOOK_ID=YOUR_WEBHOOK_IDRun these checks to confirm every component is working correctly.
# Check the health endpoint
curl http://localhost:8787/health
# Expected: {"status":"ok","services":{"stellarRpc":{"status":"ok"},"eventRegistry":{"status":"ok","eventCount":0}}}# Check the events API (may be empty if no contracts are active)
curl http://localhost:8787/api/events
# Expected: {"events":[],"total":0} (or populated with events)# Check scheduler status
curl http://localhost:8787/api/schedule/stats
# Expected: {"pending":0,"processing":0,"completed":0,"failed":0,"overdue":0}Open http://localhost:5173 in your browser and confirm:
- The page loads without errors
- The events feed renders (may be empty)
- No CORS errors in the browser console (F12 → Console)
If you set up the frontend, open http://localhost:3000 and confirm:
- The analytics dashboard loads
- Charts render without errors
# Verify the database exists and has the correct schema
sqlite3 listener/data/notifications.db ".tables"
# Expected: notification_execution_log notification_templates polling_cursors
# notification_template_audit_log processed_events rate_limit_events
# scheduled_notificationsIf you need to reset everything:
# Reset listener database
rm -f listener/data/notifications.db
cd listener && npm run migrate
# Clear listener event registry (restart the process)
# Stop with Ctrl+C, then npm run dev again
---
## 7. Running Tests
Always run tests before submitting a pull request.
### Contracts
```bash
# AutoShare
cd contract/contracts/hello-world && cargo test
# TaskBounty
cd Documents/Task\ Bounty && cargo test
cd listener
npm testcd dashboard
npm testThe CI pipeline executes these checks on every pull request:
# Listener
cd listener
npm run typecheck # TypeScript strict type checking
npm test # Jest test suite
# Dashboard
cd dashboard
npm run lint # ESLint (zero warnings)
npm run build # TypeScript check + Vite build
npm test # Jest test suite
# Contracts
cd contract
cargo fmt --all -- --check # Rust formatting check
cargo test --workspace --all-features --verboseInstall these VS Code extensions:
- rust-analyzer — Rust language support
- CodeLLDB — Debugger for Rust
- Better TOML — TOML file support
- ESLint — TypeScript linting
- Prettier — Code formatter
Add this to .vscode/settings.json (already present in the repository):
{
"rust-analyzer.cargo.target": "wasm32-unknown-unknown",
"rust-analyzer.checkOnSave.allTargets": false
}This configures rust-analyzer to use the wasm32 target and avoids false-positive type errors from non-Wasm platform checks.
A more extensive troubleshooting guide is available at
TROUBLESHOOTING.md. This section covers the most common setup issues.
Q: npm install fails with node-gyp or sqlite3 errors.
Native sqlite3 bindings must be compiled for your platform and Node.js version.
# Rebuild native bindings
npm rebuild sqlite3
# If that fails, reinstall
npm uninstall sqlite3 && npm installOn Windows, ensure you have Visual Studio Build Tools installed with the
"C++ build tools" workload. On macOS, install Xcode Command Line Tools:
xcode-select --install.
On Windows, ensure you have Visual Studio Build Tools installed with the "C++ build tools" workload.
Q: Which Node.js version should I use?
The listener CI runs on Node 20, the dashboard CI runs on Node 18. Use Node 20 for local development (it is forward-compatible with the dashboard). Use nvm to switch if needed.
Q: The listener starts but no events appear.
- Verify the contract ID in
CONTRACT_ADDRESSESis correct and deployed on the same network asSTELLAR_RPC_URL. - Confirm the RPC endpoint is reachable:
curl -X POST https://soroban-testnet.stellar.org:443 -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"getHealth"}'
- Check listener logs for poll cycle output:
Look for lines containing
cd listener && npm run dev
"Received events"or"Processing event". - Verify the API is responding:
curl http://localhost:8787/health curl http://localhost:8787/api/events
Q: stellar: command not found
# Ensure cargo's bin directory is in your PATH
source "$HOME/.cargo/env"
# Or reinstall
cargo install --locked stellar-cli --features optQ: Error: Database not initialized or SQLITE_ERROR: no such table
cd listener
npm run migrateIf the data directory is missing:
mkdir -p listener/data
npm run migrateQ: EADDRINUSE: address already in use :::8787
# Find the process using the port (macOS/Linux)
lsof -i :8787
kill -9 <PID>
# Or change the port in listener/.env
EVENTS_API_PORT=8788Q: Dashboard shows a blank page or "Failed to fetch"
- Is the listener running? (
npm run devinlistener/) - Does
VITE_EVENTS_API_URLindashboard/.envmatch the listener's port? - Restart the Vite dev server after editing
.env.
Q: error: toolchain 'stable' does not support target 'wasm32-unknown-unknown'
rustup target add wasm32-unknown-unknownQ: error[E0463]: can't find crate for 'std'
Build with the correct target:
cargo build --target wasm32-unknown-unknown --release
# Or use Stellar CLI (handles the target automatically):
stellar contract buildIf things stop working after pulling latest changes, run the full refresh: If things stop working after pulling latest changes:
# Contracts
cd contract && stellar contract build
# Listener
cd listener && npm install && npm run migrate
# Dashboard
cd dashboard && npm install
# Frontend
cd frontend && npm install- Search open issues — your problem may already be reported.
- Search open issues — your problem may already be reported.
- Read the detailed Troubleshooting Guide.
- Open a new issue with:
- Your OS and version
- Output of
rustc --version,node --version,stellar --version - The full error message and stack trace
- Steps you have already tried
Notify-Chain/
├── contract/ # Soroban smart contract workspace
│ ├── contracts/hello-world/ # AutoShare contract (active)
│ └── Cargo.toml # Workspace configuration
│
├── listener/ # Off-chain listener service
│ ├── src/
│ │ ├── api/ # HTTP API (events, health, templates)
│ │ ├── services/ # Core: subscriber, dedup, notifier, scheduler
│ │ ├── store/ # In-memory event registry + preferences
│ │ ├── database/ # SQLite schema and client
│ │ ├── types/ # TypeScript type definitions
│ │ ├── utils/ # Logging, formatting, helpers
│ │ └── index.ts # Entry point
│ └── src/__tests__/ # Integration / E2E tests
│
├── dashboard/ # React + Vite event dashboard
│ └── src/
│ ├── components/ # UI components (EventCard, filters, etc.)
│ ├── services/ # API client
│ ├── store/ # Zustand state management
│ └── pages/ # Page components
│
├── Documents/Task Bounty/ # TaskBounty contract (Soroban)
│
├── frontend/ # Next.js analytics dashboard (Chart.js)
│ └── app/
│ ├── analytics/ # Analytics pages with charts
│ └── page.tsx # Landing page
├── frontend/ # Legacy Next.js frontend (not actively maintained)
│
├── scripts/ # Helper scripts (health check, etc.)
│
├── CONTRIBUTOR_SETUP.md # This file
├── CONTRIBUTING.md # Contribution guidelines & PR workflow
├── TROUBLESHOOTING.md # Detailed troubleshooting reference
├── ARCHITECTURE_OVERVIEW.md # High-level architecture walkthrough
├── SYSTEM_ARCHITECTURE.md # Visual architecture with Mermaid diagrams
└── README.md # Project overview and quick start