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