sol_parser_sdk/core/events/
raw_instruction.rs1use super::EventMetadata;
3use serde::{Deserialize, Serialize};
4use solana_sdk::pubkey::Pubkey;
5
6#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
9pub struct RawInstructionPayload {
10 pub program_id: Pubkey,
11 pub instruction_index: usize,
12 pub accounts: Vec<Option<Pubkey>>,
13 pub account_indices: Vec<u8>,
14 pub instruction_data: Vec<u8>,
15}
16
17impl RawInstructionPayload {
18 pub fn with_metadata(&self, metadata: EventMetadata) -> RawInstructionEvent {
20 RawInstructionEvent {
21 metadata,
22 dexes: raw_instruction_dexes(self.program_id, &self.accounts),
23 program_id: self.program_id,
24 instruction_index: self.instruction_index,
25 accounts: self.accounts.clone(),
26 account_indices: self.account_indices.clone(),
27 instruction_data: self.instruction_data.clone(),
28 }
29 }
30}
31
32impl From<&RawInstructionEvent> for RawInstructionPayload {
33 fn from(raw: &RawInstructionEvent) -> Self {
34 Self {
35 program_id: raw.program_id,
36 instruction_index: raw.instruction_index,
37 accounts: raw.accounts.clone(),
38 account_indices: raw.account_indices.clone(),
39 instruction_data: raw.instruction_data.clone(),
40 }
41 }
42}
43
44#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
46pub enum TradeParseStatus {
47 Unresolved,
49 #[default]
51 InstructionDecoded,
52 ExecutionConfirmed,
55}
56
57pub type PumpFunParseStatus = TradeParseStatus;
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct RawInstructionEvent {
62 pub metadata: EventMetadata,
63 #[serde(default)]
65 pub dexes: Vec<RawInstructionDex>,
66 pub program_id: Pubkey,
67 pub instruction_index: usize,
68 pub accounts: Vec<Option<Pubkey>>,
71 pub account_indices: Vec<u8>,
73 pub instruction_data: Vec<u8>,
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
79pub enum RawInstructionDexType {
80 #[serde(rename = "pumpfun")]
81 PumpFun,
82 #[serde(rename = "pumpswap")]
83 PumpSwap,
84 #[serde(rename = "raydium_launchlab")]
85 RaydiumLaunchlab,
86 #[serde(rename = "raydium_cpmm")]
87 RaydiumCpmm,
88 #[serde(rename = "raydium_clmm")]
89 RaydiumClmm,
90 #[serde(rename = "raydium_amm_v4")]
91 RaydiumAmmV4,
92 #[serde(rename = "orca_whirlpool")]
93 OrcaWhirlpool,
94 #[serde(rename = "meteora_pools")]
95 MeteoraPools,
96 #[serde(rename = "meteora_damm_v2")]
97 MeteoraDammV2,
98 #[serde(rename = "meteora_dlmm")]
99 MeteoraDlmm,
100 #[serde(rename = "meteora_dbc")]
101 MeteoraDbc,
102}
103
104impl RawInstructionDexType {
105 pub const fn as_str(self) -> &'static str {
106 match self {
107 Self::PumpFun => "pumpfun",
108 Self::PumpSwap => "pumpswap",
109 Self::RaydiumLaunchlab => "raydium_launchlab",
110 Self::RaydiumCpmm => "raydium_cpmm",
111 Self::RaydiumClmm => "raydium_clmm",
112 Self::RaydiumAmmV4 => "raydium_amm_v4",
113 Self::OrcaWhirlpool => "orca_whirlpool",
114 Self::MeteoraPools => "meteora_pools",
115 Self::MeteoraDammV2 => "meteora_damm_v2",
116 Self::MeteoraDlmm => "meteora_dlmm",
117 Self::MeteoraDbc => "meteora_dbc",
118 }
119 }
120}
121
122#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
126pub struct RawInstructionDex {
127 pub dex_type: RawInstructionDexType,
128 pub program_id: Pubkey,
129 pub pool: Option<Pubkey>,
130}
131
132pub fn raw_instruction_dexes(
133 program_id: Pubkey,
134 accounts: &[Option<Pubkey>],
135) -> Vec<RawInstructionDex> {
136 use crate::grpc::program_ids::*;
137 let known = [
138 (RawInstructionDexType::PumpFun, PUMPFUN_PROGRAM),
139 (RawInstructionDexType::PumpSwap, PUMPSWAP_PROGRAM),
140 (RawInstructionDexType::RaydiumLaunchlab, RAYDIUM_LAUNCHLAB_PROGRAM),
141 (RawInstructionDexType::RaydiumCpmm, RAYDIUM_CPMM_PROGRAM),
142 (RawInstructionDexType::RaydiumClmm, RAYDIUM_CLMM_PROGRAM),
143 (RawInstructionDexType::RaydiumAmmV4, RAYDIUM_AMM_V4_PROGRAM),
144 (RawInstructionDexType::OrcaWhirlpool, ORCA_WHIRLPOOL_PROGRAM),
145 (RawInstructionDexType::MeteoraPools, METEORA_POOLS_PROGRAM),
146 (RawInstructionDexType::MeteoraDammV2, METEORA_DAMM_V2_PROGRAM),
147 (RawInstructionDexType::MeteoraDlmm, METEORA_DLMM_PROGRAM),
148 (RawInstructionDexType::MeteoraDbc, METEORA_DBC_PROGRAM),
149 ];
150 known
151 .into_iter()
152 .filter(|(_, key)| program_id == *key || accounts.contains(&Some(*key)))
153 .map(|(name, key)| RawInstructionDex { dex_type: name, program_id: key, pool: None })
154 .collect()
155}
156
157pub fn raw_instruction_matches_filter(
158 dexes: &[RawInstructionDex],
159 filter: &crate::grpc::EventTypeFilter,
160) -> bool {
161 use crate::grpc::EventType;
162 if filter.exclude_types.as_ref().is_some_and(|types| types.contains(&EventType::RawInstruction))
163 {
164 return false;
165 }
166 if filter.include_only.as_ref().is_some_and(|types| types.contains(&EventType::RawInstruction))
167 {
168 return true;
169 }
170 if dexes.is_empty() {
171 return filter.include_only.is_none();
172 }
173 dexes.iter().any(|dex| {
174 let event = match dex.dex_type {
175 RawInstructionDexType::PumpFun => EventType::PumpFunTrade,
176 RawInstructionDexType::PumpSwap => EventType::PumpSwapTrade,
177 RawInstructionDexType::RaydiumLaunchlab => EventType::RaydiumLaunchlabTrade,
178 RawInstructionDexType::RaydiumCpmm => EventType::RaydiumCpmmSwap,
179 RawInstructionDexType::RaydiumClmm => EventType::RaydiumClmmSwap,
180 RawInstructionDexType::RaydiumAmmV4 => EventType::RaydiumAmmV4Swap,
181 RawInstructionDexType::OrcaWhirlpool => EventType::OrcaWhirlpoolSwap,
182 RawInstructionDexType::MeteoraPools => EventType::MeteoraPoolsSwap,
183 RawInstructionDexType::MeteoraDammV2 => EventType::MeteoraDammV2Swap,
184 RawInstructionDexType::MeteoraDlmm => EventType::MeteoraDlmmSwap,
185 RawInstructionDexType::MeteoraDbc => EventType::MeteoraDbcSwap,
186 };
187 filter.should_include(event)
188 })
189}
190
191#[cfg(test)]
192mod enum_tests {
193 use super::*;
194 #[test]
195 fn dex_identifiers_round_trip_without_changing_json() {
196 for (kind, value) in [
197 (RawInstructionDexType::PumpFun, "pumpfun"),
198 (RawInstructionDexType::PumpSwap, "pumpswap"),
199 (RawInstructionDexType::RaydiumLaunchlab, "raydium_launchlab"),
200 (RawInstructionDexType::RaydiumCpmm, "raydium_cpmm"),
201 (RawInstructionDexType::RaydiumClmm, "raydium_clmm"),
202 (RawInstructionDexType::RaydiumAmmV4, "raydium_amm_v4"),
203 (RawInstructionDexType::OrcaWhirlpool, "orca_whirlpool"),
204 (RawInstructionDexType::MeteoraPools, "meteora_pools"),
205 (RawInstructionDexType::MeteoraDammV2, "meteora_damm_v2"),
206 (RawInstructionDexType::MeteoraDlmm, "meteora_dlmm"),
207 (RawInstructionDexType::MeteoraDbc, "meteora_dbc"),
208 ] {
209 assert_eq!(serde_json::to_value(kind).unwrap(), value);
210 assert_eq!(
211 serde_json::from_value::<RawInstructionDexType>(serde_json::json!(value)).unwrap(),
212 kind
213 );
214 }
215 assert!(serde_json::from_str::<RawInstructionDexType>("\"typo\"").is_err());
216 }
217}