1use crate::models::{
2 DisabledReason, Relayer, RelayerError, RelayerEvmPolicy, RelayerSolanaPolicy,
3 RelayerStellarPolicy,
4};
5use serde::{Deserialize, Serialize};
6
7use super::{RelayerNetworkPolicy, RelayerNetworkType, RpcConfig};
8
9pub type NetworkType = RelayerNetworkType;
11
12pub struct RelayerRepoUpdater {
15 original: RelayerRepoModel,
16}
17
18impl RelayerRepoUpdater {
19 pub fn from_existing(existing: RelayerRepoModel) -> Self {
21 Self { original: existing }
22 }
23
24 pub fn apply_domain_update(self, domain: Relayer) -> RelayerRepoModel {
30 let mut updated = RelayerRepoModel::from(domain);
31 updated.address = self.original.address;
33 updated.system_disabled = self.original.system_disabled;
34 updated.disabled_reason = self.original.disabled_reason;
35 updated
36 }
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct RelayerRepoModel {
41 pub id: String,
42 pub name: String,
43 pub network: String,
44 pub paused: bool,
45 pub network_type: NetworkType,
46 pub signer_id: String,
47 pub policies: RelayerNetworkPolicy,
48 pub address: String,
49 pub notification_id: Option<String>,
50 pub system_disabled: bool,
51 pub disabled_reason: Option<DisabledReason>,
52 pub custom_rpc_urls: Option<Vec<RpcConfig>>,
53}
54
55impl RelayerRepoModel {
56 pub fn validate_active_state(&self) -> Result<(), RelayerError> {
57 if self.paused {
58 return Err(RelayerError::RelayerPaused);
59 }
60
61 if self.system_disabled {
62 return Err(RelayerError::RelayerDisabled);
63 }
64
65 Ok(())
66 }
67}
68
69impl Default for RelayerRepoModel {
70 fn default() -> Self {
71 Self {
72 id: "".to_string(),
73 name: "".to_string(),
74 network: "".to_string(),
75 paused: false,
76 network_type: NetworkType::Evm,
77 signer_id: "".to_string(),
78 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default()),
79 address: "0x".to_string(),
80 notification_id: None,
81 system_disabled: false,
82 disabled_reason: None,
83 custom_rpc_urls: None,
84 }
85 }
86}
87
88impl From<RelayerRepoModel> for Relayer {
89 fn from(repo_model: RelayerRepoModel) -> Self {
90 Self {
91 id: repo_model.id,
92 name: repo_model.name,
93 network: repo_model.network,
94 paused: repo_model.paused,
95 network_type: repo_model.network_type,
96 policies: Some(repo_model.policies),
97 signer_id: repo_model.signer_id,
98 notification_id: repo_model.notification_id,
99 custom_rpc_urls: repo_model.custom_rpc_urls,
100 }
101 }
102}
103
104impl From<Relayer> for RelayerRepoModel {
105 fn from(relayer: Relayer) -> Self {
106 Self {
107 id: relayer.id,
108 name: relayer.name,
109 network: relayer.network,
110 paused: relayer.paused,
111 network_type: relayer.network_type,
112 signer_id: relayer.signer_id,
113 policies: relayer.policies.unwrap_or_else(|| {
114 match relayer.network_type {
116 RelayerNetworkType::Evm => {
117 RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default())
118 }
119 RelayerNetworkType::Solana => {
120 RelayerNetworkPolicy::Solana(RelayerSolanaPolicy::default())
121 }
122 RelayerNetworkType::Stellar => {
123 RelayerNetworkPolicy::Stellar(RelayerStellarPolicy::default())
124 }
125 }
126 }),
127 address: "".to_string(), notification_id: relayer.notification_id,
129 system_disabled: false,
130 disabled_reason: None,
131 custom_rpc_urls: relayer.custom_rpc_urls,
132 }
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use crate::models::{
139 RelayerEvmPolicy, RelayerSolanaPolicy, RelayerStellarPolicy, SolanaAllowedTokensPolicy,
140 SolanaFeePaymentStrategy,
141 };
142
143 use super::*;
144
145 fn create_test_relayer(paused: bool, system_disabled: bool) -> RelayerRepoModel {
146 RelayerRepoModel {
147 id: "test_relayer".to_string(),
148 name: "Test Relayer".to_string(),
149 paused,
150 system_disabled,
151 disabled_reason: None,
152 network: "test_network".to_string(),
153 network_type: NetworkType::Evm,
154 signer_id: "test_signer".to_string(),
155 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default()),
156 address: "0xtest".to_string(),
157 notification_id: None,
158 custom_rpc_urls: None,
159 }
160 }
161
162 fn create_test_relayer_solana(paused: bool, system_disabled: bool) -> RelayerRepoModel {
163 RelayerRepoModel {
164 id: "test_solana_relayer".to_string(),
165 name: "Test Solana Relayer".to_string(),
166 paused,
167 system_disabled,
168 network: "mainnet".to_string(),
169 network_type: NetworkType::Solana,
170 signer_id: "test_signer".to_string(),
171 policies: RelayerNetworkPolicy::Solana(RelayerSolanaPolicy {
172 fee_payment_strategy: Some(SolanaFeePaymentStrategy::Relayer),
173 min_balance: Some(1000000),
174 max_signatures: Some(5),
175 allowed_tokens: None,
176 allowed_programs: None,
177 allowed_accounts: None,
178 disallowed_accounts: None,
179 max_tx_data_size: None,
180 max_allowed_fee_lamports: None,
181 swap_config: None,
182 fee_margin_percentage: None,
183 }),
184 address: "SolanaAddress123".to_string(),
185 notification_id: None,
186 custom_rpc_urls: None,
187 ..Default::default()
188 }
189 }
190
191 fn create_test_relayer_stellar(paused: bool, system_disabled: bool) -> RelayerRepoModel {
192 RelayerRepoModel {
193 id: "test_stellar_relayer".to_string(),
194 name: "Test Stellar Relayer".to_string(),
195 paused,
196 system_disabled,
197 network: "mainnet".to_string(),
198 network_type: NetworkType::Stellar,
199 signer_id: "test_signer".to_string(),
200 policies: RelayerNetworkPolicy::Stellar(RelayerStellarPolicy {
201 min_balance: Some(20000000),
202 max_fee: Some(100000),
203 timeout_seconds: Some(30),
204 concurrent_transactions: None,
205 }),
206 address: "GXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".to_string(),
207 notification_id: None,
208 custom_rpc_urls: None,
209 ..Default::default()
210 }
211 }
212
213 #[test]
214 fn test_validate_active_state_success() {
215 let relayer = create_test_relayer(false, false);
216 assert!(relayer.validate_active_state().is_ok());
217 }
218
219 #[test]
220 fn test_validate_active_state_success_solana() {
221 let relayer = create_test_relayer_solana(false, false);
222 assert!(relayer.validate_active_state().is_ok());
223 }
224
225 #[test]
226 fn test_validate_active_state_success_stellar() {
227 let relayer = create_test_relayer_stellar(false, false);
228 assert!(relayer.validate_active_state().is_ok());
229 }
230
231 #[test]
232 fn test_validate_active_state_paused() {
233 let relayer = create_test_relayer(true, false);
234 let result = relayer.validate_active_state();
235 assert!(result.is_err());
236 assert!(matches!(result.unwrap_err(), RelayerError::RelayerPaused));
237 }
238
239 #[test]
240 fn test_validate_active_state_paused_solana() {
241 let relayer = create_test_relayer_solana(true, false);
242 let result = relayer.validate_active_state();
243 assert!(result.is_err());
244 assert!(matches!(result.unwrap_err(), RelayerError::RelayerPaused));
245 }
246
247 #[test]
248 fn test_validate_active_state_paused_stellar() {
249 let relayer = create_test_relayer_stellar(true, false);
250 let result = relayer.validate_active_state();
251 assert!(result.is_err());
252 assert!(matches!(result.unwrap_err(), RelayerError::RelayerPaused));
253 }
254
255 #[test]
256 fn test_validate_active_state_disabled() {
257 let relayer = create_test_relayer(false, true);
258 let result = relayer.validate_active_state();
259 assert!(result.is_err());
260 assert!(matches!(result.unwrap_err(), RelayerError::RelayerDisabled));
261 }
262
263 #[test]
264 fn test_validate_active_state_disabled_solana() {
265 let relayer = create_test_relayer_solana(false, true);
266 let result = relayer.validate_active_state();
267 assert!(result.is_err());
268 assert!(matches!(result.unwrap_err(), RelayerError::RelayerDisabled));
269 }
270
271 #[test]
272 fn test_validate_active_state_disabled_stellar() {
273 let relayer = create_test_relayer_stellar(false, true);
274 let result = relayer.validate_active_state();
275 assert!(result.is_err());
276 assert!(matches!(result.unwrap_err(), RelayerError::RelayerDisabled));
277 }
278
279 #[test]
280 fn test_validate_active_state_both_paused_and_disabled() {
281 let relayer = create_test_relayer(true, true);
283 let result = relayer.validate_active_state();
284 assert!(result.is_err());
285 assert!(matches!(result.unwrap_err(), RelayerError::RelayerPaused));
286 }
287
288 #[test]
289 fn test_conversion_from_repo_model_to_domain_evm() {
290 let repo_model = create_test_relayer(false, false);
291 let domain_relayer = Relayer::from(repo_model.clone());
292
293 assert_eq!(domain_relayer.id, repo_model.id);
294 assert_eq!(domain_relayer.name, repo_model.name);
295 assert_eq!(domain_relayer.network, repo_model.network);
296 assert_eq!(domain_relayer.paused, repo_model.paused);
297 assert_eq!(domain_relayer.network_type, repo_model.network_type);
298 assert_eq!(domain_relayer.signer_id, repo_model.signer_id);
299 assert_eq!(domain_relayer.notification_id, repo_model.notification_id);
300 assert_eq!(domain_relayer.custom_rpc_urls, repo_model.custom_rpc_urls);
301
302 assert!(domain_relayer.policies.is_some());
304 if let Some(RelayerNetworkPolicy::Evm(_)) = domain_relayer.policies {
305 } else {
307 panic!("Expected EVM policy");
308 }
309 }
310
311 #[test]
312 fn test_conversion_from_repo_model_to_domain_solana() {
313 let repo_model = create_test_relayer_solana(false, false);
314 let domain_relayer = Relayer::from(repo_model.clone());
315
316 assert_eq!(domain_relayer.id, repo_model.id);
317 assert_eq!(domain_relayer.network_type, RelayerNetworkType::Solana);
318
319 assert!(domain_relayer.policies.is_some());
321 if let Some(RelayerNetworkPolicy::Solana(solana_policy)) = domain_relayer.policies {
322 assert_eq!(solana_policy.min_balance, Some(1000000));
323 assert_eq!(solana_policy.max_signatures, Some(5));
324 assert_eq!(
325 solana_policy.fee_payment_strategy,
326 Some(SolanaFeePaymentStrategy::Relayer)
327 );
328 } else {
329 panic!("Expected Solana policy");
330 }
331 }
332
333 #[test]
334 fn test_conversion_from_repo_model_to_domain_stellar() {
335 let repo_model = create_test_relayer_stellar(false, false);
336 let domain_relayer = Relayer::from(repo_model.clone());
337
338 assert_eq!(domain_relayer.id, repo_model.id);
339 assert_eq!(domain_relayer.network_type, RelayerNetworkType::Stellar);
340
341 assert!(domain_relayer.policies.is_some());
343 if let Some(RelayerNetworkPolicy::Stellar(stellar_policy)) = domain_relayer.policies {
344 assert_eq!(stellar_policy.min_balance, Some(20000000));
345 assert_eq!(stellar_policy.max_fee, Some(100000));
346 assert_eq!(stellar_policy.timeout_seconds, Some(30));
347 } else {
348 panic!("Expected Stellar policy");
349 }
350 }
351
352 #[test]
353 fn test_conversion_from_domain_to_repo_model_evm() {
354 let domain_relayer = Relayer {
355 id: "test_evm_relayer".to_string(),
356 name: "Test EVM Relayer".to_string(),
357 network: "mainnet".to_string(),
358 paused: false,
359 network_type: RelayerNetworkType::Evm,
360 policies: Some(RelayerNetworkPolicy::Evm(RelayerEvmPolicy {
361 gas_price_cap: Some(100_000_000_000),
362 eip1559_pricing: Some(true),
363 min_balance: None,
364 gas_limit_estimation: None,
365 whitelist_receivers: None,
366 private_transactions: None,
367 })),
368 signer_id: "test_signer".to_string(),
369 notification_id: Some("notification_123".to_string()),
370 custom_rpc_urls: None,
371 };
372
373 let repo_model = RelayerRepoModel::from(domain_relayer.clone());
374
375 assert_eq!(repo_model.id, domain_relayer.id);
376 assert_eq!(repo_model.name, domain_relayer.name);
377 assert_eq!(repo_model.network, domain_relayer.network);
378 assert_eq!(repo_model.paused, domain_relayer.paused);
379 assert_eq!(repo_model.network_type, domain_relayer.network_type);
380 assert_eq!(repo_model.signer_id, domain_relayer.signer_id);
381 assert_eq!(repo_model.notification_id, domain_relayer.notification_id);
382 assert_eq!(repo_model.custom_rpc_urls, domain_relayer.custom_rpc_urls);
383
384 assert_eq!(repo_model.address, "");
386 assert!(!repo_model.system_disabled);
387
388 if let RelayerNetworkPolicy::Evm(evm_policy) = repo_model.policies {
390 assert_eq!(evm_policy.gas_price_cap, Some(100_000_000_000));
391 assert_eq!(evm_policy.eip1559_pricing, Some(true));
392 } else {
393 panic!("Expected EVM policy");
394 }
395 }
396
397 #[test]
398 fn test_conversion_from_domain_to_repo_model_solana() {
399 let domain_relayer = Relayer {
400 id: "test_solana_relayer".to_string(),
401 name: "Test Solana Relayer".to_string(),
402 network: "mainnet".to_string(),
403 paused: false,
404 network_type: RelayerNetworkType::Solana,
405 policies: Some(RelayerNetworkPolicy::Solana(RelayerSolanaPolicy {
406 fee_payment_strategy: Some(SolanaFeePaymentStrategy::User),
407 min_balance: Some(5000000),
408 max_signatures: Some(8),
409 allowed_tokens: Some(vec![SolanaAllowedTokensPolicy::new(
410 "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v".to_string(),
411 Some(100000),
412 None,
413 )]),
414 allowed_programs: None,
415 allowed_accounts: None,
416 disallowed_accounts: None,
417 max_tx_data_size: None,
418 max_allowed_fee_lamports: None,
419 swap_config: None,
420 fee_margin_percentage: None,
421 })),
422 signer_id: "test_signer".to_string(),
423 notification_id: None,
424 custom_rpc_urls: None,
425 };
426
427 let repo_model = RelayerRepoModel::from(domain_relayer.clone());
428
429 assert_eq!(repo_model.network_type, RelayerNetworkType::Solana);
430
431 if let RelayerNetworkPolicy::Solana(solana_policy) = repo_model.policies {
433 assert_eq!(
434 solana_policy.fee_payment_strategy,
435 Some(SolanaFeePaymentStrategy::User)
436 );
437 assert_eq!(solana_policy.min_balance, Some(5000000));
438 assert_eq!(solana_policy.max_signatures, Some(8));
439 assert!(solana_policy.allowed_tokens.is_some());
440 } else {
441 panic!("Expected Solana policy");
442 }
443 }
444
445 #[test]
446 fn test_conversion_from_domain_to_repo_model_stellar() {
447 let domain_relayer = Relayer {
448 id: "test_stellar_relayer".to_string(),
449 name: "Test Stellar Relayer".to_string(),
450 network: "mainnet".to_string(),
451 paused: false,
452 network_type: RelayerNetworkType::Stellar,
453 policies: Some(RelayerNetworkPolicy::Stellar(RelayerStellarPolicy {
454 min_balance: Some(30000000),
455 max_fee: Some(150000),
456 timeout_seconds: Some(60),
457 concurrent_transactions: None,
458 })),
459 signer_id: "test_signer".to_string(),
460 notification_id: None,
461 custom_rpc_urls: None,
462 };
463
464 let repo_model = RelayerRepoModel::from(domain_relayer.clone());
465
466 assert_eq!(repo_model.network_type, RelayerNetworkType::Stellar);
467
468 if let RelayerNetworkPolicy::Stellar(stellar_policy) = repo_model.policies {
470 assert_eq!(stellar_policy.min_balance, Some(30000000));
471 assert_eq!(stellar_policy.max_fee, Some(150000));
472 assert_eq!(stellar_policy.timeout_seconds, Some(60));
473 } else {
474 panic!("Expected Stellar policy");
475 }
476 }
477
478 #[test]
479 fn test_conversion_from_domain_with_no_policies_evm() {
480 let domain_relayer = Relayer {
481 id: "test_evm_relayer".to_string(),
482 name: "Test EVM Relayer".to_string(),
483 network: "mainnet".to_string(),
484 paused: false,
485 network_type: RelayerNetworkType::Evm,
486 policies: None, signer_id: "test_signer".to_string(),
488 notification_id: None,
489 custom_rpc_urls: None,
490 };
491
492 let repo_model = RelayerRepoModel::from(domain_relayer);
493
494 if let RelayerNetworkPolicy::Evm(evm_policy) = repo_model.policies {
496 assert_eq!(evm_policy.gas_price_cap, None);
498 assert_eq!(evm_policy.eip1559_pricing, None);
499 assert_eq!(evm_policy.min_balance, None);
500 assert_eq!(evm_policy.gas_limit_estimation, None);
501 assert_eq!(evm_policy.whitelist_receivers, None);
502 assert_eq!(evm_policy.private_transactions, None);
503 } else {
504 panic!("Expected default EVM policy");
505 }
506 }
507
508 #[test]
509 fn test_conversion_from_domain_with_no_policies_solana() {
510 let domain_relayer = Relayer {
511 id: "test_solana_relayer".to_string(),
512 name: "Test Solana Relayer".to_string(),
513 network: "mainnet".to_string(),
514 paused: false,
515 network_type: RelayerNetworkType::Solana,
516 policies: None, signer_id: "test_signer".to_string(),
518 notification_id: None,
519 custom_rpc_urls: None,
520 };
521
522 let repo_model = RelayerRepoModel::from(domain_relayer);
523
524 if let RelayerNetworkPolicy::Solana(solana_policy) = repo_model.policies {
526 assert_eq!(solana_policy.fee_payment_strategy, None);
528 assert_eq!(solana_policy.min_balance, None);
529 assert_eq!(solana_policy.max_signatures, None);
530 assert_eq!(solana_policy.allowed_tokens, None);
531 assert_eq!(solana_policy.allowed_programs, None);
532 assert_eq!(solana_policy.allowed_accounts, None);
533 assert_eq!(solana_policy.disallowed_accounts, None);
534 assert_eq!(solana_policy.max_tx_data_size, None);
535 assert_eq!(solana_policy.max_allowed_fee_lamports, None);
536 assert_eq!(solana_policy.swap_config, None);
537 assert_eq!(solana_policy.fee_margin_percentage, None);
538 } else {
539 panic!("Expected default Solana policy");
540 }
541 }
542
543 #[test]
544 fn test_conversion_from_domain_with_no_policies_stellar() {
545 let domain_relayer = Relayer {
546 id: "test_stellar_relayer".to_string(),
547 name: "Test Stellar Relayer".to_string(),
548 network: "mainnet".to_string(),
549 paused: false,
550 network_type: RelayerNetworkType::Stellar,
551 policies: None, signer_id: "test_signer".to_string(),
553 notification_id: None,
554 custom_rpc_urls: None,
555 };
556
557 let repo_model = RelayerRepoModel::from(domain_relayer);
558
559 if let RelayerNetworkPolicy::Stellar(stellar_policy) = repo_model.policies {
561 assert_eq!(stellar_policy.min_balance, None);
563 assert_eq!(stellar_policy.max_fee, None);
564 assert_eq!(stellar_policy.timeout_seconds, None);
565 } else {
566 panic!("Expected default Stellar policy");
567 }
568 }
569
570 #[test]
571 fn test_relayer_repo_updater_preserves_runtime_fields() {
572 let original = RelayerRepoModel {
574 id: "test_relayer".to_string(),
575 name: "Original Name".to_string(),
576 address: "0x742d35Cc6634C0532925a3b8D8C2e48a73F6ba2E".to_string(), system_disabled: true, disabled_reason: Some(DisabledReason::BalanceCheckFailed(
579 "Balance too low".to_string(),
580 )), paused: false,
582 network: "mainnet".to_string(),
583 network_type: NetworkType::Evm,
584 signer_id: "test_signer".to_string(),
585 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default()),
586 notification_id: None,
587 custom_rpc_urls: None,
588 };
589
590 let domain_update = Relayer {
592 id: "test_relayer".to_string(),
593 name: "Updated Name".to_string(), paused: true, network: "mainnet".to_string(),
596 network_type: RelayerNetworkType::Evm,
597 signer_id: "test_signer".to_string(),
598 policies: Some(RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default())),
599 notification_id: Some("new_notification".to_string()), custom_rpc_urls: None,
601 };
602
603 let updated =
605 RelayerRepoUpdater::from_existing(original.clone()).apply_domain_update(domain_update);
606
607 assert_eq!(updated.name, "Updated Name");
609 assert!(updated.paused);
610 assert_eq!(
611 updated.notification_id,
612 Some("new_notification".to_string())
613 );
614
615 assert_eq!(
617 updated.address,
618 "0x742d35Cc6634C0532925a3b8D8C2e48a73F6ba2E"
619 );
620 assert!(updated.system_disabled);
621 assert_eq!(
622 updated.disabled_reason,
623 Some(DisabledReason::BalanceCheckFailed(
624 "Balance too low".to_string()
625 ))
626 );
627 }
628
629 #[test]
630 fn test_relayer_repo_updater_preserves_runtime_fields_solana() {
631 let original = RelayerRepoModel {
633 id: "test_solana_relayer".to_string(),
634 name: "Original Solana Name".to_string(),
635 address: "SolanaOriginalAddress123".to_string(), system_disabled: true, disabled_reason: Some(DisabledReason::RpcValidationFailed(
638 "RPC check failed".to_string(),
639 )), paused: false,
641 network: "mainnet".to_string(),
642 network_type: NetworkType::Solana,
643 signer_id: "test_signer".to_string(),
644 policies: RelayerNetworkPolicy::Solana(RelayerSolanaPolicy::default()),
645 notification_id: None,
646 custom_rpc_urls: None,
647 };
648
649 let domain_update = Relayer {
651 id: "test_solana_relayer".to_string(),
652 name: "Updated Solana Name".to_string(), paused: true, network: "mainnet".to_string(),
655 network_type: RelayerNetworkType::Solana,
656 signer_id: "test_signer".to_string(),
657 policies: Some(RelayerNetworkPolicy::Solana(RelayerSolanaPolicy {
658 min_balance: Some(2000000), ..RelayerSolanaPolicy::default()
660 })),
661 notification_id: Some("solana_notification".to_string()), custom_rpc_urls: None,
663 };
664
665 let updated =
667 RelayerRepoUpdater::from_existing(original.clone()).apply_domain_update(domain_update);
668
669 assert_eq!(updated.name, "Updated Solana Name");
671 assert!(updated.paused);
672 assert_eq!(
673 updated.notification_id,
674 Some("solana_notification".to_string())
675 );
676
677 assert_eq!(updated.address, "SolanaOriginalAddress123");
679 assert!(updated.system_disabled);
680 assert_eq!(
681 updated.disabled_reason,
682 Some(DisabledReason::RpcValidationFailed(
683 "RPC check failed".to_string()
684 ))
685 );
686
687 if let RelayerNetworkPolicy::Solana(solana_policy) = updated.policies {
689 assert_eq!(solana_policy.min_balance, Some(2000000));
690 } else {
691 panic!("Expected Solana policy");
692 }
693 }
694
695 #[test]
696 fn test_relayer_repo_updater_preserves_runtime_fields_stellar() {
697 let original = RelayerRepoModel {
699 id: "test_stellar_relayer".to_string(),
700 name: "Original Stellar Name".to_string(),
701 address: "GORIGINALXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".to_string(), system_disabled: false, disabled_reason: None, paused: true,
705 network: "mainnet".to_string(),
706 network_type: NetworkType::Stellar,
707 signer_id: "test_signer".to_string(),
708 policies: RelayerNetworkPolicy::Stellar(RelayerStellarPolicy::default()),
709 notification_id: Some("original_notification".to_string()),
710 custom_rpc_urls: None,
711 };
712
713 let domain_update = Relayer {
715 id: "test_stellar_relayer".to_string(),
716 name: "Updated Stellar Name".to_string(), paused: false, network: "mainnet".to_string(),
719 network_type: RelayerNetworkType::Stellar,
720 signer_id: "test_signer".to_string(),
721 policies: Some(RelayerNetworkPolicy::Stellar(RelayerStellarPolicy {
722 min_balance: Some(40000000), max_fee: Some(200000), timeout_seconds: Some(120), concurrent_transactions: None,
726 })),
727 notification_id: None, custom_rpc_urls: None,
729 };
730
731 let updated =
733 RelayerRepoUpdater::from_existing(original.clone()).apply_domain_update(domain_update);
734
735 assert_eq!(updated.name, "Updated Stellar Name");
737 assert!(!updated.paused);
738 assert_eq!(updated.notification_id, None);
739
740 assert_eq!(
742 updated.address,
743 "GORIGINALXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
744 );
745 assert!(!updated.system_disabled);
746 assert_eq!(updated.disabled_reason, None);
747
748 if let RelayerNetworkPolicy::Stellar(stellar_policy) = updated.policies {
750 assert_eq!(stellar_policy.min_balance, Some(40000000));
751 assert_eq!(stellar_policy.max_fee, Some(200000));
752 assert_eq!(stellar_policy.timeout_seconds, Some(120));
753 } else {
754 panic!("Expected Stellar policy");
755 }
756 }
757
758 #[test]
759 fn test_repo_model_serialization_deserialization_evm() {
760 let original = create_test_relayer(false, false);
761
762 let serialized = serde_json::to_string(&original).unwrap();
764 assert!(!serialized.is_empty());
765
766 let deserialized: RelayerRepoModel = serde_json::from_str(&serialized).unwrap();
768
769 assert_eq!(original.id, deserialized.id);
771 assert_eq!(original.name, deserialized.name);
772 assert_eq!(original.network, deserialized.network);
773 assert_eq!(original.paused, deserialized.paused);
774 assert_eq!(original.network_type, deserialized.network_type);
775 assert_eq!(original.signer_id, deserialized.signer_id);
776 assert_eq!(original.address, deserialized.address);
777 assert_eq!(original.notification_id, deserialized.notification_id);
778 assert_eq!(original.system_disabled, deserialized.system_disabled);
779 assert_eq!(original.custom_rpc_urls, deserialized.custom_rpc_urls);
780
781 match (&original.policies, &deserialized.policies) {
783 (RelayerNetworkPolicy::Evm(_), RelayerNetworkPolicy::Evm(_)) => {
784 }
786 _ => panic!("Policy types don't match after serialization/deserialization"),
787 }
788 }
789
790 #[test]
791 fn test_repo_model_serialization_deserialization_solana() {
792 let original = create_test_relayer_solana(true, false);
793
794 let serialized = serde_json::to_string(&original).unwrap();
796 assert!(!serialized.is_empty());
797
798 let deserialized: RelayerRepoModel = serde_json::from_str(&serialized).unwrap();
800
801 assert_eq!(original.id, deserialized.id);
803 assert_eq!(original.network_type, RelayerNetworkType::Solana);
804 assert_eq!(deserialized.network_type, RelayerNetworkType::Solana);
805 assert_eq!(original.paused, deserialized.paused);
806
807 match (&original.policies, &deserialized.policies) {
809 (RelayerNetworkPolicy::Solana(orig), RelayerNetworkPolicy::Solana(deser)) => {
810 assert_eq!(orig.fee_payment_strategy, deser.fee_payment_strategy);
811 assert_eq!(orig.min_balance, deser.min_balance);
812 assert_eq!(orig.max_signatures, deser.max_signatures);
813 }
814 _ => panic!("Policy types don't match after serialization/deserialization"),
815 }
816 }
817
818 #[test]
819 fn test_repo_model_serialization_deserialization_stellar() {
820 let original = create_test_relayer_stellar(false, true);
821
822 let serialized = serde_json::to_string(&original).unwrap();
824 assert!(!serialized.is_empty());
825
826 let deserialized: RelayerRepoModel = serde_json::from_str(&serialized).unwrap();
828
829 assert_eq!(original.id, deserialized.id);
831 assert_eq!(original.network_type, RelayerNetworkType::Stellar);
832 assert_eq!(deserialized.network_type, RelayerNetworkType::Stellar);
833 assert_eq!(original.system_disabled, deserialized.system_disabled);
834
835 match (&original.policies, &deserialized.policies) {
837 (RelayerNetworkPolicy::Stellar(orig), RelayerNetworkPolicy::Stellar(deser)) => {
838 assert_eq!(orig.min_balance, deser.min_balance);
839 assert_eq!(orig.max_fee, deser.max_fee);
840 assert_eq!(orig.timeout_seconds, deser.timeout_seconds);
841 }
842 _ => panic!("Policy types don't match after serialization/deserialization"),
843 }
844 }
845
846 #[test]
847 fn test_repo_model_default() {
848 let default_model = RelayerRepoModel::default();
849
850 assert_eq!(default_model.id, "");
851 assert_eq!(default_model.name, "");
852 assert_eq!(default_model.network, "");
853 assert!(!default_model.paused);
854 assert_eq!(default_model.network_type, NetworkType::Evm);
855 assert_eq!(default_model.signer_id, "");
856 assert_eq!(default_model.address, "0x");
857 assert_eq!(default_model.notification_id, None);
858 assert!(!default_model.system_disabled);
859 assert_eq!(default_model.custom_rpc_urls, None);
860
861 if let RelayerNetworkPolicy::Evm(_) = default_model.policies {
863 } else {
865 panic!("Default should have EVM policy");
866 }
867 }
868
869 #[test]
870 fn test_round_trip_conversion_all_network_types() {
871 let original_evm = Relayer {
875 id: "evm_relayer".to_string(),
876 name: "EVM Relayer".to_string(),
877 network: "mainnet".to_string(),
878 paused: false,
879 network_type: RelayerNetworkType::Evm,
880 policies: Some(RelayerNetworkPolicy::Evm(RelayerEvmPolicy {
881 gas_price_cap: Some(50_000_000_000),
882 eip1559_pricing: Some(true),
883 min_balance: None,
884 gas_limit_estimation: None,
885 whitelist_receivers: None,
886 private_transactions: None,
887 })),
888 signer_id: "evm_signer".to_string(),
889 notification_id: Some("evm_notification".to_string()),
890 custom_rpc_urls: None,
891 };
892
893 let repo_evm = RelayerRepoModel::from(original_evm.clone());
894 let recovered_evm = Relayer::from(repo_evm);
895
896 assert_eq!(original_evm.id, recovered_evm.id);
897 assert_eq!(original_evm.network_type, recovered_evm.network_type);
898 assert_eq!(original_evm.notification_id, recovered_evm.notification_id);
899
900 let original_solana = Relayer {
902 id: "solana_relayer".to_string(),
903 name: "Solana Relayer".to_string(),
904 network: "mainnet".to_string(),
905 paused: true,
906 network_type: RelayerNetworkType::Solana,
907 policies: Some(RelayerNetworkPolicy::Solana(RelayerSolanaPolicy {
908 fee_payment_strategy: Some(SolanaFeePaymentStrategy::User),
909 min_balance: Some(3000000),
910 max_signatures: None,
911 allowed_tokens: None,
912 allowed_programs: None,
913 allowed_accounts: None,
914 disallowed_accounts: None,
915 max_tx_data_size: None,
916 max_allowed_fee_lamports: None,
917 swap_config: None,
918 fee_margin_percentage: None,
919 })),
920 signer_id: "solana_signer".to_string(),
921 notification_id: None,
922 custom_rpc_urls: None,
923 };
924
925 let repo_solana = RelayerRepoModel::from(original_solana.clone());
926 let recovered_solana = Relayer::from(repo_solana);
927
928 assert_eq!(original_solana.id, recovered_solana.id);
929 assert_eq!(original_solana.network_type, recovered_solana.network_type);
930 assert_eq!(original_solana.paused, recovered_solana.paused);
931
932 let original_stellar = Relayer {
934 id: "stellar_relayer".to_string(),
935 name: "Stellar Relayer".to_string(),
936 network: "mainnet".to_string(),
937 paused: false,
938 network_type: RelayerNetworkType::Stellar,
939 policies: Some(RelayerNetworkPolicy::Stellar(RelayerStellarPolicy {
940 min_balance: Some(50000000),
941 max_fee: Some(250000),
942 timeout_seconds: Some(180),
943 concurrent_transactions: None,
944 })),
945 signer_id: "stellar_signer".to_string(),
946 notification_id: Some("stellar_notification".to_string()),
947 custom_rpc_urls: None,
948 };
949
950 let repo_stellar = RelayerRepoModel::from(original_stellar.clone());
951 let recovered_stellar = Relayer::from(repo_stellar);
952
953 assert_eq!(original_stellar.id, recovered_stellar.id);
954 assert_eq!(
955 original_stellar.network_type,
956 recovered_stellar.network_type
957 );
958 assert_eq!(
959 original_stellar.notification_id,
960 recovered_stellar.notification_id
961 );
962 }
963}