Skip to main content

sol_parser_sdk/grpc/
program_ids.rs

1use crate::grpc::types::Protocol;
2use solana_sdk::pubkey;
3use solana_sdk::pubkey::Pubkey;
4use std::collections::HashMap;
5
6// Program IDs for supported DEX protocols (string format)
7pub const PUMPFUN_PROGRAM_ID: &str = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
8pub const PUMPSWAP_PROGRAM_ID: &str = "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA";
9pub const PUMPSWAP_FEES_PROGRAM_ID: &str = "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ";
10pub const RAYDIUM_LAUNCHLAB_PROGRAM_ID: &str = "LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj";
11pub const RAYDIUM_CPMM_PROGRAM_ID: &str = "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C";
12pub const RAYDIUM_CLMM_PROGRAM_ID: &str = "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK";
13pub const RAYDIUM_AMM_V4_PROGRAM_ID: &str = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8";
14pub const ORCA_WHIRLPOOL_PROGRAM_ID: &str = "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc";
15pub const METEORA_POOLS_PROGRAM_ID: &str = "Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB";
16pub const METEORA_DAMM_V2_PROGRAM_ID: &str = "cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG";
17pub const METEORA_DLMM_PROGRAM_ID: &str = "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo";
18pub const METEORA_DBC_PROGRAM_ID: &str = "dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN";
19
20// Program IDs (Pubkey format for matching)
21pub const PUMPFUN_PROGRAM: Pubkey = pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P");
22pub const PUMPSWAP_PROGRAM: Pubkey = pubkey!("pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA");
23pub const PUMPSWAP_FEES_PROGRAM: Pubkey = pubkey!("pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ");
24pub const RAYDIUM_LAUNCHLAB_PROGRAM: Pubkey =
25    pubkey!("LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj");
26pub const RAYDIUM_CPMM_PROGRAM: Pubkey = pubkey!("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C");
27pub const RAYDIUM_CLMM_PROGRAM: Pubkey = pubkey!("CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK");
28pub const RAYDIUM_AMM_V4_PROGRAM: Pubkey = pubkey!("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8");
29pub const ORCA_WHIRLPOOL_PROGRAM: Pubkey = pubkey!("whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc");
30pub const METEORA_POOLS_PROGRAM: Pubkey = pubkey!("Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB");
31pub const METEORA_DAMM_V2_PROGRAM: Pubkey = pubkey!("cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG");
32pub const METEORA_DLMM_PROGRAM: Pubkey = pubkey!("LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo");
33pub const METEORA_DBC_PROGRAM: Pubkey = pubkey!("dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN");
34
35/// Avoid base58 decoding for program ids emitted by the DEXes this crate parses.
36#[inline(always)]
37pub(crate) fn known_program_id(program_id: &str) -> Option<Pubkey> {
38    match program_id {
39        PUMPFUN_PROGRAM_ID => Some(PUMPFUN_PROGRAM),
40        PUMPSWAP_PROGRAM_ID => Some(PUMPSWAP_PROGRAM),
41        PUMPSWAP_FEES_PROGRAM_ID => Some(PUMPSWAP_FEES_PROGRAM),
42        RAYDIUM_LAUNCHLAB_PROGRAM_ID => Some(RAYDIUM_LAUNCHLAB_PROGRAM),
43        RAYDIUM_CPMM_PROGRAM_ID => Some(RAYDIUM_CPMM_PROGRAM),
44        RAYDIUM_CLMM_PROGRAM_ID => Some(RAYDIUM_CLMM_PROGRAM),
45        RAYDIUM_AMM_V4_PROGRAM_ID => Some(RAYDIUM_AMM_V4_PROGRAM),
46        ORCA_WHIRLPOOL_PROGRAM_ID => Some(ORCA_WHIRLPOOL_PROGRAM),
47        METEORA_POOLS_PROGRAM_ID => Some(METEORA_POOLS_PROGRAM),
48        METEORA_DAMM_V2_PROGRAM_ID => Some(METEORA_DAMM_V2_PROGRAM),
49        METEORA_DLMM_PROGRAM_ID => Some(METEORA_DLMM_PROGRAM),
50        METEORA_DBC_PROGRAM_ID => Some(METEORA_DBC_PROGRAM),
51        _ => None,
52    }
53}
54
55/// Programs whose instruction positions are queried later by account/data fillers.
56#[inline(always)]
57pub(crate) fn needs_invoke_context(program_id: &Pubkey) -> bool {
58    matches!(
59        *program_id,
60        PUMPFUN_PROGRAM
61            | PUMPSWAP_PROGRAM
62            | PUMPSWAP_FEES_PROGRAM
63            | RAYDIUM_LAUNCHLAB_PROGRAM
64            | RAYDIUM_CPMM_PROGRAM
65            | RAYDIUM_CLMM_PROGRAM
66            | RAYDIUM_AMM_V4_PROGRAM
67            | ORCA_WHIRLPOOL_PROGRAM
68            | METEORA_POOLS_PROGRAM
69            | METEORA_DAMM_V2_PROGRAM
70            | METEORA_DLMM_PROGRAM
71    )
72}
73
74lazy_static::lazy_static! {
75    pub static ref PROTOCOL_PROGRAM_IDS: HashMap<Protocol, Vec<&'static str>> = {
76        let mut map = HashMap::new();
77        map.insert(Protocol::PumpFun, vec![PUMPFUN_PROGRAM_ID]);
78        map.insert(Protocol::PumpSwap, vec![PUMPSWAP_PROGRAM_ID]);
79        map.insert(Protocol::PumpFees, vec![PUMPSWAP_FEES_PROGRAM_ID]);
80        map.insert(Protocol::RaydiumLaunchlab, vec![RAYDIUM_LAUNCHLAB_PROGRAM_ID]);
81        map.insert(Protocol::RaydiumCpmm, vec![RAYDIUM_CPMM_PROGRAM_ID]);
82        map.insert(Protocol::RaydiumClmm, vec![RAYDIUM_CLMM_PROGRAM_ID]);
83        map.insert(Protocol::RaydiumAmmV4, vec![RAYDIUM_AMM_V4_PROGRAM_ID]);
84        map.insert(Protocol::OrcaWhirlpool, vec![ORCA_WHIRLPOOL_PROGRAM_ID]);
85        map.insert(Protocol::MeteoraPools, vec![METEORA_POOLS_PROGRAM_ID]);
86        map.insert(Protocol::MeteoraDammV2, vec![METEORA_DAMM_V2_PROGRAM_ID]);
87        map.insert(Protocol::MeteoraDlmm, vec![METEORA_DLMM_PROGRAM_ID]);
88        map.insert(Protocol::MeteoraDbc, vec![METEORA_DBC_PROGRAM_ID]);
89        map
90    };
91}
92
93pub fn get_program_ids_for_protocols(protocols: &[Protocol]) -> Vec<String> {
94    let mut program_ids = Vec::new();
95    for protocol in protocols {
96        if let Some(ids) = PROTOCOL_PROGRAM_IDS.get(protocol) {
97            for id in ids {
98                program_ids.push(id.to_string());
99            }
100        }
101    }
102    program_ids.sort();
103    program_ids.dedup();
104    program_ids
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110    use crate::instr;
111
112    #[test]
113    fn grpc_program_ids_match_instruction_program_ids() {
114        assert_eq!(PUMPFUN_PROGRAM, instr::program_ids::PUMPFUN_PROGRAM_ID);
115        assert_eq!(PUMPSWAP_PROGRAM, instr::program_ids::PUMPSWAP_PROGRAM_ID);
116        assert_eq!(PUMPSWAP_FEES_PROGRAM, instr::program_ids::PUMP_FEES_PROGRAM_ID);
117        assert_eq!(RAYDIUM_LAUNCHLAB_PROGRAM, instr::program_ids::RAYDIUM_LAUNCHLAB_PROGRAM_ID);
118        assert_eq!(RAYDIUM_CPMM_PROGRAM, instr::program_ids::RAYDIUM_CPMM_PROGRAM_ID);
119        assert_eq!(RAYDIUM_CLMM_PROGRAM, instr::program_ids::RAYDIUM_CLMM_PROGRAM_ID);
120        assert_eq!(RAYDIUM_AMM_V4_PROGRAM, instr::program_ids::RAYDIUM_AMM_V4_PROGRAM_ID);
121        assert_eq!(ORCA_WHIRLPOOL_PROGRAM, instr::program_ids::ORCA_WHIRLPOOL_PROGRAM_ID);
122        assert_eq!(METEORA_POOLS_PROGRAM, instr::program_ids::METEORA_POOLS_PROGRAM_ID);
123        assert_eq!(METEORA_DAMM_V2_PROGRAM, instr::program_ids::METEORA_DAMM_V2_PROGRAM_ID);
124        assert_eq!(METEORA_DLMM_PROGRAM, instr::program_ids::METEORA_DLMM_PROGRAM_ID);
125        assert_eq!(METEORA_DBC_PROGRAM, instr::program_ids::METEORA_DBC_PROGRAM_ID);
126    }
127
128    #[test]
129    fn protocol_filter_maps_all_supported_protocols() {
130        let protocols = [
131            Protocol::PumpFun,
132            Protocol::PumpSwap,
133            Protocol::PumpFees,
134            Protocol::RaydiumLaunchlab,
135            Protocol::RaydiumCpmm,
136            Protocol::RaydiumClmm,
137            Protocol::RaydiumAmmV4,
138            Protocol::OrcaWhirlpool,
139            Protocol::MeteoraPools,
140            Protocol::MeteoraDammV2,
141            Protocol::MeteoraDlmm,
142            Protocol::MeteoraDbc,
143        ];
144        for protocol in protocols {
145            assert!(
146                PROTOCOL_PROGRAM_IDS.contains_key(&protocol),
147                "missing program id mapping for {protocol:?}"
148            );
149        }
150    }
151
152    #[test]
153    fn invoke_context_only_tracks_programs_used_by_fillers() {
154        for program_id in [
155            PUMPFUN_PROGRAM,
156            PUMPSWAP_PROGRAM,
157            PUMPSWAP_FEES_PROGRAM,
158            RAYDIUM_LAUNCHLAB_PROGRAM,
159            RAYDIUM_CPMM_PROGRAM,
160            RAYDIUM_CLMM_PROGRAM,
161            RAYDIUM_AMM_V4_PROGRAM,
162            ORCA_WHIRLPOOL_PROGRAM,
163            METEORA_POOLS_PROGRAM,
164            METEORA_DAMM_V2_PROGRAM,
165            METEORA_DLMM_PROGRAM,
166        ] {
167            assert!(needs_invoke_context(&program_id));
168        }
169        assert!(!needs_invoke_context(&Pubkey::new_unique()));
170    }
171
172    #[test]
173    fn known_log_program_ids_map_without_decoding() {
174        for (encoded, expected) in [
175            (PUMPFUN_PROGRAM_ID, PUMPFUN_PROGRAM),
176            (PUMPSWAP_PROGRAM_ID, PUMPSWAP_PROGRAM),
177            (PUMPSWAP_FEES_PROGRAM_ID, PUMPSWAP_FEES_PROGRAM),
178            (RAYDIUM_LAUNCHLAB_PROGRAM_ID, RAYDIUM_LAUNCHLAB_PROGRAM),
179            (RAYDIUM_CPMM_PROGRAM_ID, RAYDIUM_CPMM_PROGRAM),
180            (RAYDIUM_CLMM_PROGRAM_ID, RAYDIUM_CLMM_PROGRAM),
181            (RAYDIUM_AMM_V4_PROGRAM_ID, RAYDIUM_AMM_V4_PROGRAM),
182            (ORCA_WHIRLPOOL_PROGRAM_ID, ORCA_WHIRLPOOL_PROGRAM),
183            (METEORA_POOLS_PROGRAM_ID, METEORA_POOLS_PROGRAM),
184            (METEORA_DAMM_V2_PROGRAM_ID, METEORA_DAMM_V2_PROGRAM),
185            (METEORA_DLMM_PROGRAM_ID, METEORA_DLMM_PROGRAM),
186            (METEORA_DBC_PROGRAM_ID, METEORA_DBC_PROGRAM),
187        ] {
188            assert_eq!(known_program_id(encoded), Some(expected));
189        }
190        assert_eq!(known_program_id("11111111111111111111111111111111"), None);
191    }
192}