sol_parser_sdk/core/events/
raw_instruction.rs1use super::EventMetadata;
3use serde::{Deserialize, Serialize};
4use solana_sdk::pubkey::Pubkey;
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct RawInstructionEvent {
8 pub metadata: EventMetadata,
9 #[serde(default)]
11 pub dexes: Vec<RawInstructionDex>,
12 pub program_id: Pubkey,
13 pub instruction_index: usize,
14 pub accounts: Vec<Option<Pubkey>>,
17 pub account_indices: Vec<u8>,
19 pub instruction_data: Vec<u8>,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
25pub enum RawInstructionDexType {
26 #[serde(rename = "pumpfun")]
27 PumpFun,
28 #[serde(rename = "pumpswap")]
29 PumpSwap,
30 #[serde(rename = "raydium_launchlab")]
31 RaydiumLaunchlab,
32 #[serde(rename = "raydium_cpmm")]
33 RaydiumCpmm,
34 #[serde(rename = "raydium_clmm")]
35 RaydiumClmm,
36 #[serde(rename = "raydium_amm_v4")]
37 RaydiumAmmV4,
38 #[serde(rename = "orca_whirlpool")]
39 OrcaWhirlpool,
40 #[serde(rename = "meteora_pools")]
41 MeteoraPools,
42 #[serde(rename = "meteora_damm_v2")]
43 MeteoraDammV2,
44 #[serde(rename = "meteora_dlmm")]
45 MeteoraDlmm,
46 #[serde(rename = "meteora_dbc")]
47 MeteoraDbc,
48}
49
50impl RawInstructionDexType {
51 pub const fn as_str(self) -> &'static str {
52 match self {
53 Self::PumpFun => "pumpfun",
54 Self::PumpSwap => "pumpswap",
55 Self::RaydiumLaunchlab => "raydium_launchlab",
56 Self::RaydiumCpmm => "raydium_cpmm",
57 Self::RaydiumClmm => "raydium_clmm",
58 Self::RaydiumAmmV4 => "raydium_amm_v4",
59 Self::OrcaWhirlpool => "orca_whirlpool",
60 Self::MeteoraPools => "meteora_pools",
61 Self::MeteoraDammV2 => "meteora_damm_v2",
62 Self::MeteoraDlmm => "meteora_dlmm",
63 Self::MeteoraDbc => "meteora_dbc",
64 }
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
72pub struct RawInstructionDex {
73 pub dex_type: RawInstructionDexType,
74 pub program_id: Pubkey,
75 pub pool: Option<Pubkey>,
76}
77
78pub fn raw_instruction_dexes(
79 program_id: Pubkey,
80 accounts: &[Option<Pubkey>],
81) -> Vec<RawInstructionDex> {
82 use crate::grpc::program_ids::*;
83 let known = [
84 (RawInstructionDexType::PumpFun, PUMPFUN_PROGRAM),
85 (RawInstructionDexType::PumpSwap, PUMPSWAP_PROGRAM),
86 (RawInstructionDexType::RaydiumLaunchlab, RAYDIUM_LAUNCHLAB_PROGRAM),
87 (RawInstructionDexType::RaydiumCpmm, RAYDIUM_CPMM_PROGRAM),
88 (RawInstructionDexType::RaydiumClmm, RAYDIUM_CLMM_PROGRAM),
89 (RawInstructionDexType::RaydiumAmmV4, RAYDIUM_AMM_V4_PROGRAM),
90 (RawInstructionDexType::OrcaWhirlpool, ORCA_WHIRLPOOL_PROGRAM),
91 (RawInstructionDexType::MeteoraPools, METEORA_POOLS_PROGRAM),
92 (RawInstructionDexType::MeteoraDammV2, METEORA_DAMM_V2_PROGRAM),
93 (RawInstructionDexType::MeteoraDlmm, METEORA_DLMM_PROGRAM),
94 (RawInstructionDexType::MeteoraDbc, METEORA_DBC_PROGRAM),
95 ];
96 known
97 .into_iter()
98 .filter(|(_, key)| program_id == *key || accounts.contains(&Some(*key)))
99 .map(|(name, key)| RawInstructionDex { dex_type: name, program_id: key, pool: None })
100 .collect()
101}
102
103pub fn raw_instruction_matches_filter(
104 dexes: &[RawInstructionDex],
105 filter: &crate::grpc::EventTypeFilter,
106) -> bool {
107 use crate::grpc::EventType;
108 if filter.exclude_types.as_ref().is_some_and(|types| types.contains(&EventType::RawInstruction))
109 {
110 return false;
111 }
112 if filter.include_only.as_ref().is_some_and(|types| types.contains(&EventType::RawInstruction))
113 {
114 return true;
115 }
116 if dexes.is_empty() {
117 return filter.include_only.is_none();
118 }
119 dexes.iter().any(|dex| {
120 let event = match dex.dex_type {
121 RawInstructionDexType::PumpFun => EventType::PumpFunTrade,
122 RawInstructionDexType::PumpSwap => EventType::PumpSwapTrade,
123 RawInstructionDexType::RaydiumLaunchlab => EventType::RaydiumLaunchlabTrade,
124 RawInstructionDexType::RaydiumCpmm => EventType::RaydiumCpmmSwap,
125 RawInstructionDexType::RaydiumClmm => EventType::RaydiumClmmSwap,
126 RawInstructionDexType::RaydiumAmmV4 => EventType::RaydiumAmmV4Swap,
127 RawInstructionDexType::OrcaWhirlpool => EventType::OrcaWhirlpoolSwap,
128 RawInstructionDexType::MeteoraPools => EventType::MeteoraPoolsSwap,
129 RawInstructionDexType::MeteoraDammV2 => EventType::MeteoraDammV2Swap,
130 RawInstructionDexType::MeteoraDlmm => EventType::MeteoraDlmmSwap,
131 RawInstructionDexType::MeteoraDbc => EventType::MeteoraDbcSwap,
132 };
133 filter.should_include(event)
134 })
135}
136
137#[cfg(test)]
138mod enum_tests {
139 use super::*;
140 #[test]
141 fn dex_identifiers_round_trip_without_changing_json() {
142 for (kind, value) in [
143 (RawInstructionDexType::PumpFun, "pumpfun"),
144 (RawInstructionDexType::PumpSwap, "pumpswap"),
145 (RawInstructionDexType::RaydiumLaunchlab, "raydium_launchlab"),
146 (RawInstructionDexType::RaydiumCpmm, "raydium_cpmm"),
147 (RawInstructionDexType::RaydiumClmm, "raydium_clmm"),
148 (RawInstructionDexType::RaydiumAmmV4, "raydium_amm_v4"),
149 (RawInstructionDexType::OrcaWhirlpool, "orca_whirlpool"),
150 (RawInstructionDexType::MeteoraPools, "meteora_pools"),
151 (RawInstructionDexType::MeteoraDammV2, "meteora_damm_v2"),
152 (RawInstructionDexType::MeteoraDlmm, "meteora_dlmm"),
153 (RawInstructionDexType::MeteoraDbc, "meteora_dbc"),
154 ] {
155 assert_eq!(serde_json::to_value(kind).unwrap(), value);
156 assert_eq!(
157 serde_json::from_value::<RawInstructionDexType>(serde_json::json!(value)).unwrap(),
158 kind
159 );
160 }
161 assert!(serde_json::from_str::<RawInstructionDexType>("\"typo\"").is_err());
162 }
163}