Skip to content

Latest commit

 

History

469 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Swipely — Backend

API and monitoring services for Swipely, a cross-chain bridge and DEX liquidity monitoring platform for the Stellar network. This service ingests on-chain and off-chain data, computes bridge-health and liquidity metrics, exposes a REST + WebSocket API, and dispatches alerts.

Tech stack

  • Node.js + TypeScript
  • Fastify 5 (REST, WebSockets, Swagger/OpenAPI)
  • PostgreSQL via Knex (migrations + seeds)
  • Redis + BullMQ for queues and background jobs
  • @stellar/stellar-sdk and ethers for chain access
  • Prometheus (prom-client) metrics, pino logging
  • Alerting via Discord, Telegram, and email (nodemailer)
  • Zod for validation, Vitest for tests

Getting started

npm install
cp .env.example .env        # then fill in the values
npm run migrate             # apply database migrations
npm run dev                 # start the API in watch mode

Useful scripts

Script Description
npm run dev Start the API with hot reload
npm run build Compile TypeScript to dist/
npm start Run the compiled server
npm run migrate Apply migrations
npm run seed Seed the database
npm run test Run the test suite
npm run docs:generate Generate the OpenAPI spec

API documentation

The API's OpenAPI 3 contract is generated from the live Fastify route schemas via npm run docs:generate and committed at docs/openapi.json (hand-authored fragments live under docs/openapi/). A CI check regenerates the spec on every push/PR and fails the build if it differs from the committed file, so the contract can't silently drift from the actual routes.

Once the API is running, Swagger UI serves the same spec interactively at http://localhost:<PORT>/docs (http://localhost:3001/docs with the default PORT) — the raw JSON is available at /docs/json and YAML at /docs/yaml.

Observability

Prometheus scrape config, alert rules, and a Grafana dashboard live alongside the service (prometheus.yml, prometheus-alerts.yml, grafana/). See METRICS_QUICKSTART.md for a fast local setup, and docs/metrics-collection.md for the full catalog of exposed metrics (names, types, labels, and meaning).

Environment variables

All variables are validated at startup by a Zod schema in src/config/index.ts. The process exits immediately with a clear error if any required variable is missing or malformed. Secret values are never included in error output — only the variable name appears.

Copy .env.example to .env and fill in the values. The table below lists every variable the app reads.

Legend — Required ★ means the app will not start without it in production. Variables with a default are optional everywhere.

Application

Variable Purpose Default Required
NODE_ENV Runtime environment development
PORT HTTP server port 3001
WS_PORT WebSocket server port 3002
CORS_ALLOWED_ORIGINS Comma-separated allowed CORS origins (production)

Security

Variable Purpose Default Required
JWT_SECRET Signs export download tokens (min 32 chars) ★ production
CONFIG_ENCRYPTION_KEY Encrypts sensitive config values at rest (min 32 chars) ★ production
API_KEY_BOOTSTRAP_TOKEN Seeds the first admin API key on first run

PostgreSQL / TimescaleDB

Variable Purpose Default Required
POSTGRES_HOST Database host localhost
POSTGRES_PORT Database port 5432
POSTGRES_DB Database name bridge_watch
POSTGRES_USER Database user bridge_watch
POSTGRES_PASSWORD Database password bridge_watch_dev ★ production

Redis

Variable Purpose Default Required
REDIS_HOST Redis host localhost
REDIS_PORT Redis port 6379
REDIS_PASSWORD Redis auth password ""
REDIS_CLUSTER Set "true" to enable Cluster mode in production

Stellar

Variable Purpose Default Required
STELLAR_NETWORK testnet or mainnet testnet
STELLAR_HORIZON_URL Horizon endpoint https://horizon-testnet.stellar.org
SOROBAN_RPC_URL Soroban RPC endpoint https://soroban-testnet.stellar.org
SOROBAN_MAINNET_RPC_URL Mainnet Soroban RPC endpoint
CIRCUIT_BREAKER_CONTRACT_ID Soroban circuit-breaker contract
LIQUIDITY_CONTRACT_ADDRESS Soroban liquidity contract

Ethereum / EVM

Variable Purpose Default Required
ETHEREUM_RPC_URL Ethereum JSON-RPC endpoint
ETHEREUM_RPC_WS_URL Ethereum WebSocket RPC endpoint
ETHEREUM_RPC_FALLBACK_URL Fallback Ethereum RPC
RPC_PROVIDER_TYPE http or ws http
USDC_BRIDGE_ADDRESS USDC bridge contract address
EURC_BRIDGE_ADDRESS EURC bridge contract address
USDC_TOKEN_ADDRESS USDC ERC-20 token address
EURC_TOKEN_ADDRESS EURC ERC-20 token address
POLYGON_RPC_URL Polygon RPC endpoint
POLYGON_RPC_FALLBACK_URL Fallback Polygon RPC
BASE_RPC_URL Base chain RPC endpoint
BASE_RPC_FALLBACK_URL Fallback Base chain RPC

External APIs

Variable Purpose Default Required
CIRCLE_API_KEY Circle API key for USDC/EURC data
CIRCLE_API_URL Circle API base URL https://api.circle.com
CIRCLE_API_TIMEOUT_MS Circle request timeout (ms) 5000
CIRCLE_CACHE_TTL_SEC Redis TTL for Circle responses (s) 60
CIRCLE_RATE_LIMIT_MAX Circle rate-limit max requests per window 30
CIRCLE_RATE_LIMIT_WINDOW_MS Circle rate-limit window (ms) 60000
COINBASE_API_KEY Coinbase Advanced Trade API key
COINBASE_API_SECRET Coinbase Advanced Trade API secret
ONEINCH_API_KEY 1inch EVM DEX aggregator API key
COINMARKETCAP_API_KEY CoinMarketCap API key
COINGECKO_API_KEY CoinGecko demo API key (higher rate limits)

Logging

Variable Purpose Default Required
LOG_LEVEL Minimum log level (fataltrace) info
LOG_FILE Write logs to file path (production)
LOG_MAX_FILE_SIZE Max log file size in bytes 104857600
LOG_MAX_FILES Max number of rotated log files 10
LOG_RETENTION_DAYS Days to retain log files 30
LOG_REQUEST_BODY Log incoming request bodies false
LOG_RESPONSE_BODY Log outgoing response bodies false
LOG_SENSITIVE_DATA Allow sensitive data in logs (must be false in prod) false
REQUEST_SLOW_THRESHOLD_MS Log warning for requests slower than this (ms) 1000

Rate Limiting

Variable Purpose Default Required
RATE_LIMIT_MAX Global max requests per window 100
RATE_LIMIT_WINDOW_MS Rate-limit window duration (ms) 60000
RATE_LIMIT_BURST_MULTIPLIER Burst allowance fraction of max 0.1
RATE_LIMIT_WHITELIST_IPS Comma-separated IPs that bypass limiting
RATE_LIMIT_WHITELIST_KEYS Comma-separated API keys that bypass limiting
RATE_LIMIT_ENABLE_DYNAMIC Enable dynamic rate limiting true
RATE_LIMIT_STATS_RETENTION_HOURS How long to retain rate-limit stats 168
RATE_LIMIT_ENDPOINT_ASSETS Per-window limit for /assets 200
RATE_LIMIT_ENDPOINT_BRIDGES Per-window limit for /bridges 150
RATE_LIMIT_ENDPOINT_ALERTS Per-window limit for /alerts 50
RATE_LIMIT_ENDPOINT_ANALYTICS Per-window limit for /analytics 100
RATE_LIMIT_ENDPOINT_CONFIG Per-window limit for /config 30
RATE_LIMIT_ENDPOINT_HEALTH Per-window limit for /health 1000

Price Provider Rate Limiting & Fallback

Per-provider outbound rate limits for the price aggregation pipeline. Each provider keeps an independent Redis counter, so throttling one source never throttles the others. Throttled or tripped providers fall back to their last-known-good cached price (marked stale) instead of fabricating data.

Variable Purpose Default Required
SDEX_RATE_LIMIT_MAX Stellar DEX (Horizon order book) max requests per window 30
SDEX_RATE_LIMIT_WINDOW_MS Stellar DEX rate-limit window (ms) 60000
AMM_RATE_LIMIT_MAX Stellar AMM (Horizon liquidity pools) max requests per window 30
AMM_RATE_LIMIT_WINDOW_MS Stellar AMM rate-limit window (ms) 60000
PRICE_PROVIDER_CACHE_TTL_SEC TTL (s) for last-known-good per-provider price fallback 300

Email (SMTP)

Variable Purpose Default Required
SMTP_HOST SMTP server hostname
SMTP_PORT SMTP server port 587
SMTP_SECURE Use TLS (true/false) false
SMTP_USER SMTP authentication user
SMTP_PASSWORD SMTP authentication password
SMTP_FROM_ADDRESS Sender email address noreply@bridgewatch.io
SMTP_FROM_NAME Sender display name Bridge Watch

Discord Bot

Variable Purpose Default Required
DISCORD_BOT_TOKEN Discord bot token
DISCORD_CLIENT_ID Discord application client ID

Telegram Bot

Variable Purpose Default Required
TELEGRAM_BOT_TOKEN Telegram bot token
TELEGRAM_WEBHOOK_URL Telegram webhook callback URL
TELEGRAM_WEBHOOK_SECRET Shared secret to verify Telegram webhook calls
TELEGRAM_ADMIN_CHAT_IDS Comma-separated admin Telegram chat IDs
TELEGRAM_BOT_ENABLED Enable/disable the Telegram bot true

Health Check

Variable Purpose Default Required
HEALTH_CHECK_TIMEOUT_MS Timeout for individual health checks (ms) 5000
HEALTH_CHECK_INTERVAL_MS Health check polling interval (ms) 30000
HEALTH_CHECK_MEMORY_THRESHOLD % heap usage before status → degraded 90
HEALTH_CHECK_DISK_THRESHOLD % disk usage before status → degraded 80
MAINTENANCE_MODE Enable maintenance mode false
MAINTENANCE_MESSAGE Maintenance status message ""
MAINTENANCE_SEVERITY Maintenance severity level info
STATUS_PAGE_URL Public status page URL

Export Service

Variable Purpose Default Required
EXPORT_STORAGE_PATH Directory to store exported files ./exports
EXPORT_DOWNLOAD_URL_EXPIRY_HOURS Hours before download URL expires 24
EXPORT_COMPRESSION_THRESHOLD_BYTES Compress exports larger than this 1048576
EXPORT_STREAMING_PAGE_SIZE Rows per page when streaming exports 1000
EXPORT_QUEUE_CONCURRENCY Concurrent export jobs 3
EXPORT_MAX_DATE_RANGE_DAYS Maximum allowed export date range 90

Compliance Reports

Variable Purpose Default Required
REPORT_DIR Directory for generated compliance reports ./reports
ARCHIVE_DIR Directory for archived reports ./archives
REPORT_SIGNING_KEY_PATH Path to PEM key used to sign reports

Background Jobs

Variable Purpose Default Required
RECONCILIATION_INTERVAL_MS Batch reconciliation poll interval 600000
SOURCE_DECOMMISSION_CHECK_INTERVAL_MS Source decommission readiness check interval 3600000
PROVIDER_BREAKER_PROBE_INTERVAL_MS Provider circuit-breaker probe sweep interval 30000
BRIDGE_VERIFICATION_INTERVAL_MS Bridge supply verification interval 300000

BullMQ Queue Rate Limiting

Variable Purpose Default Required
QUEUE_RATE_MAX_CRITICAL Max jobs per window for critical queue 1000
QUEUE_RATE_DURATION_MS_CRITICAL Window duration for critical queue (ms) 1000
QUEUE_RATE_MAX_HIGH Max jobs per window for high queue 1000
QUEUE_RATE_DURATION_MS_HIGH Window duration for high queue (ms) 1000
QUEUE_RATE_MAX_NORMAL Max jobs per window for normal queue 1000
QUEUE_RATE_DURATION_MS_NORMAL Window duration for normal queue (ms) 1000
QUEUE_RATE_MAX_LOW Max jobs per window for low queue 1000
QUEUE_RATE_DURATION_MS_LOW Window duration for low queue (ms) 1000

Miscellaneous

Variable Purpose Default Required
CORRELATION_THRESHOLD Incident correlation similarity score (0–1) 0.6
WS_AUTH_SECRET Secret for private WebSocket channel auth ★ production
RETRY_MAX Max retry attempts for external calls 3
PRICE_DEVIATION_THRESHOLD Fraction deviation that triggers a price alert 0.02
BRIDGE_SUPPLY_MISMATCH_THRESHOLD Fraction mismatch that triggers a supply alert 0.1

Related repositories

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages