openzeppelin_monitor/utils/tests/builders/solana/
monitor.rs1use crate::models::{
6 AddressWithSpec, ChainConfiguration, ContractSpec, EventCondition, FunctionCondition,
7 MatchConditions, Monitor, ScriptLanguage, SolanaMonitorConfig, TransactionCondition,
8 TransactionStatus, TriggerConditions,
9};
10
11pub struct MonitorBuilder {
13 name: String,
14 networks: Vec<String>,
15 paused: bool,
16 addresses: Vec<AddressWithSpec>,
17 match_conditions: MatchConditions,
18 trigger_conditions: Vec<TriggerConditions>,
19 triggers: Vec<String>,
20 chain_configurations: Vec<ChainConfiguration>,
21}
22
23impl Default for MonitorBuilder {
24 fn default() -> Self {
25 Self {
26 name: "TestSolanaMonitor".to_string(),
27 networks: vec!["solana_mainnet".to_string()],
28 paused: false,
29 addresses: vec![AddressWithSpec {
30 address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA".to_string(),
31 contract_spec: None,
32 }],
33 match_conditions: MatchConditions {
34 functions: vec![],
35 events: vec![],
36 transactions: vec![],
37 },
38 trigger_conditions: vec![],
39 triggers: vec![],
40 chain_configurations: vec![ChainConfiguration {
41 solana: Some(SolanaMonitorConfig::default()),
42 ..Default::default()
43 }],
44 }
45 }
46}
47
48impl MonitorBuilder {
49 pub fn new() -> Self {
50 Self::default()
51 }
52
53 pub fn name(mut self, name: &str) -> Self {
54 self.name = name.to_string();
55 self
56 }
57
58 pub fn networks(mut self, networks: Vec<String>) -> Self {
59 self.networks = networks;
60 self
61 }
62
63 pub fn paused(mut self, paused: bool) -> Self {
64 self.paused = paused;
65 self
66 }
67
68 pub fn address(mut self, address: &str) -> Self {
69 self.addresses = vec![AddressWithSpec {
70 address: address.to_string(),
71 contract_spec: None,
72 }];
73 self
74 }
75
76 pub fn addresses(mut self, addresses: Vec<String>) -> Self {
77 self.addresses = addresses
78 .into_iter()
79 .map(|addr| AddressWithSpec {
80 address: addr,
81 contract_spec: None,
82 })
83 .collect();
84 self
85 }
86
87 pub fn add_address(mut self, address: &str) -> Self {
88 self.addresses.push(AddressWithSpec {
89 address: address.to_string(),
90 contract_spec: None,
91 });
92 self
93 }
94
95 pub fn address_with_spec(mut self, address: &str, spec: Option<ContractSpec>) -> Self {
96 self.addresses = vec![AddressWithSpec {
97 address: address.to_string(),
98 contract_spec: spec,
99 }];
100 self
101 }
102
103 pub fn addresses_with_spec(mut self, addresses: Vec<(String, Option<ContractSpec>)>) -> Self {
104 self.addresses = addresses
105 .into_iter()
106 .map(|(addr, spec)| AddressWithSpec {
107 address: addr,
108 contract_spec: spec,
109 })
110 .collect();
111 self
112 }
113
114 pub fn function(mut self, signature: &str, expression: Option<String>) -> Self {
116 self.match_conditions.functions.push(FunctionCondition {
117 signature: signature.to_string(),
118 expression,
119 });
120 self
121 }
122
123 pub fn event(mut self, signature: &str, expression: Option<String>) -> Self {
125 self.match_conditions.events.push(EventCondition {
126 signature: signature.to_string(),
127 expression,
128 });
129 self
130 }
131
132 pub fn transaction(mut self, status: TransactionStatus, expression: Option<String>) -> Self {
133 self.match_conditions
134 .transactions
135 .push(TransactionCondition { status, expression });
136 self
137 }
138
139 pub fn trigger_condition(
140 mut self,
141 script_path: &str,
142 timeout_ms: u32,
143 language: ScriptLanguage,
144 arguments: Option<Vec<String>>,
145 ) -> Self {
146 self.trigger_conditions.push(TriggerConditions {
147 script_path: script_path.to_string(),
148 timeout_ms,
149 arguments,
150 language,
151 });
152 self
153 }
154
155 pub fn triggers(mut self, triggers: Vec<String>) -> Self {
156 self.triggers = triggers;
157 self
158 }
159
160 pub fn match_conditions(mut self, match_conditions: MatchConditions) -> Self {
161 self.match_conditions = match_conditions;
162 self
163 }
164
165 pub fn build(self) -> Monitor {
166 Monitor {
167 name: self.name,
168 networks: self.networks,
169 paused: self.paused,
170 addresses: self.addresses,
171 match_conditions: self.match_conditions,
172 trigger_conditions: self.trigger_conditions,
173 triggers: self.triggers,
174 chain_configurations: self.chain_configurations,
175 }
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182
183 #[test]
184 fn test_default_solana_monitor() {
185 let monitor = MonitorBuilder::new().build();
186
187 assert_eq!(monitor.name, "TestSolanaMonitor");
188 assert_eq!(monitor.networks, vec!["solana_mainnet"]);
189 assert!(!monitor.paused);
190 assert_eq!(monitor.addresses.len(), 1);
191 assert_eq!(
192 monitor.addresses[0].address,
193 "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
194 );
195 assert!(monitor.addresses[0].contract_spec.is_none());
196 assert!(monitor.match_conditions.functions.is_empty());
197 assert!(monitor.match_conditions.events.is_empty());
198 assert!(monitor.match_conditions.transactions.is_empty());
199 assert!(monitor.trigger_conditions.is_empty());
200 assert!(monitor.triggers.is_empty());
201 assert!(monitor.chain_configurations[0].solana.is_some());
203 assert!(monitor.chain_configurations[0].evm.is_none());
204 }
205
206 #[test]
207 fn test_basic_builder_methods() {
208 let monitor = MonitorBuilder::new()
209 .name("MySolanaMonitor")
210 .networks(vec!["solana_devnet".to_string()])
211 .paused(true)
212 .address("11111111111111111111111111111111")
213 .build();
214
215 assert_eq!(monitor.name, "MySolanaMonitor");
216 assert_eq!(monitor.networks, vec!["solana_devnet"]);
217 assert!(monitor.paused);
218 assert_eq!(monitor.addresses.len(), 1);
219 assert_eq!(
220 monitor.addresses[0].address,
221 "11111111111111111111111111111111"
222 );
223 }
224
225 #[test]
226 fn test_address_methods() {
227 let monitor = MonitorBuilder::new()
228 .addresses(vec![
229 "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA".to_string(),
230 "11111111111111111111111111111111".to_string(),
231 ])
232 .add_address("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")
233 .build();
234
235 assert_eq!(monitor.addresses.len(), 3);
236 assert_eq!(
237 monitor.addresses[0].address,
238 "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
239 );
240 assert_eq!(
241 monitor.addresses[1].address,
242 "11111111111111111111111111111111"
243 );
244 assert_eq!(
245 monitor.addresses[2].address,
246 "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
247 );
248 }
249
250 #[test]
251 fn test_match_conditions() {
252 let monitor = MonitorBuilder::new()
253 .function("transfer", Some("amount > 1000000".to_string()))
254 .event("TransferEvent", None)
255 .transaction(TransactionStatus::Success, None)
256 .build();
257
258 assert_eq!(monitor.match_conditions.functions.len(), 1);
259 assert_eq!(monitor.match_conditions.functions[0].signature, "transfer");
260 assert_eq!(
261 monitor.match_conditions.functions[0].expression,
262 Some("amount > 1000000".to_string())
263 );
264 assert_eq!(monitor.match_conditions.events.len(), 1);
265 assert_eq!(
266 monitor.match_conditions.events[0].signature,
267 "TransferEvent"
268 );
269 assert_eq!(monitor.match_conditions.transactions.len(), 1);
270 assert_eq!(
271 monitor.match_conditions.transactions[0].status,
272 TransactionStatus::Success
273 );
274 }
275
276 #[test]
277 fn test_trigger_conditions() {
278 let monitor = MonitorBuilder::new()
279 .trigger_condition("script.py", 1000, ScriptLanguage::Python, None)
280 .trigger_condition(
281 "script.js",
282 2000,
283 ScriptLanguage::JavaScript,
284 Some(vec!["-verbose".to_string()]),
285 )
286 .build();
287
288 assert_eq!(monitor.trigger_conditions.len(), 2);
289 assert_eq!(monitor.trigger_conditions[0].script_path, "script.py");
290 assert_eq!(monitor.trigger_conditions[0].timeout_ms, 1000);
291 assert_eq!(
292 monitor.trigger_conditions[0].language,
293 ScriptLanguage::Python
294 );
295 assert_eq!(monitor.trigger_conditions[1].script_path, "script.js");
296 assert_eq!(monitor.trigger_conditions[1].timeout_ms, 2000);
297 assert_eq!(
298 monitor.trigger_conditions[1].language,
299 ScriptLanguage::JavaScript
300 );
301 assert_eq!(
302 monitor.trigger_conditions[1].arguments,
303 Some(vec!["-verbose".to_string()])
304 );
305 }
306
307 #[test]
308 fn test_triggers() {
309 let monitor = MonitorBuilder::new()
310 .triggers(vec!["trigger1".to_string(), "trigger2".to_string()])
311 .build();
312
313 assert_eq!(monitor.triggers.len(), 2);
314 assert_eq!(monitor.triggers[0], "trigger1");
315 assert_eq!(monitor.triggers[1], "trigger2");
316 }
317}