Files

151 lines
5.0 KiB
Rust
Raw Permalink Normal View History

use solana_streamer_sdk::streaming::{
event_parser::{
common::{filter::EventTypeFilter, EventType},
protocols::{
bonk::parser::BONK_PROGRAM_ID,
meteora_damm_v2::parser::METEORA_DAMM_V2_PROGRAM_ID,
pumpfun::parser::PUMPFUN_PROGRAM_ID,
pumpswap::parser::PUMPSWAP_PROGRAM_ID,
raydium_amm_v4::parser::RAYDIUM_AMM_V4_PROGRAM_ID,
raydium_clmm::parser::RAYDIUM_CLMM_PROGRAM_ID,
raydium_cpmm::parser::RAYDIUM_CPMM_PROGRAM_ID,
sol_parser_forward::{
METEORA_DLMM_PROGRAM_ID, METEORA_POOLS_PROGRAM_ID, ORCA_WHIRLPOOL_PROGRAM_ID,
},
},
2025-11-10 00:38:23 +08:00
DexEvent, Protocol,
},
grpc::ClientConfig,
yellowstone_grpc::{AccountFilter, TransactionFilter},
YellowstoneGrpc,
};
2025-01-03 00:38:45 +08:00
2025-01-02 19:44:38 +08:00
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Starting Yellowstone gRPC Streamer...");
test_grpc().await?;
Ok(())
}
async fn test_grpc() -> Result<(), Box<dyn std::error::Error>> {
2025-08-03 05:37:04 +08:00
println!("Subscribing to Yellowstone gRPC events...");
// Create low-latency configuration.
// Metrics add overhead; enable explicitly with STREAMER_ENABLE_METRICS=1.
2026-06-01 20:20:01 +08:00
let config = ClientConfig {
enable_metrics: std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"),
..Default::default()
};
2025-08-03 05:37:04 +08:00
let grpc = YellowstoneGrpc::new_with_config(
"https://solana-yellowstone-grpc.publicnode.com:443".to_string(),
2025-05-31 14:45:20 +08:00
None,
2025-08-04 21:30:55 +08:00
config,
2025-05-31 14:45:20 +08:00
)?;
2025-08-03 05:37:04 +08:00
println!("GRPC client created successfully");
let callback = create_event_callback();
// Will try to parse corresponding protocol events from transactions
let protocols = vec![
Protocol::PumpFun,
Protocol::PumpSwap,
Protocol::Bonk,
Protocol::RaydiumCpmm,
Protocol::RaydiumClmm,
Protocol::RaydiumAmmV4,
2025-11-10 00:38:23 +08:00
Protocol::MeteoraDammV2,
Protocol::OrcaWhirlpool,
Protocol::MeteoraPools,
Protocol::MeteoraDlmm,
];
2025-08-03 05:37:04 +08:00
println!("Protocols to monitor: {:?}", protocols);
// Filter accounts
let account_include = vec![
2025-11-10 00:38:23 +08:00
PUMPFUN_PROGRAM_ID.to_string(), // Listen to pumpfun program ID
PUMPSWAP_PROGRAM_ID.to_string(), // Listen to pumpswap program ID
BONK_PROGRAM_ID.to_string(), // Listen to bonk program ID
RAYDIUM_CPMM_PROGRAM_ID.to_string(), // Listen to raydium_cpmm program ID
RAYDIUM_CLMM_PROGRAM_ID.to_string(), // Listen to raydium_clmm program ID
RAYDIUM_AMM_V4_PROGRAM_ID.to_string(), // Listen to raydium_amm_v4 program ID
METEORA_DAMM_V2_PROGRAM_ID.to_string(), // Listen to meteora_damm_v2 program ID
ORCA_WHIRLPOOL_PROGRAM_ID.to_string(), // Listen to orca_whirlpool program ID
METEORA_POOLS_PROGRAM_ID.to_string(), // Listen to meteora_pools program ID
METEORA_DLMM_PROGRAM_ID.to_string(), // Listen to meteora_dlmm program ID
];
let account_exclude = vec![];
let account_required = vec![];
// Listen to transaction data
let transaction_filter = TransactionFilter {
account_include: account_include.clone(),
account_exclude,
account_required,
};
// Listen to account data belonging to owner programs -> account event monitoring
let account_filter =
AccountFilter { account: vec![], owner: account_include.clone(), filters: vec![] };
// Event filtering. Set STREAMER_TRADES_ONLY=1 to keep only selected trade events.
let event_type_filter = if std::env::var("STREAMER_TRADES_ONLY").as_deref() == Ok("1") {
Some(EventTypeFilter::include_only(vec![
EventType::PumpFunBuy,
EventType::PumpFunSell,
EventType::PumpSwapBuy,
EventType::PumpSwapSell,
]))
} else {
None
};
println!("Starting to listen for events, press Ctrl+C to stop...");
2025-08-03 05:37:04 +08:00
println!("Monitoring programs: {:?}", account_include);
2025-08-03 05:37:04 +08:00
println!("Starting subscription...");
grpc.subscribe_events_immediate(
protocols,
None,
vec![transaction_filter],
vec![account_filter],
event_type_filter,
None,
callback,
)
.await?;
// Demo safety stop: stop automatically after 1000 seconds.
let grpc_clone = grpc.clone();
tokio::spawn(async move {
tokio::time::sleep(std::time::Duration::from_secs(1000)).await;
grpc_clone.stop().await;
});
println!("Waiting for Ctrl+C to stop...");
tokio::signal::ctrl_c().await?;
Ok(())
}
2025-01-02 19:44:38 +08:00
2025-10-12 22:00:15 +08:00
fn create_event_callback() -> impl Fn(DexEvent) {
|event: DexEvent| {
println!(
"🎉 Event received! Type: {:?}, tx_index: {:?}",
event.metadata().event_type,
event.metadata().tx_index
);
match event {
2025-10-12 22:00:15 +08:00
DexEvent::BlockMetaEvent(e) => {
println!("{:?}", e);
}
// .... other events
_ => {
println!("{:?}", event);
}
}
}
}