About MonadPulse

What this is, where the data comes from, and how it works

What is MonadPulse?

MonadPulse is an independent analytics platform for the Monad network. It shows what no standard block explorer does: validator performance patterns, health scores, block production anomalies, gas trends, and real-time alerts.

Built by shadowoftime, an independent Monad testnet validator based in Sydney, Australia. The platform runs on the same server as the validator node, pulling data directly from the local RPC with zero external dependencies.

How does Health Score work?

Each validator gets a score from 0 to 100 recalculated every hour. The score is a weighted composite of five factors:

40% Uptime blocks produced / blocks assigned. This matches the VDP uptime formula as understood by the validator community. We approximate blocks_assigned via stake-weighted expectation (validator_stake / total_stake × network_blocks) since per-block leader election isn't exposed on-chain — correct in long-window averages. Target ≥98% weekly. During Foundation stake rotation when the validator is out of consensus, blocks_assigned = 0 and the validator is excluded from this metric, not penalised.
20% Block Quality How close avg block time is to the target (~400ms). Consistent timing = higher score.
15% Client compatibility Active validators who are proposing blocks at expected rate receive 100 — outdated clients fall out of consensus within days, so a healthy uptime implies a compatible version. The only validator we can directly penalize here is our own local node (monadpulse.xyz operator), whose web3_clientVersion is compared to the latest Monad release.
15% Stake Stability Compared across the last 3 epoch snapshots (written by the collector every 30 min): flat or growing total stake → 100, declining stake → lower score. Needs at least 2 epochs of data to activate — neutral 75 until then. Mainnet is still accumulating snapshots at the moment.
10% Age Days since the validator's first on-chain Reward event (read from the staking precompile). Maxes out at 30 days. On networks we only started indexing recently (MonadPulse began continuously indexing Monad mainnet in April 2026; Monad mainnet itself produced its first block on 14 May 2025, with public launch and TGE on 24 November 2025), visible age is capped by our data-retention window — validators older than that show the maximum we can see.

Color coding: green (80+) = excellent, orange (50-80) = moderate, pink (<50) = needs attention.

A 🔄 badge next to a validator's name means they are currently in Monad Foundation's stake-rotation cycle. Until the active-set is expanded via MIP9, Foundation periodically pulls part of its VDP delegation from some validators and redistributes it to others — so every delegated validator gets time in the active-set. Validators flagged here are intentionally idle, not failing: uptime scoring skips the recency penalty for them, so their Health reflects pre-rotation performance, not the forced gap.

The 0–100 scale is the theoretical maximum. In practice no validator reaches 100: it would require perfect uptime (40pt) plus perfect block timing (20pt) plus latest client upgrade within hours (15pt) plus maximum delegation stake (15pt) plus 30+ days active (10pt). A validator in the upper-70s is at or near the top of the network. The same composite value appears in the API, on the Dashboard, on the Validators page and on each validator's detail page — no per-page re-scaling.

Where does the data come from?

Block data Testnet: local Monad node RPC (eth_getBlockByNumber) — real-time, every block. Mainnet: public rpc.monad.xyz — rate-limited, polled continuously.
Epoch data Staking precompile (0x...1000) getEpoch() — polled every 60 seconds as fallback; epoch boundaries also detected immediately on block ingest.
Validator names monad-developers/validator-info — canonical directory, mapped by SECP pubkey. Rebuild runs weekly + on every epoch boundary.
Client versions github.com/category-labs/monad releases API — checked hourly
Mainnet data Public RPC (rpc.monad.xyz) — rate-limited, best-effort
Staking events Staking precompile event logs via eth_getLogs (Delegate / Undelegate / ClaimRewards / Withdraw / CommissionChanged) — ingested every 60 seconds.
Delegation graph Aggregated from the staking precompile via get_delegators per validator — rebuilt weekly and on every epoch boundary.
Validator location Two layers: (1) P2P-signed peer registry (peers.toml) from our own Monad nodes — every validator publishes a signed name record with their IP and ports, and our nodes accumulate these as they discover peers. (2) Manual override from each operator's public information (website, social profiles) for the small set of validators not yet seen via P2P. IPs are then resolved through ip-api.com for city, country, ASN, and datacenter classification. Refreshes daily at 03:30 UTC.
Mainnet observer node A non-validating Monad mainnet full node runs on the same server as the testnet validator (since 2026-04-30). It exists solely to give MonadPulse access to mainnet block data, peer registry, and the staking precompile without depending on any third-party RPC. Isolated from the testnet validator via systemd cgroups (separate user, dedicated NVMe drives, capped CPU/memory/IO) — observer load cannot impact validator block production.

What are the Alerts?

MonadPulse monitors the network and generates alerts for notable events:

Slow blocks (>5 seconds) — something unusual happened with the proposer or network.
New epochs — boundary block reached, validator set may have changed.
TPS spikes — transaction volume >2x the 24h average.
New client releases — critical for VDP validators (48h update window).

All alerts are also sent to the public Telegram channel. Subscribe to get notified instantly.

Technical stack

Collector: Python asyncio service pulling blocks in real-time from local Monad RPC. Runs as systemd unit with rate limiting, graceful shutdown, and automatic backfill.
Database: PostgreSQL 16 with separate tables for blocks, epochs, health scores, gas stats, and alerts. All tables have a network column for testnet/mainnet separation.
API: FastAPI with async PostgreSQL queries. Rate-limited at nginx level (30 req/s).
Frontend: Vanilla HTML/JS with Chart.js. No framework, no build step. Dark theme with Monad brand colors.
Infra: OVH Advance-4, AMD EPYC 4585PX, 64GB RAM, 4x NVMe. Sydney, Australia.

Open source

MonadPulse is open source under the MIT license.
github.com/ShadowOfTime1/monadpulse