parser_proxy_ws/
config.rs

1use anyhow::{Context, Result};
2use serde::{Deserialize, Serialize};
3use std::fs;
4use std::path::Path;
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct Config {
8    pub server: ServerConfig,
9    pub grpc: GrpcConfig,
10    pub protocols: ProtocolsConfig,
11    pub events: EventsConfig,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct ServerConfig {
16    pub host: String,
17    pub port: u16,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct GrpcConfig {
22    pub endpoint: String,
23    pub token: Option<String>,
24    pub enable_metrics: bool,
25    pub enable_tls: bool,
26    pub connection_timeout_ms: u64,
27    pub request_timeout_ms: u64,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct ProtocolsConfig {
32    pub pumpfun: bool,
33    pub pumpswap: bool,
34    pub bonk: bool,
35    pub raydium_amm_v4: bool,
36    pub raydium_clmm: bool,
37    pub raydium_cpmm: bool,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct EventsConfig {
42    pub block_meta: bool,
43    pub bonk_trade: bool,
44    pub bonk_pool_create: bool,
45    pub bonk_migrate_amm: bool,
46    pub pumpfun_trade: bool,
47    pub pumpfun_create: bool,
48    pub pumpfun_complete: bool,
49    pub pumpfun_migrate: bool,
50    pub pumpswap_buy: bool,
51    pub pumpswap_sell: bool,
52    pub pumpswap_create_pool: bool,
53    pub pumpswap_pool_created: bool,
54    pub pumpswap_trade: bool,
55    pub pumpswap_liquidity_added: bool,
56    pub pumpswap_liquidity_removed: bool,
57    pub pumpswap_pool_updated: bool,
58    pub pumpswap_fees_claimed: bool,
59    pub raydium_cpmm_swap: bool,
60    pub raydium_cpmm_deposit: bool,
61    pub raydium_cpmm_withdraw: bool,
62    pub raydium_cpmm_initialize: bool,
63    pub raydium_clmm_swap: bool,
64    pub raydium_clmm_create_pool: bool,
65    pub raydium_clmm_open_position: bool,
66    pub raydium_clmm_close_position: bool,
67    pub raydium_clmm_increase_liquidity: bool,
68    pub raydium_clmm_decrease_liquidity: bool,
69    pub raydium_clmm_open_position_with_token_ext_nft: bool,
70    pub raydium_clmm_collect_fee: bool,
71    pub raydium_amm_v4_swap: bool,
72    pub raydium_amm_v4_deposit: bool,
73    pub raydium_amm_v4_withdraw: bool,
74    pub raydium_amm_v4_initialize2: bool,
75    pub raydium_amm_v4_withdraw_pnl: bool,
76    pub orca_whirlpool_swap: bool,
77    pub orca_whirlpool_liquidity_increased: bool,
78    pub orca_whirlpool_liquidity_decreased: bool,
79    pub orca_whirlpool_pool_initialized: bool,
80    pub meteora_pools_swap: bool,
81    pub meteora_pools_add_liquidity: bool,
82    pub meteora_pools_remove_liquidity: bool,
83    pub meteora_pools_bootstrap_liquidity: bool,
84    pub meteora_pools_pool_created: bool,
85    pub meteora_pools_set_pool_fees: bool,
86    pub meteora_damm_v2_swap: bool,
87    pub meteora_damm_v2_add_liquidity: bool,
88    pub meteora_damm_v2_remove_liquidity: bool,
89    pub meteora_damm_v2_initialize_pool: bool,
90    pub meteora_damm_v2_create_position: bool,
91    pub meteora_damm_v2_close_position: bool,
92    pub meteora_damm_v2_claim_position_fee: bool,
93    pub meteora_damm_v2_initialize_reward: bool,
94    pub meteora_damm_v2_fund_reward: bool,
95    pub meteora_damm_v2_claim_reward: bool,
96    pub token_account: bool,
97    pub nonce_account: bool,
98    pub token_info: bool,
99}
100
101impl Default for Config {
102    fn default() -> Self {
103        Self {
104            server: ServerConfig {
105                host: "127.0.0.1".to_string(),
106                port: 9001,
107            },
108            grpc: GrpcConfig {
109                endpoint: "https://solana-yellowstone-grpc.publicnode.com:443".to_string(),
110                token: None,
111                enable_metrics: true,
112                enable_tls: true,
113                connection_timeout_ms: 10000,
114                request_timeout_ms: 30000,
115            },
116            protocols: ProtocolsConfig {
117                pumpfun: true,
118                pumpswap: false,
119                bonk: false,
120                raydium_amm_v4: false,
121                raydium_clmm: false,
122                raydium_cpmm: false,
123            },
124            events: EventsConfig {
125                block_meta: false,
126                bonk_trade: false,
127                bonk_pool_create: false,
128                bonk_migrate_amm: false,
129                pumpfun_trade: true,
130                pumpfun_create: true,
131                pumpfun_complete: false,
132                pumpfun_migrate: false,
133                pumpswap_buy: false,
134                pumpswap_sell: false,
135                pumpswap_create_pool: false,
136                pumpswap_pool_created: false,
137                pumpswap_trade: false,
138                pumpswap_liquidity_added: false,
139                pumpswap_liquidity_removed: false,
140                pumpswap_pool_updated: false,
141                pumpswap_fees_claimed: false,
142                raydium_cpmm_swap: false,
143                raydium_cpmm_deposit: false,
144                raydium_cpmm_withdraw: false,
145                raydium_cpmm_initialize: false,
146                raydium_clmm_swap: false,
147                raydium_clmm_create_pool: false,
148                raydium_clmm_open_position: false,
149                raydium_clmm_close_position: false,
150                raydium_clmm_increase_liquidity: false,
151                raydium_clmm_decrease_liquidity: false,
152                raydium_clmm_open_position_with_token_ext_nft: false,
153                raydium_clmm_collect_fee: false,
154                raydium_amm_v4_swap: false,
155                raydium_amm_v4_deposit: false,
156                raydium_amm_v4_withdraw: false,
157                raydium_amm_v4_initialize2: false,
158                raydium_amm_v4_withdraw_pnl: false,
159                orca_whirlpool_swap: false,
160                orca_whirlpool_liquidity_increased: false,
161                orca_whirlpool_liquidity_decreased: false,
162                orca_whirlpool_pool_initialized: false,
163                meteora_pools_swap: false,
164                meteora_pools_add_liquidity: false,
165                meteora_pools_remove_liquidity: false,
166                meteora_pools_bootstrap_liquidity: false,
167                meteora_pools_pool_created: false,
168                meteora_pools_set_pool_fees: false,
169                meteora_damm_v2_swap: false,
170                meteora_damm_v2_add_liquidity: false,
171                meteora_damm_v2_remove_liquidity: false,
172                meteora_damm_v2_initialize_pool: false,
173                meteora_damm_v2_create_position: false,
174                meteora_damm_v2_close_position: false,
175                meteora_damm_v2_claim_position_fee: false,
176                meteora_damm_v2_initialize_reward: false,
177                meteora_damm_v2_fund_reward: false,
178                meteora_damm_v2_claim_reward: false,
179                token_account: false,
180                nonce_account: false,
181                token_info: false,
182            },
183        }
184    }
185}
186
187impl Config {
188    pub fn load_from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
189        let content = fs::read_to_string(&path)
190            .with_context(|| format!("Failed to read config file: {:?}", path.as_ref()))?;
191
192        let config: Config = toml::from_str(&content)
193            .with_context(|| format!("Failed to parse config file: {:?}", path.as_ref()))?;
194
195        Ok(config)
196    }
197
198    pub fn load_or_default<P: AsRef<Path>>(path: P) -> Self {
199        match Self::load_from_file(&path) {
200            Ok(config) => {
201                tracing::info!("✅ Loaded config from: {:?}", path.as_ref());
202                config
203            }
204            Err(e) => {
205                tracing::warn!("⚠️  Failed to load config: {}, using default", e);
206                Self::default()
207            }
208        }
209    }
210
211    pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
212        let content = toml::to_string_pretty(self)
213            .context("Failed to serialize config to TOML")?;
214
215        fs::write(&path, content)
216            .with_context(|| format!("Failed to write config file: {:?}", path.as_ref()))?;
217
218        Ok(())
219    }
220
221    pub fn get_enabled_protocols(&self) -> Vec<sol_parser_sdk::grpc::Protocol> {
222        use sol_parser_sdk::grpc::Protocol;
223        let mut protocols = Vec::new();
224
225        if self.protocols.pumpfun {
226            protocols.push(Protocol::PumpFun);
227        }
228        if self.protocols.pumpswap {
229            protocols.push(Protocol::PumpSwap);
230        }
231        if self.protocols.bonk {
232            protocols.push(Protocol::Bonk);
233        }
234        if self.protocols.raydium_amm_v4 {
235            protocols.push(Protocol::RaydiumAmmV4);
236        }
237        if self.protocols.raydium_clmm {
238            protocols.push(Protocol::RaydiumClmm);
239        }
240        if self.protocols.raydium_cpmm {
241            protocols.push(Protocol::RaydiumCpmm);
242        }
243
244        protocols
245    }
246
247    pub fn get_enabled_event_types(&self) -> Vec<sol_parser_sdk::grpc::EventType> {
248        use sol_parser_sdk::grpc::EventType;
249        let mut event_types = Vec::new();
250
251        if self.events.block_meta { event_types.push(EventType::BlockMeta); }
252        if self.events.bonk_trade { event_types.push(EventType::BonkTrade); }
253        if self.events.bonk_pool_create { event_types.push(EventType::BonkPoolCreate); }
254        if self.events.bonk_migrate_amm { event_types.push(EventType::BonkMigrateAmm); }
255        if self.events.pumpfun_trade { event_types.push(EventType::PumpFunTrade); }
256        if self.events.pumpfun_create { event_types.push(EventType::PumpFunCreate); }
257        if self.events.pumpfun_complete { event_types.push(EventType::PumpFunComplete); }
258        if self.events.pumpfun_migrate { event_types.push(EventType::PumpFunMigrate); }
259        if self.events.pumpswap_buy { event_types.push(EventType::PumpSwapBuy); }
260        if self.events.pumpswap_sell { event_types.push(EventType::PumpSwapSell); }
261        if self.events.pumpswap_create_pool { event_types.push(EventType::PumpSwapCreatePool); }
262        if self.events.pumpswap_pool_created { event_types.push(EventType::PumpSwapPoolCreated); }
263        if self.events.pumpswap_trade { event_types.push(EventType::PumpSwapTrade); }
264        if self.events.pumpswap_liquidity_added { event_types.push(EventType::PumpSwapLiquidityAdded); }
265        if self.events.pumpswap_liquidity_removed { event_types.push(EventType::PumpSwapLiquidityRemoved); }
266        if self.events.pumpswap_pool_updated { event_types.push(EventType::PumpSwapPoolUpdated); }
267        if self.events.pumpswap_fees_claimed { event_types.push(EventType::PumpSwapFeesClaimed); }
268        if self.events.raydium_cpmm_swap { event_types.push(EventType::RaydiumCpmmSwap); }
269        if self.events.raydium_cpmm_deposit { event_types.push(EventType::RaydiumCpmmDeposit); }
270        if self.events.raydium_cpmm_withdraw { event_types.push(EventType::RaydiumCpmmWithdraw); }
271        if self.events.raydium_cpmm_initialize { event_types.push(EventType::RaydiumCpmmInitialize); }
272        if self.events.raydium_clmm_swap { event_types.push(EventType::RaydiumClmmSwap); }
273        if self.events.raydium_clmm_create_pool { event_types.push(EventType::RaydiumClmmCreatePool); }
274        if self.events.raydium_clmm_open_position { event_types.push(EventType::RaydiumClmmOpenPosition); }
275        if self.events.raydium_clmm_close_position { event_types.push(EventType::RaydiumClmmClosePosition); }
276        if self.events.raydium_clmm_increase_liquidity { event_types.push(EventType::RaydiumClmmIncreaseLiquidity); }
277        if self.events.raydium_clmm_decrease_liquidity { event_types.push(EventType::RaydiumClmmDecreaseLiquidity); }
278        if self.events.raydium_clmm_open_position_with_token_ext_nft { event_types.push(EventType::RaydiumClmmOpenPositionWithTokenExtNft); }
279        if self.events.raydium_clmm_collect_fee { event_types.push(EventType::RaydiumClmmCollectFee); }
280        if self.events.raydium_amm_v4_swap { event_types.push(EventType::RaydiumAmmV4Swap); }
281        if self.events.raydium_amm_v4_deposit { event_types.push(EventType::RaydiumAmmV4Deposit); }
282        if self.events.raydium_amm_v4_withdraw { event_types.push(EventType::RaydiumAmmV4Withdraw); }
283        if self.events.raydium_amm_v4_initialize2 { event_types.push(EventType::RaydiumAmmV4Initialize2); }
284        if self.events.raydium_amm_v4_withdraw_pnl { event_types.push(EventType::RaydiumAmmV4WithdrawPnl); }
285        if self.events.orca_whirlpool_swap { event_types.push(EventType::OrcaWhirlpoolSwap); }
286        if self.events.orca_whirlpool_liquidity_increased { event_types.push(EventType::OrcaWhirlpoolLiquidityIncreased); }
287        if self.events.orca_whirlpool_liquidity_decreased { event_types.push(EventType::OrcaWhirlpoolLiquidityDecreased); }
288        if self.events.orca_whirlpool_pool_initialized { event_types.push(EventType::OrcaWhirlpoolPoolInitialized); }
289        if self.events.meteora_pools_swap { event_types.push(EventType::MeteoraPoolsSwap); }
290        if self.events.meteora_pools_add_liquidity { event_types.push(EventType::MeteoraPoolsAddLiquidity); }
291        if self.events.meteora_pools_remove_liquidity { event_types.push(EventType::MeteoraPoolsRemoveLiquidity); }
292        if self.events.meteora_pools_bootstrap_liquidity { event_types.push(EventType::MeteoraPoolsBootstrapLiquidity); }
293        if self.events.meteora_pools_pool_created { event_types.push(EventType::MeteoraPoolsPoolCreated); }
294        if self.events.meteora_pools_set_pool_fees { event_types.push(EventType::MeteoraPoolsSetPoolFees); }
295        if self.events.meteora_damm_v2_swap { event_types.push(EventType::MeteoraDammV2Swap); }
296        if self.events.meteora_damm_v2_add_liquidity { event_types.push(EventType::MeteoraDammV2AddLiquidity); }
297        if self.events.meteora_damm_v2_remove_liquidity { event_types.push(EventType::MeteoraDammV2RemoveLiquidity); }
298        if self.events.meteora_damm_v2_initialize_pool { event_types.push(EventType::MeteoraDammV2InitializePool); }
299        if self.events.meteora_damm_v2_create_position { event_types.push(EventType::MeteoraDammV2CreatePosition); }
300        if self.events.meteora_damm_v2_close_position { event_types.push(EventType::MeteoraDammV2ClosePosition); }
301        if self.events.meteora_damm_v2_claim_position_fee { event_types.push(EventType::MeteoraDammV2ClaimPositionFee); }
302        if self.events.meteora_damm_v2_initialize_reward { event_types.push(EventType::MeteoraDammV2InitializeReward); }
303        if self.events.meteora_damm_v2_fund_reward { event_types.push(EventType::MeteoraDammV2FundReward); }
304        if self.events.meteora_damm_v2_claim_reward { event_types.push(EventType::MeteoraDammV2ClaimReward); }
305        if self.events.token_account { event_types.push(EventType::TokenAccount); }
306        if self.events.nonce_account { event_types.push(EventType::NonceAccount); }
307        if self.events.token_info { event_types.push(EventType::TokenInfo); }
308
309        event_types
310    }
311}