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,
},
},
DexEvent, Protocol,
},
grpc::ClientConfig,
yellowstone_grpc::{AccountFilter, TransactionFilter},
YellowstoneGrpc,
};
#[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>> {
println!("Subscribing to Yellowstone gRPC events...");
let mut config: ClientConfig = ClientConfig::default();
config.enable_metrics = std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1");
let grpc = YellowstoneGrpc::new_with_config(
"https://solana-yellowstone-grpc.publicnode.com:443".to_string(),
None,
config,
)?;
println!("GRPC client created successfully");
let callback = create_event_callback();
let protocols = vec![
Protocol::PumpFun,
Protocol::PumpSwap,
Protocol::Bonk,
Protocol::RaydiumCpmm,
Protocol::RaydiumClmm,
Protocol::RaydiumAmmV4,
Protocol::MeteoraDammV2,
Protocol::OrcaWhirlpool,
Protocol::MeteoraPools,
Protocol::MeteoraDlmm,
];
println!("Protocols to monitor: {:?}", protocols);
let account_include = vec![
PUMPFUN_PROGRAM_ID.to_string(), PUMPSWAP_PROGRAM_ID.to_string(), BONK_PROGRAM_ID.to_string(), RAYDIUM_CPMM_PROGRAM_ID.to_string(), RAYDIUM_CLMM_PROGRAM_ID.to_string(), RAYDIUM_AMM_V4_PROGRAM_ID.to_string(), METEORA_DAMM_V2_PROGRAM_ID.to_string(), ORCA_WHIRLPOOL_PROGRAM_ID.to_string(), METEORA_POOLS_PROGRAM_ID.to_string(), METEORA_DLMM_PROGRAM_ID.to_string(), ];
let account_exclude = vec![];
let account_required = vec![];
let transaction_filter = TransactionFilter {
account_include: account_include.clone(),
account_exclude,
account_required,
};
let account_filter =
AccountFilter { account: vec![], owner: account_include.clone(), filters: vec![] };
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...");
println!("Monitoring programs: {:?}", account_include);
println!("Starting subscription...");
grpc.subscribe_events_immediate(
protocols,
None,
vec![transaction_filter],
vec![account_filter],
event_type_filter,
None,
callback,
)
.await?;
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(())
}
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 {
DexEvent::BlockMetaEvent(e) => {
println!("{:?}", e);
}
_ => {
println!("{:?}", event);
}
}
}
}