1use crate::errors::{Result, TensoraError};
4use crate::types::chains;
5use std::env;
6use dotenvy::dotenv;
7
8#[derive(Debug, Clone)]
10pub struct TensoraConfig {
11 pub tensora_rpc: String,
13
14 pub tensora_chain_id: u64,
16
17 pub bsc_rpc: String,
19
20 pub bsc_chain_id: u64,
22
23 pub private_key: Option<String>,
25
26 pub addresses: AddressConfig,
28}
29
30#[derive(Debug, Clone)]
32pub struct AddressConfig {
33 pub l1_wtora: Option<String>,
35
36 pub l2_wtora: Option<String>,
38
39 pub l1_bridge: Option<String>,
41
42 pub l2_bridge: Option<String>,
44
45 pub staking_hub: Option<String>,
47
48 pub subnet_factory: Option<String>,
50
51 pub entry_point: Option<String>,
53
54 pub paymaster: Option<String>,
56}
57
58impl Default for AddressConfig {
59 fn default() -> Self {
60 Self {
61 l1_wtora: None,
62 l2_wtora: None,
63 l1_bridge: None,
64 l2_bridge: None,
65 staking_hub: None,
66 subnet_factory: None,
67 entry_point: None,
68 paymaster: None,
69 }
70 }
71}
72
73impl TensoraConfig {
74 pub fn from_env() -> Result<Self> {
84 let _ = dotenv();
86
87 let tensora_rpc = env::var("TENSORA_RPC")
88 .unwrap_or_else(|_| chains::TENSORA_RPC.to_string());
89
90 let tensora_chain_id = env::var("TENSORA_CHAIN_ID")
91 .unwrap_or_else(|_| chains::TENSORA_CHAIN_ID.to_string())
92 .parse()
93 .map_err(|_| TensoraError::Config("Invalid TENSORA_CHAIN_ID".to_string()))?;
94
95 let bsc_rpc = env::var("BSC_RPC")
96 .unwrap_or_else(|_| chains::BSC_RPC.to_string());
97
98 let bsc_chain_id = env::var("BSC_CHAIN_ID")
99 .unwrap_or_else(|_| chains::BSC_CHAIN_ID.to_string())
100 .parse()
101 .map_err(|_| TensoraError::Config("Invalid BSC_CHAIN_ID".to_string()))?;
102
103 let private_key = env::var("PRIVATE_KEY").ok();
104
105 let addresses = AddressConfig {
106 l1_wtora: env::var("L1_WTORA").ok(),
107 l2_wtora: env::var("L2_WTORA").ok(),
108 l1_bridge: env::var("L1_BRIDGE").ok(),
109 l2_bridge: env::var("L2_BRIDGE").ok(),
110 staking_hub: env::var("STAKING_HUB").ok(),
111 subnet_factory: env::var("SUBNET_FACTORY").ok(),
112 entry_point: env::var("ENTRY_POINT").ok(),
113 paymaster: env::var("PAYMASTER").ok(),
114 };
115
116 Ok(Self {
117 tensora_rpc,
118 tensora_chain_id,
119 bsc_rpc,
120 bsc_chain_id,
121 private_key,
122 addresses,
123 })
124 }
125
126 pub fn new(tensora_rpc: String, bsc_rpc: String) -> Self {
128 Self {
129 tensora_rpc,
130 tensora_chain_id: chains::TENSORA_CHAIN_ID,
131 bsc_rpc,
132 bsc_chain_id: chains::BSC_CHAIN_ID,
133 private_key: None,
134 addresses: AddressConfig::default(),
135 }
136 }
137
138 pub fn with_private_key(mut self, private_key: String) -> Self {
140 self.private_key = Some(private_key);
141 self
142 }
143
144 pub fn with_addresses(mut self, addresses: AddressConfig) -> Self {
146 self.addresses = addresses;
147 self
148 }
149
150 pub fn validate(&self) -> Result<()> {
152 if self.tensora_chain_id != chains::TENSORA_CHAIN_ID {
154 return Err(TensoraError::InvalidChainId {
155 expected: chains::TENSORA_CHAIN_ID,
156 actual: self.tensora_chain_id,
157 });
158 }
159
160 if self.bsc_chain_id != chains::BSC_CHAIN_ID {
161 return Err(TensoraError::InvalidChainId {
162 expected: chains::BSC_CHAIN_ID,
163 actual: self.bsc_chain_id,
164 });
165 }
166
167 if self.tensora_rpc.is_empty() {
169 return Err(TensoraError::Config("TENSORA_RPC cannot be empty".to_string()));
170 }
171
172 if self.bsc_rpc.is_empty() {
173 return Err(TensoraError::Config("BSC_RPC cannot be empty".to_string()));
174 }
175
176 Ok(())
177 }
178}
179
180impl Default for TensoraConfig {
181 fn default() -> Self {
182 Self {
183 tensora_rpc: chains::TENSORA_RPC.to_string(),
184 tensora_chain_id: chains::TENSORA_CHAIN_ID,
185 bsc_rpc: chains::BSC_RPC.to_string(),
186 bsc_chain_id: chains::BSC_CHAIN_ID,
187 private_key: None,
188 addresses: AddressConfig::default(),
189 }
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196
197 #[test]
198 fn test_default_config() {
199 let config = TensoraConfig::default();
200 assert_eq!(config.tensora_chain_id, chains::TENSORA_CHAIN_ID);
201 assert_eq!(config.bsc_chain_id, chains::BSC_CHAIN_ID);
202 }
203
204 #[test]
205 fn test_validate_config() {
206 let config = TensoraConfig::default();
207 assert!(config.validate().is_ok());
208 }
209
210 #[test]
211 fn test_invalid_chain_id() {
212 let mut config = TensoraConfig::default();
213 config.tensora_chain_id = 99999;
214 assert!(config.validate().is_err());
215 }
216}
217