A collection of Rust and TypeScript packages for Solana stream data, operated by ValidatorsDAO. This repository is published as open-source software (OSS) and is freely available for anyone to use.
This project provides libraries and tools for streaming real-time data from the Solana blockchain. It supports both Geyser and Shreds approaches, making it easier for developers to access Solana data streams.
yellowstone-grpc-client 13.x and expose deshred, token-account expansion, and cuckoo filter helpersfromSlot / from_slot)Tip: start with slots, then add filters as needed. When resuming from fromSlot,
duplicates are expected.
If you have ERPC Dedicated Shreds, you can forward raw Shreds over UDP to your own listener. This is Solana’s fastest observation layer—before Geyser gRPC and far ahead of RPC/WebSocket. The SDK includes a simple Rust sample; pump.fun is used only because it’s the most common question we get.
Note: the shared Shreds gRPC endpoint runs over TCP, so it’s slower than UDP Shreds.
shreds-udp-rs, Rust): pump.fun is just a common example—swap in your own target.settings.jsonc plus env (e.g., SOLANA_RPC_ENDPOINT); see the sample README.ip:port to see detections.
This example comes from the SDK sample; clone and run it to see hits, or swap in your own target.
For the entire workspace:
git clone https://github.com/ValidatorsDAO/solana-stream.git
cd solana-stream
pnpm install
Create a .env file at client/geyser-ts/.env with your environment variables:
# Optional: required only if your endpoint enforces auth
X_TOKEN=YOUR_X_TOKEN
GEYSER_ENDPOINT=https://grpc-ams.erpc.global
SOLANA_RPC_ENDPOINT="https://edge.erpc.global?api-key=YOUR_API_KEY"
⚠️ Please note: This endpoint is a sample and cannot be used as is. Please obtain and configure the appropriate endpoint for your environment.
Next, build and run the client:
pnpm -F @validators-dao/solana-stream-sdk build
pnpm -F geyser-ts dev
Create a .env file (placed in the project root)
SHREDS_ENDPOINT=https://shreds-ams.erpc.global
SOLANA_RPC_ENDPOINT="https://edge.erpc.global?api-key=YOUR_API_KEY"
⚠️ Please note: This endpoint is a sample and cannot be used as is. Please obtain and configure the appropriate endpoint for your environment.
Run the sample client
cargo run -p shreds-rs
The sample code can be found at:
https://github.com/ValidatorsDAO/solana-stream/blob/main/client/shreds-rs/src/main.rs
A 1-day free trial for the Shreds endpoints is available by joining the Validators DAO Discord community. Please try it out: https://discord.gg/C7ZQSrCkYR
You can also use the published crate in your own projects:
[dependencies]
solana-stream-sdk = "1.4.0"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
dotenvy = "0.15"
solana-entry = "3.0.12"
bincode = "1.3.3"
use solana_stream_sdk::{CommitmentLevel, ShredstreamClient};
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load environment variables
dotenvy::dotenv().ok();
// Connect to shreds endpoint
let endpoint = env::var("SHREDS_ENDPOINT")
.unwrap_or_else(|_| "https://shreds-ams.erpc.global".to_string());
let mut client = ShredstreamClient::connect(&endpoint).await?;
// Create subscription for specific account
let request = ShredstreamClient::create_entries_request_for_account(
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
Some(CommitmentLevel::Processed),
);
// Subscribe to entries stream
let mut stream = client.subscribe_entries(request).await?;
// Process incoming entries
while let Some(entry) = stream.message().await? {
let entries = bincode::deserialize::<Vec<solana_entry::entry::Entry>>(&entry.entries)?;
println!("Slot: {}, Entries: {}", entry.slot, entries.len());
for entry in entries {
println!(" Entry has {} transactions", entry.transactions.len());
}
}
Ok(())
}
For specific packages, navigate to the package directory and install dependencies.
client/shreds-udp-rs listens for Shredstream over UDP and highlights watched programs (defaults to pump.fun). Settings live in client/shreds-udp-rs/settings.jsonc and are embedded at build time; secrets like RPC can be overridden via environment variables.
Quick start:
export SOLANA_RPC_ENDPOINT=https://api.mainnet-beta.solana.com # pass secrets via env only
cargo run -p shreds-udp-rs # settings already in settings.jsonc
Log legend:
🎯 program hit, 🐣 authority hit (🎯🐣 means both)🐣 create, 🟢 buy, 🔻 sell, 🪙 other, ❓ unknown/missing amountsskip_vote_txs=true)pump_min_lamports can suppress small pump.fun buy/sell logs❓.Components from crate/solana-stream-sdk (5 layers):
ShredsUdpConfig): reads JSONC/env and builds ProgramWatchConfig (pump.fun defaults; composite mint finder = pump.fun accounts + SPL Token MintTo/Initialize). Use watch_config_no_defaults() to opt out of pump.fun fallbacks.UdpShredReceiver): minimal UDP socket reader with timestamps.decode_udp_datagram) → ② FEC buffer (insert_shred + ShredsUdpState) → ③ deshred (deshred_shreds_to_entries) → ④ watcher/detail (collect_watch_events + detailers) → ⑤ sink (logs/custom hooks).handle_pumpfun_watcher wraps the same 5 layers (pump.fun defaults).ProgramWatchConfig::with_detailers(...) or replace the sink with your own hook.skip_vote_txs=true, so vote-only shreds/txs are dropped early.cargo run -p shreds-udp-rs (pump.fun defaults, one-call wrapper) or cargo run -p shreds-udp-rs --bin generic_logger (pump.fun-free logger; set GENERIC_WATCH_PROGRAM_IDS / GENERIC_WATCH_AUTHORITIES to watch your own programs).Troubleshooting:
solana-stream-sdk >= 1.4.0 for Direct Shreds UDP. Agave 3.x serializes deshredded entries with wincode; SDK 1.2.0 tried bincode first in the UDP helper, and SDK 1.2.1 could still decode from the middle of a multi-FEC entry segment.entry decode failed: invalid value: integer ..., expected a valid transaction message version, continue signal on byte-three, unexpected end of file, or alias encoding usually indicate a codec mismatch rather than firewall loss.Design notes
pump_min_lamports to log only pump.fun buy/sell with SOL limit above a threshold; logs show sol: when the limit is parsed.Quick choices:
handle_pumpfun_watcher in your own binary and set watch IDs/env as needed. This matches the out-of-the-box behavior shown in the screenshots.decode_udp_datagram → insert_shred → deshred_shreds_to_entries → collect_watch_events) and hook your own sink right after detection (see client/shreds-udp-rs custom hook example).Minimal usage example (Rust):
```rust use solana_stream_sdk::shreds_udp::{ShredsUdpConfig, ShredsUdpState, DeshredPolicy, handle_pumpfun_watcher}; use solana_stream_sdk::UdpShredReceiver; use std::sync::Arc;
async fn main() -> Result<(), Box> { let cfg = ShredsUdpConfig::from_env(); // reads SHREDS_UDP_CONFIG jsonc too let mut receiver = UdpShredReceiver::bind(&cfg.bind_addr, None).await?; let policy = DeshredPolicy { require_code_match: cfg.require_code_match }; let watch_
$ claude mcp add solana-stream \
-- python -m otcore.mcp_server <graph>