orca_tx_sender/
rpc_config.rs1use solana_client::nonblocking::rpc_client::RpcClient;
2use solana_program::hash::Hash;
3use std::time::Duration;
4
5const MAINNET_HASH: &str = "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d";
6const DEVNET_HASH: &str = "EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG";
7const ECLIPSE_HASH: &str = "EAQLJCV2mh23BsK2P9oYpV5CHVLDNHTxYss3URrNmg3s";
8const ECLIPSE_TESTNET_HASH: &str = "CX4huckiV9QNAkKNVKi5Tj8nxzBive5kQimd94viMKsU";
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum ChainId {
12 Mainnet,
13 Devnet,
14 Eclipse,
15 EclipseTestnet,
16 Unknown(Hash),
17}
18
19impl ChainId {
20 pub fn is_mainnet(&self) -> bool {
21 matches!(self, Self::Mainnet)
22 }
23}
24
25impl From<Hash> for ChainId {
26 fn from(hash: Hash) -> Self {
27 let hash_str = hash.to_string();
29 if hash_str == MAINNET_HASH {
31 return Self::Mainnet;
32 } else if hash_str == DEVNET_HASH {
33 return Self::Devnet;
34 } else if hash_str == ECLIPSE_HASH {
35 return Self::Eclipse;
36 } else if hash_str == ECLIPSE_TESTNET_HASH {
37 return Self::EclipseTestnet;
38 }
39 Self::Unknown(hash)
40 }
41}
42
43#[non_exhaustive]
49#[derive(Debug, Default, Clone, PartialEq)]
50pub struct RpcConfig {
51 pub url: String,
52 pub supports_priority_fee_percentile: bool,
53 pub chain_id: Option<ChainId>,
54}
55
56impl RpcConfig {
57 pub fn with_url(mut self, url: impl Into<String>) -> Self {
60 self.url = url.into();
61 self
62 }
63
64 pub fn with_priority_fee_percentile_support(
65 mut self,
66 supports_priority_fee_percentile: bool,
67 ) -> Self {
68 self.supports_priority_fee_percentile = supports_priority_fee_percentile;
69 self
70 }
71
72 pub fn with_chain_id(mut self, chain_id: ChainId) -> Self {
73 self.chain_id = Some(chain_id);
74 self
75 }
76
77 pub async fn new(url: impl Into<String>) -> Result<Self, String> {
78 let url = url.into();
79 let client = RpcClient::new(url.clone());
80 let genesis_hash = client
81 .get_genesis_hash()
82 .await
83 .map_err(|e| format!("Chain Detection Error: Failed to get genesis hash: {e}"))?;
84
85 Ok(Self {
86 url,
87 supports_priority_fee_percentile: false,
88 chain_id: Some(ChainId::from(genesis_hash)),
89 })
90 }
91
92 pub fn client(&self) -> RpcClient {
93 RpcClient::new_with_timeout(self.url.clone(), Duration::from_millis(90_000))
94 }
95
96 pub fn is_mainnet(&self) -> bool {
98 self.chain_id
99 .as_ref()
100 .is_some_and(|chain_id| chain_id.is_mainnet())
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn builder_sets_rpc_configuration() {
110 let config = RpcConfig::default()
111 .with_url("https://example.com")
112 .with_priority_fee_percentile_support(true)
113 .with_chain_id(ChainId::Mainnet);
114
115 assert_eq!(config.url, "https://example.com");
116 assert!(config.supports_priority_fee_percentile);
117 assert_eq!(config.chain_id, Some(ChainId::Mainnet));
118 }
119}