You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Self-hosted validator monitoring for Ethereum, Polkadot, Cosmos, Solana, and more — Prometheus metrics and multi-channel alerts. A FastAPI dashboard watches operator duties, consensus health, and host infrastructure so you catch downtime and penalties early.
It does not scan external security surfaces. One CHAIN per process.
All three start in demo mode so you can confirm the UI without a node. One CHAIN per process — ethereum,solana is invalid; run a second instance for a second network.
Option A — PyPI
Python 3.11 or newer (python3 --version), then:
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -U pip
pip install validator-pulse
validator-pulse init # writes .env.local in this directory
validator-pulse # prints config path + docs, then starts
validator-pulse --help shows the same pointers. The app reads .env.local, then .env, from the current working directory (not from the package). Leave DEMO_MODE=true and CHAIN=ethereum for the first run.
Caddyfile.restrict is fail-closed: an empty allowlist denies everyone. Set WEB_AUTH_USERNAME / WEB_AUTH_PASSWORD as well if Caddy is reachable beyond this machine. Single-host only — not Kubernetes.
If the install fails
Symptom
Likely cause
python3: command not found or version < 3.11
Install Python 3.11+ and retry Option A or B
No module named validator_pulse
venv not active, or (Option B) you skipped pip install -e .
Address already in use / port 3000 busy
Another process (often a previous validator-pulse) holds the port. Stop it, or validator-pulse --port 3001
PARACHAIN_ID is ignored on relay (DOT unless you override the token). Relay live mode uses era points + block production until full staking-storage decoding lands.
Committee selection is private — only observed votes/proposals are recorded. Offline / suspension is operational risk, not slashing.
BNB Smart Chain
Required
Example
BSC_RPC_URL
https://bsc-dataseed.binance.org
BSC_VALIDATOR_ADDRESSES
operator or consensus 0x…
Optional: BSC_METRICS_URL, contract overrides, BSC_MISDEMEANOR_THRESHOLD / BSC_FELONY_THRESHOLD. Downtime thresholds come from getSlashThresholds() unless you override them. Double-sign and malicious finality votes are immediately critical.
Aptos
Required
Example
APTOS_REST_URL
https://fullnode.mainnet.aptoslabs.com/v1
APTOS_POOL_ADDRESSES
staking-pool 0x…
ALERT_APTOS_FAILED_PROPOSALS
3
Optional: APTOS_METRICS_URL, APTOS_API_KEY. Failed proposals cost rewards; there is no principal slashing.
Sui
Required
Example
SUI_GRAPHQL_URL
https://graphql.mainnet.sui.io/graphql
SUI_VALIDATOR_ADDRESSES
0x…
ALERT_SUI_AT_RISK_EPOCHS
3
Optional local Prometheus: SUI_METRICS_URL (9184/metrics). Safe mode and confirmed reward slashing are critical; low-stake atRisk stays a separate signal.
Monad
Required
Example
MONAD_RPC_URL
https://rpc.monad.xyz (chain ID 143)
MONAD_VALIDATOR_IDS
numeric IDs
Optional local evidence: MONAD_METRICS_URL, MONAD_LEDGER_TAIL_PATH, MONAD_STATUS_PATH. EVM RPC alone cannot claim missed duties. Automated slashing is not implemented — reward / eligibility risk only.
Avalanche
Required
Example
AVALANCHE_RPC_URL
http://127.0.0.1:9650
AVALANCHE_NODE_IDS
NodeID-…
ALERT_AVALANCHE_RUNWAY_HOURS
24
Optional
Purpose
AVALANCHE_NETWORK
mainnet or fuji
AVALANCHE_METRICS_URL
/ext/metrics
AVALANCHE_UPTIME_THRESHOLD
else ACP-267 (80% pre-Helicon, 90% after)
Primary Network only. Reliable uptime needs a local node (info.uptime). Public info.uptime is never treated as the configured validator. Reward forfeiture is not principal slashing.
Mina
Required
Example
MINA_GRAPHQL_URL
http://127.0.0.1:3085/graphql
MINA_PRODUCER_PUBLIC_KEYS
B62…
ALERT_MINA_NEAR_SLOT_SLOTS
2
Optional: MINA_CLIENT_COMMAND, MINA_ARCHIVE_DATABASE_URL, MINA_LOG_PATH. Public GraphQL cannot list another producer’s private VRF duties. Query-only. No producer-stake slash.
MultiversX
Required
Example
MULTIVERSX_NODE_API_URL
http://127.0.0.1:8080
MULTIVERSX_GATEWAY_URL
https://gateway.multiversx.com
MULTIVERSX_VALIDATOR_BLS_KEYS
192-hex BLS keys
ALERT_MULTIVERSX_RATING_BELOW
20
Optional: MULTIVERSX_SHARD_ID, MULTIVERSX_JAIL_RATING_THRESHOLD. Each key on a multikey host is scored independently. Low-rating jail ≠ serious-offence stake slash.
TON
Required
Example
TON_VALIDATION_API_URL
https://elections.toncenter.com
TON_ADNL_ADDRESSES
64-hex ADNL
ALERT_TON_EFFICIENCY_BELOW
90
Optional
Purpose
TON_QOS_API_URL
catchain efficiency (efficiency may be null — not 0%)
TON_PROMETHEUS_URL / TON_MYTONCTRL_COMMAND
local read-only MyTonCtrl
TON_NETWORK
mainnet or testnet (label)
TON_EFFICIENCY_THRESHOLD
override the 90% completed-round policy
Native token displays as GRAM (formerly Toncoin / TON). The network is still TON; CHAIN=ton is unchanged. Base unit stays nanoton. Complaints / fines are fine risk, not Ethereum-style principal slashing. Zero efficiency at round start is ignored.
Auth and Prometheus
Auth is off when unset (local demos stay open). Set both username and password for HTTP Basic on the dashboard and APIs.
/api/metrics only (Authorization: Bearer, X-Metrics-Token, or ?token=)
WEB_METRICS_TOKEN does not unlock the dashboard. Binding off loopback without credentials logs a warning.
Install
Prometheus target
A / B (PyPI or venv)
127.0.0.1:3000
C (Compose)
127.0.0.1:9091 (keep scrapes on loopback)
scrape_configs:
- job_name: validatorpulsestatic_configs:
- targets: ["127.0.0.1:9091"] # Compose; use :3000 for venvauthorization:
type: Bearercredentials: scrape-token-here
To scrape a public Caddy site instead, add the scraper CIDR to CADDY_ALLOW_IPS.
Configuration
Restart after changing .env.local (or rely on reload with python -m validator_pulse). Chain-specific variables live in Per-chain setup. Everything else:
# A / B (PyPI or venv)
curl -X POST http://127.0.0.1:3000/api/alerts/test
# C (Compose / Caddy)
curl -X POST http://127.0.0.1/api/alerts/test
API
GET /api/status is schema_version: 2 (operator_id, *_base_units, duties, risk_score). Prometheus emits operator_* (preferred; chain / operator_id labels) and legacy validator_*. *_gwei is the same integer as *_base_units.
Method
Path
Purpose
GET
/
Dashboard
GET
/api/status
Full health snapshot (JSON)
GET
/api/metrics
Prometheus text exposition
POST
/api/collect
Force a collection cycle
POST
/api/alerts/test
Send a test alert
Scoring
Score
Range
Meaning
Effectiveness
0–100
Weighted primary / secondary duty completion; late primary duties get partial credit