Anomaly Detection Dashboard on Solana by Employing the Goldrush Streaming API - (Part 1)

Rajdeep Singha
Content Writer
Real-time anomaly detection transforms Web3 security from reactive to proactive. By integrating Goldrush Streaming APIs and granular monitoring

In Web3, every millisecond matters.
A wallet can be drained faster than you can refresh your block explorer. A single node lag can cascade into a network-wide outage. On Solana — where thousands of transactions fly by every second — visibility isn’t optional, it’s survival.

Traditional monitoring tools built for Web2 simply can’t keep up. They rely on slow, fixed-interval checks and miss what really matters — the spikes, surges, and subtle anomalies that hint at exploits or performance breakdowns.

That’s where protocol observability steps in. It’s the art (and science) of watching everything that happens at the node, contract, and network levels — in real time. Think of it as your blockchain’s nervous system, firing alerts the moment something feels off.

Now imagine pairing that observability with a streaming API like Goldrush — capable of capturing second-by-second on-chain data from Solana. You don’t just monitor; you predict and prevent. From sudden balance drops to suspicious bursts of wallet activity, you’ll see anomalies before they become incidents.

This guide will show you how.
We’ll explore how to build a real-time monitoring and anomaly detection pipeline on Solana using Goldrush, combining threshold-based alerts, statistical logic, and machine learning — so your dApp isn’t just reactive… it’s resilient.

Core Concepts: What Makes Solana Observability Different

Observability on Solana isn’t just about “watching blocks roll in.”
It’s about making sense of chaos — thousands of transactions, validator messages, and contract calls happening every second — and turning that noise into signal.

Here’s what you really need to track to keep your dApp or wallet healthy:

  •  Transaction Throughput – Measures how many transactions the network can process per second. A sudden dip? You might be facing congestion or RPC throttling.

  •  Block Finality – Tells you when a block becomes irreversible. If it starts lagging, your confirmations are no longer reliable.

  •  Network Latency – Tracks how long it takes data to travel between nodes. Higher latency means slower updates and frustrated users.

  • Smart Contract Events – Reveal everything from token transfers to liquidity changes. Unusual spikes can indicate exploits or bots at work.

  •  Node Health – Validator uptime and sync status directly affect your protocol’s stability — one faulty node can ripple across the chain.


All this data has to come from somewhere.
You can tap into Solana nodes and RPC endpoints for raw, ground-truth information — but for real-time insights, you need streaming APIs like Goldrush.

Goldrush doesn’t wait for you to ask; it pushes live data — wallet balances, DEX trades, validator health, token flows — as they happen. Traditional monitoring tools poll data every few minutes, missing events that occur between checks. But Solana moves too fast for that. Transactions settle in under a second — by the time a log file updates, the exploit is already over.

Streaming APIs change that game completely.
They deliver continuous, high-frequency data that lets you:

  • Detect flash loan attacks the instant they start

  • Catch transaction spikes or gas anomalies in seconds

  • Identify failed contract calls that hint at bugs before they cascade

In short: traditional monitoring looks backward; streaming observability looks forward.
That’s what makes it essential for Web3 developers building on Solana.

By implementing anomaly detection, teams gain several competitive advantages: security threats are identified within seconds rather than hours, reducing exposure windows. User trust increases through transparent, real-time visibility. Operational efficiency improves as alerts are actionable and specific, not noisy false positives. Compliance becomes easier when audit trails capture every anomaly with timestamps and context

Tutorial for the getting the OHLCV Stream up and running

Step 1: Environment Setup

Begin by installing Node.js (version 16+) and npm. Visit nodejs.org and download the LTS version. Verify installation:

node --version

npm --version

Step 2: Project Initialization

2.1) Create a new directory for your project:

mkdir solana-anomaly-detector

cd solana-anomaly-detector

What this does: Creates a new folder for your project and enters it. All your files will be organized here.

2.2) Initialize npm and install dependencies:

npm init -y

npm install dotenv @covalenthq/client-sdk chalk

What this does:

  • npm init -y creates a package.json file (package configuration file) with default settings

  • npm install dotenv installs the dotenv package to safely load environment variables from .env file

  • npm install @covalenthq/client-sdk installs Covalent's official Goldrush SDK for streaming blockchain data

  • npm install chalk installs the chalk package for colored terminal output (makes logs easier to read)

2.3) Create a .env file in the root directory:

GOLDRUSH_KEY=your_api_key_here

What this does: Stores your Goldrush Streamin API key securely in a .env file. This file is ignored by Git (never committed) so your credentials stay private.

Obtain your Goldrush API key from goldrush.dev by registering as a developer. This key authenticates your requests to the Goldrush Streaming API.

Step 3: Project Structure

Organize your project with this directory structure:

solana-anomaly-detector/

├── .env

├── .gitignore

├── package.json

├── package-lock.json

├── goldrush-cli.js

Live data: subscribe to OHLCV on SOL

Before we dive into the actual code, it’s worth aligning on what you’re actually streaming, how GoldRush delivers it, and what “good” looks like in production.

What “OHLCV” means in this context

OHLCV stands for Open, High, Low, Close, Volume—a candlestick that aggregates many swaps into a single bar. On Base, these bars are derived from DEX pools (e.g., Uniswap v3). Each bar represents a fixed window (e.g., 1 minute) for a specific pool/pair contract.

GoldRush’s OHLCV Pairs stream expects a pool/pair contract address, not a token address. The pool address is typically listed on the DEX pool page, and it's a good idea to keep a small map of token addresses/decimals (such as WETH, USDC, or any other token you’re working with) for later trading logic.

How the stream behaves

When you connect, you choose an interval and a timeframe.  That initial backfill warms up your model, so you don’t start cold. Then, you switch to the live bar when you’re ready.

The GoldRush SDK multiplexes multiple subscriptions over a single WebSocket, allowing you you add Token Balances or Wallet Activity streams later without opening new sockets. Keep the event handler light—do heavy work off-thread if you scale up.

  1. Interval = the size of each candle (e.g., ONE_MINUTE).

  2. Timeframe = how many historical bars to send immediately on connect (e.g., one_hour gives ~60 bars).

// add .env file in the root directory GOLDRUSH_KEY=your_api_key
// Package.json { "name": "sol_detection", "version": "1.0.0", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node goldrush-cli.js" }, "keywords": [], "author": "", "license": "ISC", "description": "", "dependencies": { "@covalenthq/client-sdk": "^2.3.4", "chalk": "^4.1.2", "dotenv": "^17.2.3", "graphql-ws": "^6.0.6", "ws": "^8.18.3" } }

Create goldrush-cli.js in the root folder

Step 4: Setting Up Environment & Imports

require('dotenv').config(); const { GoldRushClient, StreamingChain, StreamingInterval, StreamingTimeframe, } = require('@covalenthq/client-sdk'); let chalk;

We start by loading environment variables using dotenv to securely manage the API key.
Next, we import the Covalent GoldRush SDK — which provides the GoldRushClient for connecting to the streaming API.
We’ll also use Chalk later to add colors and formatting to our terminal output.

Step 5: Initializing the GoldRush Client

(async () => { chalk = (await import('chalk')).default; const apiKey = process.env.GOLDRUSH_KEY; if (!apiKey) { console.error("ERROR: GOLDRUSH_KEY not found in .env file"); process.exit(1); } const client = new GoldRushClient(apiKey, {}, { onConnecting: () => console.log(chalk.blue("🔗 Connecting to GoldRush streaming service...")), onOpened: () => { console.clear(); displayHeader(); console.log(chalk.green("✓ Connected to streaming service!\n")); console.log(chalk.yellow("📡 Monitoring Wrapped SOL OHLCV data for anomalies...\n")); }, onClosed: () => { console.log(chalk.yellow("✓ Disconnected from streaming service")); process.exit(0); }, onError: (error) => { console.error(chalk.red("✗ Streaming error:"), error); }, });

Here, we:

  • Load chalk dynamically to avoid import issues.

  • Retrieve the GOLDRUSH_KEY from .env.

  • Initialize the GoldRushClient with event handlers for:

    • Connecting

    • Opened

    • Closed

    • Error

Each event logs a visual status message in the console, improving observability.

Step 6: Setting Configurations & Helper Functions

const priceHistory = []; const MAX_HISTORY = 50; const tokenAddress = "3ucNos4NbumPLZNWztqGHNFFgkHeRMBQAVemeeomsUxv"; // USDC on Sol function displayHeader() { console.log(chalk.cyan.bold('═══════════════════════════════════════════════════════════════')); console.log(chalk.cyan.bold(' 🚀 SOLANA TOKEN OHLCV ANOMALY DETECTION - GOLDRUSH')); console.log(chalk.cyan.bold('═══════════════════════════════════════════════════════════════')); console.log(chalk.yellow.bold(' ⚠️ BETA STREAM - May have limited availability')); console.log(chalk.gray(' Contact [email protected] for assistance')); console.log(chalk.cyan.bold('═══════════════════════════════════════════════════════════════')); } function formatPrice(price) { if (!price || price === 0) return '0.000000'; const num = parseFloat(price); return num.toFixed(6); } function formatVolume(volume) { if (!volume || volume === 0) return '0.0000e+0'; const num = parseFloat(volume); return num.toExponential(4); }

We configure:

  • priceHistory to store recent candles.

  • MAX_HISTORY as the sliding window size.

  • tokenAddress for USDC on Solana.

Then, we define helper functions for:

  • Displaying the fancy header.

  • Formatting numbers for prices and volumes in a readable way.

Step 7: Calculating Stats & Detecting Anomalies

function calculateStats(history) { if (history.length < 2) return null; const closes = history.map(c => parseFloat(c.close) || 0).filter(p => p > 0); const volumes = history.map(v => parseFloat(v.volume) || 0).filter(v => v > 0); if (closes.length < 2) return null; const avgClose = closes.reduce((a, b) => a + b) / closes.length; const avgVolume = volumes.reduce((a, b) => a + b, 0) / volumes.length; const stdDev = Math.sqrt(closes.reduce((sq, n) => sq + Math.pow(n - avgClose, 2), 0) / closes.length); return { avgClose, avgVolume, stdDev }; } function detectAnomalies(candle, history) { const anomalies = []; if (history.length < 3) return anomalies; const stats = calculateStats(history); if (!stats) return anomalies; const currentPrice = parseFloat(candle.close) || 0; const currentVolume = parseFloat(candle.volume) || 0; const currentHigh = parseFloat(candle.high) || 0; const currentLow = parseFloat(candle.low) || 0; // Detect price & volume spikes, and volatility const priceChange = ((currentPrice - stats.avgClose) / stats.avgClose) * 100; if (Math.abs(priceChange) > stats.stdDev * 2) { anomalies.push({ type: 'PRICE_SPIKE', severity: Math.abs(priceChange) > stats.stdDev * 3 ? 'CRITICAL' : 'HIGH', value: priceChange.toFixed(2) + '%', details: `Price: ${formatPrice(currentPrice)} vs Avg: ${formatPrice(stats.avgClose)}` }); } if (stats.avgVolume > 0 && currentVolume / stats.avgVolume > 2) { anomalies.push({ type: 'VOLUME_SPIKE', severity: currentVolume / stats.avgVolume > 5 ? 'CRITICAL' : 'HIGH', value: (currentVolume / stats.avgVolume).toFixed(2) + 'x', details: `Volume: ${formatVolume(currentVolume)} vs Avg: ${formatVolume(stats.avgVolume)}` }); } const spread = currentHigh - currentLow; const lastCandle = history[history.length - 1]; const avgSpread = parseFloat(lastCandle.high) - parseFloat(lastCandle.low); if (spread > avgSpread * 3) { anomalies.push({ type: 'HIGH_VOLATILITY', severity: 'MEDIUM', value: (spread / avgSpread).toFixed(2) + 'x', details: `Spread: ${formatPrice(spread)} vs Avg: ${formatPrice(avgSpread)}` }); } return anomalies; }

These functions:

  • Compute average price, volume, and standard deviation.

  • Detect price spikes, volume surges, and volatility patterns based on deviation thresholds.

This forms the core “anomaly detection engine” of your script.


Step 8: Displaying Stream & Candle Data

function displayStreamStatus() { const uptime = Math.floor((Date.now() - streamStartTime) / 1000); console.log(chalk.cyan('┌─ STREAM STATUS ───────────────────────────────────────────┐')); console.log(chalk.white(` Status: ${chalk.green('🟢 ACTIVE')}`)); console.log(chalk.white(` Uptime: ${chalk.blue(`${Math.floor(uptime / 60)}m ${uptime % 60}s`)}`)); console.log(chalk.white(` Data Count: ${chalk.yellow(dataCount)}`)); console.log(chalk.cyan('└──────────────────────────────────────────────────────────┘')); } function displayCandle(candle, anomalies) { const timestamp = new Date(candle.timestamp).toLocaleString(); const tokenName = candle.base_token?.contract_ticker_symbol || 'Unknown'; console.log(chalk.yellow(`📊 Token: ${tokenName}`)); console.log(chalk.yellow(`⏰ Timestamp: ${timestamp}`)); console.log(''); console.log(chalk.cyan('┌─ PRICE DATA (OHLCV) ─────────────────────────────────────┐')); console.log(chalk.white(` Open: ${chalk.blue(formatPrice(candle.open))}`)); console.log(chalk.white(` High: ${chalk.green(formatPrice(candle.high))}`)); console.log(chalk.white(` Low: ${chalk.red(formatPrice(candle.low))}`)); console.log(chalk.white(` Close: ${chalk.yellow(formatPrice(candle.close))}`)); console.log(chalk.cyan('└──────────────────────────────────────────────────────────┘')); console.log(''); if (anomalies.length > 0) { console.log(chalk.red.bold('⚠️ ANOMALIES DETECTED')); anomalies.forEach(a => console.log(chalk.red(`[${a.severity}] ${a.type}: ${a.value} → ${a.details}`)) ); } else { console.log(chalk.green('✓ No anomalies detected - Normal price action')); } }

These functions control how the live stream data and detected anomalies are displayed — making it look like a clean, interactive dashboard.

Step 9: Handling Idle Streams (Heartbeat)

function displayWaitingScreen() { console.log(chalk.yellow('⏳ Waiting for OHLCV data...')); console.log(chalk.gray('Stream is active and monitoring for anomalies.')); } const timeoutId = setTimeout(() => { displayWaitingScreen(); heartbeatInterval = setInterval(() => displayWaitingScreen(), 10000); }, 5000);

If the stream is idle (no data yet), this part ensures users know the script is still alive — by showing a heartbeat message every 10 seconds.

Step 10: Subscribing to the GoldRush Stream

const unsubscribe = client.StreamingService.subscribeToOHLCVTokens( { chain_name: StreamingChain.SOLANA_MAINNET, token_addresses: [tokenAddress], interval: StreamingInterval.ONE_MINUTE, timeframe: StreamingTimeframe.ONE_HOUR, }, { next: (data) => { dataReceived = true; clearTimeout(timeoutId); lastDataReceived = Date.now(); dataCount++; let candles = data?.items || [data]; candles.forEach(candle => { priceHistory.push(candle); if (priceHistory.length > MAX_HISTORY) priceHistory.shift(); const anomalies = detectAnomalies(candle, priceHistory.slice(0, -1)); displayCandle(candle, anomalies); }); }, error: (err) => console.error(chalk.red('✗ Subscription error:'), err), complete: () => console.log(chalk.green('✓ Stream completed')), } );

This is where the real-time streaming magic happens.
You subscribe to the Solana mainnet OHLCV feed for the selected token and process every new candle to detect anomalies instantly.

Step 11: Shutdown the stream

process.on('SIGINT', async () => { console.log("\n" + chalk.yellow("🛑 Shutting down...")); if (heartbeatInterval) clearInterval(heartbeatInterval); unsubscribe(); await client.StreamingService.disconnect(); process.exit(0); }); })();

Finally, we handle user termination (Ctrl+C) gracefully — unsubscribing from the stream, clearing timers, and closing the client cleanly.

What this full code does

This Node.js application monitors Solana token prices in real time using the GoldRush Streaming API.
It continuously tracks Open, High, Low, Close, Volume (OHLCV) price data and automatically detects trading anomalies that could indicate market manipulation, pump-and-dump schemes, or unusual trading activity.


Data Flow

  1. Connection opens → “Connecting…” message appears

  2. Stream starts → Waiting for first OHLCV data

  3. Data arrives → Raw JSON logged for debugging

  4. Candle data extracted → Parsed from response

  5. History updated → Adds latest candle (max 50)

  6. Stats calculated → Average and deviation computed

  7. Anomalies detected → Price, volume, or volatility alerts triggered

  8. Output displayed → Beautifully formatted with color-coded alerts

  9. Loop continues → Repeats for each new candle every minute

What the Output Shows

Each incoming update displays:

  • Token name and symbol

  • Timestamp of the data

  • OHLCV (Open, High, Low, Close, Volume) values

  • Volume in USD

  • Current price and quote rate

  • Token metadata (name, symbol, decimals)

  • Any detected anomalies with severity levels

Conclusion

Real-time anomaly detection transforms Web3 security from reactive to proactive. By integrating Goldrush Streaming APIs and granular monitoring, developers gain millisecond-level visibility into wallet activity—enabling instant threat detection and response.

But this is just the beginning. In Part 2, we’ll dive into building a production-grade observability and anomaly detection system powered by Goldrush on Solana. You’ll learn how to:

  • Define your monitoring scope (smart contracts, validators, or network-level events)

  • Stream live Solana data using low-latency WebSocket connections

  • Architect a scalable ingestion pipeline for real-time analytics

  • Implement threshold-based and ML-powered detection logic
    ….. And much more , lets dive dive into this in the next part .

Get Started

Get started with GoldRush API in minutes. Sign up for a free API key and start building.

Support

Explore multiple support options! From FAQs for self-help to real-time interactions on Discord.

Contact Sales

Interested in our professional or enterprise plans? Contact our sales team to learn more.