1use solana_sdk::pubkey::Pubkey;
4use solana_sdk::signature::Signature;
5
6use crate::core::events::*;
7use crate::logs::pump_fees::{read_fee_tiers_vec, read_fees_at, read_shareholders_vec};
8
9pub(crate) const CREATE_FEE_SHARING_IX: [u8; 8] = [195, 78, 86, 76, 111, 52, 251, 213];
10pub(crate) const INITIALIZE_FEE_CONFIG_IX: [u8; 8] = [62, 162, 20, 133, 121, 65, 145, 27];
11pub(crate) const RESET_FEE_SHARING_IX: [u8; 8] = [10, 2, 182, 95, 16, 127, 129, 186];
12pub(crate) const REVOKE_FEE_SHARING_IX: [u8; 8] = [18, 233, 158, 39, 185, 207, 58, 104];
13pub(crate) const TRANSFER_FEE_SHARING_IX: [u8; 8] = [202, 10, 75, 200, 164, 34, 210, 96];
14pub(crate) const UPDATE_ADMIN_IX: [u8; 8] = [161, 176, 40, 213, 60, 184, 179, 228];
15pub(crate) const UPDATE_FEE_CONFIG_IX: [u8; 8] = [104, 184, 103, 242, 88, 151, 107, 20];
16pub(crate) const UPDATE_FEE_SHARES_IX: [u8; 8] = [189, 13, 136, 99, 187, 164, 237, 35];
17pub(crate) const UPDATE_FEE_SHARES_V2_IX: [u8; 8] = [111, 251, 49, 6, 78, 78, 106, 18];
18pub(crate) const UPSERT_FEE_TIERS_IX: [u8; 8] = [227, 23, 150, 12, 77, 86, 94, 4];
19
20#[inline(always)]
21fn disc8(data: &[u8]) -> Option<[u8; 8]> {
22 data.get(..8)?.try_into().ok()
23}
24
25#[inline(always)]
26fn metadata(
27 signature: Signature,
28 slot: u64,
29 tx_index: u64,
30 block_time_us: Option<i64>,
31 grpc_recv_us: i64,
32) -> EventMetadata {
33 EventMetadata {
34 signature,
35 slot,
36 tx_index,
37 block_time_us: block_time_us.unwrap_or(0),
38 grpc_recv_us,
39 recent_blockhash: None,
40 }
41}
42
43#[inline(always)]
44pub fn parse_instruction(
45 instruction_data: &[u8],
46 accounts: &[Pubkey],
47 signature: Signature,
48 slot: u64,
49 tx_index: u64,
50 block_time_us: Option<i64>,
51 grpc_recv_us: i64,
52) -> Option<DexEvent> {
53 let md = metadata(signature, slot, tx_index, block_time_us, grpc_recv_us);
54 let disc = disc8(instruction_data)?;
55
56 if disc == CREATE_FEE_SHARING_IX {
57 let payer = *accounts.get(2)?;
58 let mint = *accounts.get(4)?;
59 let sharing_config = accounts.get(5).copied().unwrap_or_default();
60 let bonding_curve = accounts.get(7).copied().unwrap_or_default();
61 let pool = accounts.get(10).copied();
62 return Some(DexEvent::PumpFeesCreateFeeSharingConfig(
63 PumpFeesCreateFeeSharingConfigEvent {
64 metadata: md,
65 timestamp: 0,
66 mint,
67 bonding_curve,
68 pool,
69 sharing_config,
70 admin: payer,
71 initial_shareholders: Vec::new(),
72 status: PumpFeesConfigStatus::Active,
73 },
74 ));
75 }
76
77 if disc == UPDATE_FEE_SHARES_IX || disc == UPDATE_FEE_SHARES_V2_IX {
78 if accounts.len() < 8 || instruction_data.len() < 8 {
79 return None;
80 }
81 let authority = *accounts.get(2)?;
82 let mint = *accounts.get(4)?;
83 let sharing_config = *accounts.get(5)?;
84 let bonding_curve = accounts.get(6).copied().unwrap_or_default();
85 let pump_creator_vault = accounts.get(7).copied().unwrap_or_default();
86 let mut o = 8usize;
87 let new_shareholders = read_shareholders_vec(instruction_data, &mut o)?;
88 if o != instruction_data.len() {
89 return None;
90 }
91 return Some(DexEvent::PumpFeesUpdateFeeShares(PumpFeesUpdateFeeSharesEvent {
92 metadata: md,
93 timestamp: 0,
94 mint,
95 sharing_config,
96 admin: authority,
97 bonding_curve,
98 pump_creator_vault,
99 new_shareholders,
100 }));
101 }
102
103 if disc == INITIALIZE_FEE_CONFIG_IX {
104 let admin = *accounts.get(0)?;
105 let fee_config = *accounts.get(1)?;
106 return Some(DexEvent::PumpFeesInitializeFeeConfig(PumpFeesInitializeFeeConfigEvent {
107 metadata: md,
108 timestamp: 0,
109 admin,
110 fee_config,
111 }));
112 }
113
114 if disc == RESET_FEE_SHARING_IX {
115 let old_admin = *accounts.get(0)?;
116 let new_admin = *accounts.get(2)?;
117 let mint = *accounts.get(3)?;
118 let sharing_config = *accounts.get(4)?;
119 return Some(DexEvent::PumpFeesResetFeeSharingConfig(PumpFeesResetFeeSharingConfigEvent {
120 metadata: md,
121 timestamp: 0,
122 mint,
123 sharing_config,
124 old_admin,
125 old_shareholders: Vec::new(),
126 new_admin,
127 new_shareholders: Vec::new(),
128 }));
129 }
130
131 if disc == REVOKE_FEE_SHARING_IX {
132 let admin = *accounts.get(0)?;
133 let mint = *accounts.get(2)?;
134 let sharing_config = *accounts.get(3)?;
135 return Some(DexEvent::PumpFeesRevokeFeeSharingAuthority(
136 PumpFeesRevokeFeeSharingAuthorityEvent {
137 metadata: md,
138 timestamp: 0,
139 mint,
140 sharing_config,
141 admin,
142 },
143 ));
144 }
145
146 if disc == TRANSFER_FEE_SHARING_IX {
147 let old_admin = *accounts.get(0)?;
148 let mint = *accounts.get(2)?;
149 let sharing_config = *accounts.get(3)?;
150 let new_admin = *accounts.get(4)?;
151 return Some(DexEvent::PumpFeesTransferFeeSharingAuthority(
152 PumpFeesTransferFeeSharingAuthorityEvent {
153 metadata: md,
154 timestamp: 0,
155 mint,
156 sharing_config,
157 old_admin,
158 new_admin,
159 },
160 ));
161 }
162
163 if disc == UPDATE_ADMIN_IX {
164 let old_admin = *accounts.get(0)?;
165 let new_admin = *accounts.get(2)?;
166 return Some(DexEvent::PumpFeesUpdateAdmin(PumpFeesUpdateAdminEvent {
167 metadata: md,
168 timestamp: 0,
169 old_admin,
170 new_admin,
171 }));
172 }
173
174 if disc == UPDATE_FEE_CONFIG_IX {
175 let fee_config = *accounts.get(0)?;
176 let admin = *accounts.get(1)?;
177 if instruction_data.len() < 8 {
178 return None;
179 }
180 let mut o = 8usize;
181 let fee_tiers = read_fee_tiers_vec(instruction_data, &mut o)?;
182 let flat_fees = read_fees_at(instruction_data, &mut o)?;
183 if o != instruction_data.len() {
184 return None;
185 }
186 return Some(DexEvent::PumpFeesUpdateFeeConfig(PumpFeesUpdateFeeConfigEvent {
187 metadata: md,
188 timestamp: 0,
189 admin,
190 fee_config,
191 fee_tiers,
192 flat_fees,
193 }));
194 }
195
196 if disc == UPSERT_FEE_TIERS_IX {
197 let fee_config = *accounts.get(0)?;
198 let admin = *accounts.get(1)?;
199 if instruction_data.len() < 8 {
200 return None;
201 }
202 let mut o = 8usize;
203 let fee_tiers = read_fee_tiers_vec(instruction_data, &mut o)?;
204 let offset = *instruction_data.get(o)?;
205 o += 1;
206 if o != instruction_data.len() {
207 return None;
208 }
209 return Some(DexEvent::PumpFeesUpsertFeeTiers(PumpFeesUpsertFeeTiersEvent {
210 metadata: md,
211 timestamp: 0,
212 admin,
213 fee_config,
214 fee_tiers,
215 offset,
216 }));
217 }
218
219 None
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225
226 fn pk(byte: u8) -> Pubkey {
227 Pubkey::new_from_array([byte; 32])
228 }
229
230 fn accounts() -> Vec<Pubkey> {
231 vec![
232 pk(1), pk(2), pk(3), pk(4), pk(5), pk(6), pk(7), pk(8), pk(9), pk(10), ]
243 }
244
245 fn update_fee_shares_data(disc: [u8; 8]) -> Vec<u8> {
246 let mut data = disc.to_vec();
247 data.extend_from_slice(&1u32.to_le_bytes());
248 data.extend_from_slice(&pk(42).to_bytes());
249 data.extend_from_slice(&2500u16.to_le_bytes());
250 data
251 }
252
253 fn parse_update_fee_shares(disc: [u8; 8]) -> PumpFeesUpdateFeeSharesEvent {
254 let event = parse_instruction(
255 &update_fee_shares_data(disc),
256 &accounts(),
257 Signature::default(),
258 1,
259 0,
260 None,
261 99,
262 )
263 .expect("update_fee_shares event");
264
265 match event {
266 DexEvent::PumpFeesUpdateFeeShares(e) => e,
267 other => panic!("expected PumpFeesUpdateFeeShares, got {other:?}"),
268 }
269 }
270
271 #[test]
272 fn parses_update_fee_shares_v1_ix_vault() {
273 let event = parse_update_fee_shares(UPDATE_FEE_SHARES_IX);
274 assert_eq!(event.mint, pk(5));
275 assert_eq!(event.sharing_config, pk(6));
276 assert_eq!(event.admin, pk(3));
277 assert_eq!(event.bonding_curve, pk(7));
278 assert_eq!(event.pump_creator_vault, pk(8));
279 assert_eq!(event.new_shareholders[0].address, pk(42));
280 assert_eq!(event.new_shareholders[0].share_bps, 2500);
281 }
282
283 #[test]
284 fn parses_update_fee_shares_v2_ix_vault() {
285 let event = parse_update_fee_shares(UPDATE_FEE_SHARES_V2_IX);
286 assert_eq!(event.mint, pk(5));
287 assert_eq!(event.sharing_config, pk(6));
288 assert_eq!(event.admin, pk(3));
289 assert_eq!(event.bonding_curve, pk(7));
290 assert_eq!(event.pump_creator_vault, pk(8));
291 assert_eq!(event.new_shareholders[0].address, pk(42));
292 assert_eq!(event.new_shareholders[0].share_bps, 2500);
293 }
294}