← Back to all products
$10
Inclusion Monitor
Monitor L1 inclusion of L2 batches, verify finality, and track sequencer commitment integrity.
TypeScriptJSONMarkdown
📁 File Structure 14 files
inclusion-monitor/
├── README.md
├── package.json
├── security-notes.md
├── src/
│ ├── alerts/
│ │ └── alert-manager.ts
│ ├── analyzers/
│ │ ├── censorship-detector.ts
│ │ └── inclusion-analyzer.ts
│ ├── config.ts
│ ├── index.ts
│ ├── monitor.ts
│ ├── providers/
│ │ ├── l1-provider.ts
│ │ └── l2-provider.ts
│ └── types/
│ └── index.ts
├── tests/
│ └── monitor.test.ts
└── tsconfig.json
📖 Documentation Preview README excerpt
Inclusion Monitor
Transaction inclusion tracking and censorship detection for rollup sequencers.
Price: $9.99 | License: MIT | Category: Tooling | Runtime: Node.js 18+
Overview
inclusion-monitor is a TypeScript service that tracks transaction inclusion times on rollup sequencers and detects potential censorship or MEV-related reordering. It maintains a local SQLite database of inclusion metrics and exposes an HTTP API for querying latency percentiles and alert history.
Designed for rollup operators, researchers, and watchdogs who need visibility into sequencer fairness and inclusion guarantees.
Features
- Inclusion time tracking — Measure submission-to-inclusion latency for every transaction
- Sequencer censorship detection — Flag transactions that remain unincluded beyond configurable thresholds
- MEV reordering analysis — Detect suspicious ordering patterns (priority inversions, backruns)
- Percentile latency reporting — p50, p90, p95, p99 inclusion latency with historical trends
- Webhook alerts — Notify Slack, Discord, or custom endpoints on anomalies
- REST API — Query inclusion stats, censorship events, and latency distributions
- Persistent storage — SQLite-backed history with configurable retention
Architecture
L2 RPC (WebSocket)
│
▼
TxWatcher ──→ Track pending txs
│
▼
InclusionTracker ──→ Match pending → included
│
├──→ LatencyStore (SQLite)
│
▼
CensorshipDetector ──→ Flag long-pending txs
│
▼
AlertManager ──→ Webhook / Console / File
│
▼
REST API (Express) ──→ /stats, /alerts, /latency
Tech Stack
| Component | Technology |
|---|---|
| Runtime | Node.js 18+, TypeScript |
| Chain | ethers.js v6 |
| HTTP Server | Express |
| Database | better-sqlite3 |
| Alerts | Axios (webhooks) |
Quick Start
Prerequisites
... continues with setup instructions, usage examples, and more.
📄 Code Sample .ts preview
src/config.ts
// ═══════════════════════════════════════════════════════════════════════════════
// CryptoForge Rollup Kit — Inclusion Monitor Configuration
// ═══════════════════════════════════════════════════════════════════════════════
import { MonitorConfig } from './types';
export const DEFAULT_CONFIG: MonitorConfig = {
l1RpcUrl: process.env.L1_RPC_URL || 'http://localhost:8545',
l2RpcUrl: process.env.L2_RPC_URL || 'http://localhost:9545',
pollIntervalMs: parseInt(process.env.POLL_INTERVAL_MS || '12000', 10),
inclusionThresholdSeconds: parseInt(process.env.INCLUSION_THRESHOLD_SECONDS || '300', 10),
censorshipThresholdSeconds: parseInt(process.env.CENSORSHIP_THRESHOLD_SECONDS || '1800', 10),
maxTrackedTransactions: parseInt(process.env.MAX_TRACKED_TXS || '10000', 10),
alertWebhookUrl: process.env.ALERT_WEBHOOK_URL,
alertRateLimitMs: parseInt(process.env.ALERT_RATE_LIMIT_MS || '60000', 10),
logLevel: (process.env.LOG_LEVEL as MonitorConfig['logLevel']) || 'info',
};
export function validateConfig(config: MonitorConfig): string[] {
const errors: string[] = [];
if (!config.l1RpcUrl) {
errors.push('l1RpcUrl is required');
}
if (!config.l2RpcUrl) {
errors.push('l2RpcUrl is required');
}
if (config.pollIntervalMs < 1000) {
errors.push('pollIntervalMs must be at least 1000ms');
}
if (config.inclusionThresholdSeconds < 10) {
errors.push('inclusionThresholdSeconds must be at least 10');
}
if (config.censorshipThresholdSeconds <= config.inclusionThresholdSeconds) {
errors.push('censorshipThresholdSeconds must be greater than inclusionThresholdSeconds');
}
if (config.maxTrackedTransactions < 100) {
errors.push('maxTrackedTransactions must be at least 100');
}
if (config.alertRateLimitMs < 1000) {
errors.push('alertRateLimitMs must be at least 1000ms');
}
try {
new URL(config.l1RpcUrl);
} catch {
errors.push('l1RpcUrl must be a valid URL');
}
try {
# ... 20 more lines ...