Skip to main content

sol_parser_sdk/instr/
pump_fees.rs

1//! Pump Fees(`pfeeUx...`)外层指令:`idls/pump_fees.json`。Shred/gRPC 共用账户索引语义。
2
3use 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),  // event_authority
233            pk(2),  // program
234            pk(3),  // authority
235            pk(4),  // global
236            pk(5),  // mint
237            pk(6),  // sharing_config
238            pk(7),  // bonding_curve
239            pk(8),  // pump_creator_vault
240            pk(9),  // pump_creator_vault_ata (v2) / system_program (v1)
241            pk(10), // system_program (v2) / pump_program (v1)
242        ]
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}