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, StellarFeePaymentStrategy,
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 allowed_tokens: None,
206 fee_payment_strategy: Some(StellarFeePaymentStrategy::Relayer),
207 slippage_percentage: None,
208 fee_margin_percentage: None,
209 swap_config: None,
210 }),
211 address: "GXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".to_string(),
212 notification_id: None,
213 custom_rpc_urls: None,
214 ..Default::default()
215 }
216 }
217
218 #[test]
219 fn test_validate_active_state_success() {
220 let relayer = create_test_relayer(false, false);
221 assert!(relayer.validate_active_state().is_ok());
222 }
223
224 #[test]
225 fn test_validate_active_state_success_solana() {
226 let relayer = create_test_relayer_solana(false, false);
227 assert!(relayer.validate_active_state().is_ok());
228 }
229
230 #[test]
231 fn test_validate_active_state_success_stellar() {
232 let relayer = create_test_relayer_stellar(false, false);
233 assert!(relayer.validate_active_state().is_ok());
234 }
235
236 #[test]
237 fn test_validate_active_state_paused() {
238 let relayer = create_test_relayer(true, false);
239 let result = relayer.validate_active_state();
240 assert!(result.is_err());
241 assert!(matches!(result.unwrap_err(), RelayerError::RelayerPaused));
242 }
243
244 #[test]
245 fn test_validate_active_state_paused_solana() {
246 let relayer = create_test_relayer_solana(true, false);
247 let result = relayer.validate_active_state();
248 assert!(result.is_err());
249 assert!(matches!(result.unwrap_err(), RelayerError::RelayerPaused));
250 }
251
252 #[test]
253 fn test_validate_active_state_paused_stellar() {
254 let relayer = create_test_relayer_stellar(true, false);
255 let result = relayer.validate_active_state();
256 assert!(result.is_err());
257 assert!(matches!(result.unwrap_err(), RelayerError::RelayerPaused));
258 }
259
260 #[test]
261 fn test_validate_active_state_disabled() {
262 let relayer = create_test_relayer(false, true);
263 let result = relayer.validate_active_state();
264 assert!(result.is_err());
265 assert!(matches!(result.unwrap_err(), RelayerError::RelayerDisabled));
266 }
267
268 #[test]
269 fn test_validate_active_state_disabled_solana() {
270 let relayer = create_test_relayer_solana(false, true);
271 let result = relayer.validate_active_state();
272 assert!(result.is_err());
273 assert!(matches!(result.unwrap_err(), RelayerError::RelayerDisabled));
274 }
275
276 #[test]
277 fn test_validate_active_state_disabled_stellar() {
278 let relayer = create_test_relayer_stellar(false, true);
279 let result = relayer.validate_active_state();
280 assert!(result.is_err());
281 assert!(matches!(result.unwrap_err(), RelayerError::RelayerDisabled));
282 }
283
284 #[test]
285 fn test_validate_active_state_both_paused_and_disabled() {
286 let relayer = create_test_relayer(true, true);
288 let result = relayer.validate_active_state();
289 assert!(result.is_err());
290 assert!(matches!(result.unwrap_err(), RelayerError::RelayerPaused));
291 }
292
293 #[test]
294 fn test_conversion_from_repo_model_to_domain_evm() {
295 let repo_model = create_test_relayer(false, false);
296 let domain_relayer = Relayer::from(repo_model.clone());
297
298 assert_eq!(domain_relayer.id, repo_model.id);
299 assert_eq!(domain_relayer.name, repo_model.name);
300 assert_eq!(domain_relayer.network, repo_model.network);
301 assert_eq!(domain_relayer.paused, repo_model.paused);
302 assert_eq!(domain_relayer.network_type, repo_model.network_type);
303 assert_eq!(domain_relayer.signer_id, repo_model.signer_id);
304 assert_eq!(domain_relayer.notification_id, repo_model.notification_id);
305 assert_eq!(domain_relayer.custom_rpc_urls, repo_model.custom_rpc_urls);
306
307 assert!(domain_relayer.policies.is_some());
309 if let Some(RelayerNetworkPolicy::Evm(_)) = domain_relayer.policies {
310 } else {
312 panic!("Expected EVM policy");
313 }
314 }
315
316 #[test]
317 fn test_conversion_from_repo_model_to_domain_solana() {
318 let repo_model = create_test_relayer_solana(false, false);
319 let domain_relayer = Relayer::from(repo_model.clone());
320
321 assert_eq!(domain_relayer.id, repo_model.id);
322 assert_eq!(domain_relayer.network_type, RelayerNetworkType::Solana);
323
324 assert!(domain_relayer.policies.is_some());
326 if let Some(RelayerNetworkPolicy::Solana(solana_policy)) = domain_relayer.policies {
327 assert_eq!(solana_policy.min_balance, Some(1000000));
328 assert_eq!(solana_policy.max_signatures, Some(5));
329 assert_eq!(
330 solana_policy.fee_payment_strategy,
331 Some(SolanaFeePaymentStrategy::Relayer)
332 );
333 } else {
334 panic!("Expected Solana policy");
335 }
336 }
337
338 #[test]
339 fn test_conversion_from_repo_model_to_domain_stellar() {
340 let repo_model = create_test_relayer_stellar(false, false);
341 let domain_relayer = Relayer::from(repo_model.clone());
342
343 assert_eq!(domain_relayer.id, repo_model.id);
344 assert_eq!(domain_relayer.network_type, RelayerNetworkType::Stellar);
345
346 assert!(domain_relayer.policies.is_some());
348 if let Some(RelayerNetworkPolicy::Stellar(stellar_policy)) = domain_relayer.policies {
349 assert_eq!(stellar_policy.min_balance, Some(20000000));
350 assert_eq!(stellar_policy.max_fee, Some(100000));
351 assert_eq!(stellar_policy.timeout_seconds, Some(30));
352 } else {
353 panic!("Expected Stellar policy");
354 }
355 }
356
357 #[test]
358 fn test_conversion_from_domain_to_repo_model_evm() {
359 let domain_relayer = Relayer {
360 id: "test_evm_relayer".to_string(),
361 name: "Test EVM Relayer".to_string(),
362 network: "mainnet".to_string(),
363 paused: false,
364 network_type: RelayerNetworkType::Evm,
365 policies: Some(RelayerNetworkPolicy::Evm(RelayerEvmPolicy {
366 gas_price_cap: Some(100_000_000_000),
367 eip1559_pricing: Some(true),
368 min_balance: None,
369 gas_limit_estimation: None,
370 whitelist_receivers: None,
371 private_transactions: None,
372 })),
373 signer_id: "test_signer".to_string(),
374 notification_id: Some("notification_123".to_string()),
375 custom_rpc_urls: None,
376 };
377
378 let repo_model = RelayerRepoModel::from(domain_relayer.clone());
379
380 assert_eq!(repo_model.id, domain_relayer.id);
381 assert_eq!(repo_model.name, domain_relayer.name);
382 assert_eq!(repo_model.network, domain_relayer.network);
383 assert_eq!(repo_model.paused, domain_relayer.paused);
384 assert_eq!(repo_model.network_type, domain_relayer.network_type);
385 assert_eq!(repo_model.signer_id, domain_relayer.signer_id);
386 assert_eq!(repo_model.notification_id, domain_relayer.notification_id);
387 assert_eq!(repo_model.custom_rpc_urls, domain_relayer.custom_rpc_urls);
388
389 assert_eq!(repo_model.address, "");
391 assert!(!repo_model.system_disabled);
392
393 if let RelayerNetworkPolicy::Evm(evm_policy) = repo_model.policies {
395 assert_eq!(evm_policy.gas_price_cap, Some(100_000_000_000));
396 assert_eq!(evm_policy.eip1559_pricing, Some(true));
397 } else {
398 panic!("Expected EVM policy");
399 }
400 }
401
402 #[test]
403 fn test_conversion_from_domain_to_repo_model_solana() {
404 let domain_relayer = Relayer {
405 id: "test_solana_relayer".to_string(),
406 name: "Test Solana Relayer".to_string(),
407 network: "mainnet".to_string(),
408 paused: false,
409 network_type: RelayerNetworkType::Solana,
410 policies: Some(RelayerNetworkPolicy::Solana(RelayerSolanaPolicy {
411 fee_payment_strategy: Some(SolanaFeePaymentStrategy::User),
412 min_balance: Some(5000000),
413 max_signatures: Some(8),
414 allowed_tokens: Some(vec![SolanaAllowedTokensPolicy::new(
415 "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v".to_string(),
416 Some(100000),
417 None,
418 )]),
419 allowed_programs: None,
420 allowed_accounts: None,
421 disallowed_accounts: None,
422 max_tx_data_size: None,
423 max_allowed_fee_lamports: None,
424 swap_config: None,
425 fee_margin_percentage: None,
426 })),
427 signer_id: "test_signer".to_string(),
428 notification_id: None,
429 custom_rpc_urls: None,
430 };
431
432 let repo_model = RelayerRepoModel::from(domain_relayer.clone());
433
434 assert_eq!(repo_model.network_type, RelayerNetworkType::Solana);
435
436 if let RelayerNetworkPolicy::Solana(solana_policy) = repo_model.policies {
438 assert_eq!(
439 solana_policy.fee_payment_strategy,
440 Some(SolanaFeePaymentStrategy::User)
441 );
442 assert_eq!(solana_policy.min_balance, Some(5000000));
443 assert_eq!(solana_policy.max_signatures, Some(8));
444 assert!(solana_policy.allowed_tokens.is_some());
445 } else {
446 panic!("Expected Solana policy");
447 }
448 }
449
450 #[test]
451 fn test_conversion_from_domain_to_repo_model_stellar() {
452 let domain_relayer = Relayer {
453 id: "test_stellar_relayer".to_string(),
454 name: "Test Stellar Relayer".to_string(),
455 network: "mainnet".to_string(),
456 paused: false,
457 network_type: RelayerNetworkType::Stellar,
458 policies: Some(RelayerNetworkPolicy::Stellar(RelayerStellarPolicy {
459 min_balance: Some(30000000),
460 max_fee: Some(150000),
461 timeout_seconds: Some(60),
462 concurrent_transactions: None,
463 allowed_tokens: None,
464 fee_payment_strategy: Some(StellarFeePaymentStrategy::Relayer),
465 slippage_percentage: None,
466 fee_margin_percentage: None,
467 swap_config: None,
468 })),
469 signer_id: "test_signer".to_string(),
470 notification_id: None,
471 custom_rpc_urls: None,
472 };
473
474 let repo_model = RelayerRepoModel::from(domain_relayer.clone());
475
476 assert_eq!(repo_model.network_type, RelayerNetworkType::Stellar);
477
478 if let RelayerNetworkPolicy::Stellar(stellar_policy) = repo_model.policies {
480 assert_eq!(stellar_policy.min_balance, Some(30000000));
481 assert_eq!(stellar_policy.max_fee, Some(150000));
482 assert_eq!(stellar_policy.timeout_seconds, Some(60));
483 } else {
484 panic!("Expected Stellar policy");
485 }
486 }
487
488 #[test]
489 fn test_conversion_from_domain_with_no_policies_evm() {
490 let domain_relayer = Relayer {
491 id: "test_evm_relayer".to_string(),
492 name: "Test EVM Relayer".to_string(),
493 network: "mainnet".to_string(),
494 paused: false,
495 network_type: RelayerNetworkType::Evm,
496 policies: None, signer_id: "test_signer".to_string(),
498 notification_id: None,
499 custom_rpc_urls: None,
500 };
501
502 let repo_model = RelayerRepoModel::from(domain_relayer);
503
504 if let RelayerNetworkPolicy::Evm(evm_policy) = repo_model.policies {
506 assert_eq!(evm_policy.gas_price_cap, None);
508 assert_eq!(evm_policy.eip1559_pricing, None);
509 assert_eq!(evm_policy.min_balance, None);
510 assert_eq!(evm_policy.gas_limit_estimation, None);
511 assert_eq!(evm_policy.whitelist_receivers, None);
512 assert_eq!(evm_policy.private_transactions, None);
513 } else {
514 panic!("Expected default EVM policy");
515 }
516 }
517
518 #[test]
519 fn test_conversion_from_domain_with_no_policies_solana() {
520 let domain_relayer = Relayer {
521 id: "test_solana_relayer".to_string(),
522 name: "Test Solana Relayer".to_string(),
523 network: "mainnet".to_string(),
524 paused: false,
525 network_type: RelayerNetworkType::Solana,
526 policies: None, signer_id: "test_signer".to_string(),
528 notification_id: None,
529 custom_rpc_urls: None,
530 };
531
532 let repo_model = RelayerRepoModel::from(domain_relayer);
533
534 if let RelayerNetworkPolicy::Solana(solana_policy) = repo_model.policies {
536 assert_eq!(solana_policy.fee_payment_strategy, None);
538 assert_eq!(solana_policy.min_balance, None);
539 assert_eq!(solana_policy.max_signatures, None);
540 assert_eq!(solana_policy.allowed_tokens, None);
541 assert_eq!(solana_policy.allowed_programs, None);
542 assert_eq!(solana_policy.allowed_accounts, None);
543 assert_eq!(solana_policy.disallowed_accounts, None);
544 assert_eq!(solana_policy.max_tx_data_size, None);
545 assert_eq!(solana_policy.max_allowed_fee_lamports, None);
546 assert_eq!(solana_policy.swap_config, None);
547 assert_eq!(solana_policy.fee_margin_percentage, None);
548 } else {
549 panic!("Expected default Solana policy");
550 }
551 }
552
553 #[test]
554 fn test_conversion_from_domain_with_no_policies_stellar() {
555 let domain_relayer = Relayer {
556 id: "test_stellar_relayer".to_string(),
557 name: "Test Stellar Relayer".to_string(),
558 network: "mainnet".to_string(),
559 paused: false,
560 network_type: RelayerNetworkType::Stellar,
561 policies: None, signer_id: "test_signer".to_string(),
563 notification_id: None,
564 custom_rpc_urls: None,
565 };
566
567 let repo_model = RelayerRepoModel::from(domain_relayer);
568
569 if let RelayerNetworkPolicy::Stellar(stellar_policy) = repo_model.policies {
571 assert_eq!(stellar_policy.min_balance, None);
573 assert_eq!(stellar_policy.max_fee, None);
574 assert_eq!(stellar_policy.timeout_seconds, None);
575 } else {
576 panic!("Expected default Stellar policy");
577 }
578 }
579
580 #[test]
581 fn test_relayer_repo_updater_preserves_runtime_fields() {
582 let original = RelayerRepoModel {
584 id: "test_relayer".to_string(),
585 name: "Original Name".to_string(),
586 address: "0x742d35Cc6634C0532925a3b8D8C2e48a73F6ba2E".to_string(), system_disabled: true, disabled_reason: Some(DisabledReason::BalanceCheckFailed(
589 "Balance too low".to_string(),
590 )), paused: false,
592 network: "mainnet".to_string(),
593 network_type: NetworkType::Evm,
594 signer_id: "test_signer".to_string(),
595 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default()),
596 notification_id: None,
597 custom_rpc_urls: None,
598 };
599
600 let domain_update = Relayer {
602 id: "test_relayer".to_string(),
603 name: "Updated Name".to_string(), paused: true, network: "mainnet".to_string(),
606 network_type: RelayerNetworkType::Evm,
607 signer_id: "test_signer".to_string(),
608 policies: Some(RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default())),
609 notification_id: Some("new_notification".to_string()), custom_rpc_urls: None,
611 };
612
613 let updated =
615 RelayerRepoUpdater::from_existing(original.clone()).apply_domain_update(domain_update);
616
617 assert_eq!(updated.name, "Updated Name");
619 assert!(updated.paused);
620 assert_eq!(
621 updated.notification_id,
622 Some("new_notification".to_string())
623 );
624
625 assert_eq!(
627 updated.address,
628 "0x742d35Cc6634C0532925a3b8D8C2e48a73F6ba2E"
629 );
630 assert!(updated.system_disabled);
631 assert_eq!(
632 updated.disabled_reason,
633 Some(DisabledReason::BalanceCheckFailed(
634 "Balance too low".to_string()
635 ))
636 );
637 }
638
639 #[test]
640 fn test_relayer_repo_updater_preserves_runtime_fields_solana() {
641 let original = RelayerRepoModel {
643 id: "test_solana_relayer".to_string(),
644 name: "Original Solana Name".to_string(),
645 address: "SolanaOriginalAddress123".to_string(), system_disabled: true, disabled_reason: Some(DisabledReason::RpcValidationFailed(
648 "RPC check failed".to_string(),
649 )), paused: false,
651 network: "mainnet".to_string(),
652 network_type: NetworkType::Solana,
653 signer_id: "test_signer".to_string(),
654 policies: RelayerNetworkPolicy::Solana(RelayerSolanaPolicy::default()),
655 notification_id: None,
656 custom_rpc_urls: None,
657 };
658
659 let domain_update = Relayer {
661 id: "test_solana_relayer".to_string(),
662 name: "Updated Solana Name".to_string(), paused: true, network: "mainnet".to_string(),
665 network_type: RelayerNetworkType::Solana,
666 signer_id: "test_signer".to_string(),
667 policies: Some(RelayerNetworkPolicy::Solana(RelayerSolanaPolicy {
668 min_balance: Some(2000000), ..RelayerSolanaPolicy::default()
670 })),
671 notification_id: Some("solana_notification".to_string()), custom_rpc_urls: None,
673 };
674
675 let updated =
677 RelayerRepoUpdater::from_existing(original.clone()).apply_domain_update(domain_update);
678
679 assert_eq!(updated.name, "Updated Solana Name");
681 assert!(updated.paused);
682 assert_eq!(
683 updated.notification_id,
684 Some("solana_notification".to_string())
685 );
686
687 assert_eq!(updated.address, "SolanaOriginalAddress123");
689 assert!(updated.system_disabled);
690 assert_eq!(
691 updated.disabled_reason,
692 Some(DisabledReason::RpcValidationFailed(
693 "RPC check failed".to_string()
694 ))
695 );
696
697 if let RelayerNetworkPolicy::Solana(solana_policy) = updated.policies {
699 assert_eq!(solana_policy.min_balance, Some(2000000));
700 } else {
701 panic!("Expected Solana policy");
702 }
703 }
704
705 #[test]
706 fn test_relayer_repo_updater_preserves_runtime_fields_stellar() {
707 let original = RelayerRepoModel {
709 id: "test_stellar_relayer".to_string(),
710 name: "Original Stellar Name".to_string(),
711 address: "GORIGINALXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".to_string(), system_disabled: false, disabled_reason: None, paused: true,
715 network: "mainnet".to_string(),
716 network_type: NetworkType::Stellar,
717 signer_id: "test_signer".to_string(),
718 policies: RelayerNetworkPolicy::Stellar(RelayerStellarPolicy::default()),
719 notification_id: Some("original_notification".to_string()),
720 custom_rpc_urls: None,
721 };
722
723 let domain_update = Relayer {
725 id: "test_stellar_relayer".to_string(),
726 name: "Updated Stellar Name".to_string(), paused: false, network: "mainnet".to_string(),
729 network_type: RelayerNetworkType::Stellar,
730 signer_id: "test_signer".to_string(),
731 policies: Some(RelayerNetworkPolicy::Stellar(RelayerStellarPolicy {
732 min_balance: Some(40000000), max_fee: Some(200000), timeout_seconds: Some(120), concurrent_transactions: None,
736 allowed_tokens: None,
737 fee_payment_strategy: Some(StellarFeePaymentStrategy::Relayer),
738 slippage_percentage: None,
739 fee_margin_percentage: None,
740 swap_config: None,
741 })),
742 notification_id: None, custom_rpc_urls: None,
744 };
745
746 let updated =
748 RelayerRepoUpdater::from_existing(original.clone()).apply_domain_update(domain_update);
749
750 assert_eq!(updated.name, "Updated Stellar Name");
752 assert!(!updated.paused);
753 assert_eq!(updated.notification_id, None);
754
755 assert_eq!(
757 updated.address,
758 "GORIGINALXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
759 );
760 assert!(!updated.system_disabled);
761 assert_eq!(updated.disabled_reason, None);
762
763 if let RelayerNetworkPolicy::Stellar(stellar_policy) = updated.policies {
765 assert_eq!(stellar_policy.min_balance, Some(40000000));
766 assert_eq!(stellar_policy.max_fee, Some(200000));
767 assert_eq!(stellar_policy.timeout_seconds, Some(120));
768 } else {
769 panic!("Expected Stellar policy");
770 }
771 }
772
773 #[test]
774 fn test_repo_model_serialization_deserialization_evm() {
775 let original = create_test_relayer(false, false);
776
777 let serialized = serde_json::to_string(&original).unwrap();
779 assert!(!serialized.is_empty());
780
781 let deserialized: RelayerRepoModel = serde_json::from_str(&serialized).unwrap();
783
784 assert_eq!(original.id, deserialized.id);
786 assert_eq!(original.name, deserialized.name);
787 assert_eq!(original.network, deserialized.network);
788 assert_eq!(original.paused, deserialized.paused);
789 assert_eq!(original.network_type, deserialized.network_type);
790 assert_eq!(original.signer_id, deserialized.signer_id);
791 assert_eq!(original.address, deserialized.address);
792 assert_eq!(original.notification_id, deserialized.notification_id);
793 assert_eq!(original.system_disabled, deserialized.system_disabled);
794 assert_eq!(original.custom_rpc_urls, deserialized.custom_rpc_urls);
795
796 match (&original.policies, &deserialized.policies) {
798 (RelayerNetworkPolicy::Evm(_), RelayerNetworkPolicy::Evm(_)) => {
799 }
801 _ => panic!("Policy types don't match after serialization/deserialization"),
802 }
803 }
804
805 #[test]
806 fn test_repo_model_serialization_deserialization_solana() {
807 let original = create_test_relayer_solana(true, false);
808
809 let serialized = serde_json::to_string(&original).unwrap();
811 assert!(!serialized.is_empty());
812
813 let deserialized: RelayerRepoModel = serde_json::from_str(&serialized).unwrap();
815
816 assert_eq!(original.id, deserialized.id);
818 assert_eq!(original.network_type, RelayerNetworkType::Solana);
819 assert_eq!(deserialized.network_type, RelayerNetworkType::Solana);
820 assert_eq!(original.paused, deserialized.paused);
821
822 match (&original.policies, &deserialized.policies) {
824 (RelayerNetworkPolicy::Solana(orig), RelayerNetworkPolicy::Solana(deser)) => {
825 assert_eq!(orig.fee_payment_strategy, deser.fee_payment_strategy);
826 assert_eq!(orig.min_balance, deser.min_balance);
827 assert_eq!(orig.max_signatures, deser.max_signatures);
828 }
829 _ => panic!("Policy types don't match after serialization/deserialization"),
830 }
831 }
832
833 #[test]
834 fn test_repo_model_serialization_deserialization_stellar() {
835 let original = create_test_relayer_stellar(false, true);
836
837 let serialized = serde_json::to_string(&original).unwrap();
839 assert!(!serialized.is_empty());
840
841 let deserialized: RelayerRepoModel = serde_json::from_str(&serialized).unwrap();
843
844 assert_eq!(original.id, deserialized.id);
846 assert_eq!(original.network_type, RelayerNetworkType::Stellar);
847 assert_eq!(deserialized.network_type, RelayerNetworkType::Stellar);
848 assert_eq!(original.system_disabled, deserialized.system_disabled);
849
850 match (&original.policies, &deserialized.policies) {
852 (RelayerNetworkPolicy::Stellar(orig), RelayerNetworkPolicy::Stellar(deser)) => {
853 assert_eq!(orig.min_balance, deser.min_balance);
854 assert_eq!(orig.max_fee, deser.max_fee);
855 assert_eq!(orig.timeout_seconds, deser.timeout_seconds);
856 }
857 _ => panic!("Policy types don't match after serialization/deserialization"),
858 }
859 }
860
861 #[test]
862 fn test_repo_model_default() {
863 let default_model = RelayerRepoModel::default();
864
865 assert_eq!(default_model.id, "");
866 assert_eq!(default_model.name, "");
867 assert_eq!(default_model.network, "");
868 assert!(!default_model.paused);
869 assert_eq!(default_model.network_type, NetworkType::Evm);
870 assert_eq!(default_model.signer_id, "");
871 assert_eq!(default_model.address, "0x");
872 assert_eq!(default_model.notification_id, None);
873 assert!(!default_model.system_disabled);
874 assert_eq!(default_model.custom_rpc_urls, None);
875
876 if let RelayerNetworkPolicy::Evm(_) = default_model.policies {
878 } else {
880 panic!("Default should have EVM policy");
881 }
882 }
883
884 #[test]
885 fn test_round_trip_conversion_all_network_types() {
886 let original_evm = Relayer {
890 id: "evm_relayer".to_string(),
891 name: "EVM Relayer".to_string(),
892 network: "mainnet".to_string(),
893 paused: false,
894 network_type: RelayerNetworkType::Evm,
895 policies: Some(RelayerNetworkPolicy::Evm(RelayerEvmPolicy {
896 gas_price_cap: Some(50_000_000_000),
897 eip1559_pricing: Some(true),
898 min_balance: None,
899 gas_limit_estimation: None,
900 whitelist_receivers: None,
901 private_transactions: None,
902 })),
903 signer_id: "evm_signer".to_string(),
904 notification_id: Some("evm_notification".to_string()),
905 custom_rpc_urls: None,
906 };
907
908 let repo_evm = RelayerRepoModel::from(original_evm.clone());
909 let recovered_evm = Relayer::from(repo_evm);
910
911 assert_eq!(original_evm.id, recovered_evm.id);
912 assert_eq!(original_evm.network_type, recovered_evm.network_type);
913 assert_eq!(original_evm.notification_id, recovered_evm.notification_id);
914
915 let original_solana = Relayer {
917 id: "solana_relayer".to_string(),
918 name: "Solana Relayer".to_string(),
919 network: "mainnet".to_string(),
920 paused: true,
921 network_type: RelayerNetworkType::Solana,
922 policies: Some(RelayerNetworkPolicy::Solana(RelayerSolanaPolicy {
923 fee_payment_strategy: Some(SolanaFeePaymentStrategy::User),
924 min_balance: Some(3000000),
925 max_signatures: None,
926 allowed_tokens: None,
927 allowed_programs: None,
928 allowed_accounts: None,
929 disallowed_accounts: None,
930 max_tx_data_size: None,
931 max_allowed_fee_lamports: None,
932 swap_config: None,
933 fee_margin_percentage: None,
934 })),
935 signer_id: "solana_signer".to_string(),
936 notification_id: None,
937 custom_rpc_urls: None,
938 };
939
940 let repo_solana = RelayerRepoModel::from(original_solana.clone());
941 let recovered_solana = Relayer::from(repo_solana);
942
943 assert_eq!(original_solana.id, recovered_solana.id);
944 assert_eq!(original_solana.network_type, recovered_solana.network_type);
945 assert_eq!(original_solana.paused, recovered_solana.paused);
946
947 let original_stellar = Relayer {
949 id: "stellar_relayer".to_string(),
950 name: "Stellar Relayer".to_string(),
951 network: "mainnet".to_string(),
952 paused: false,
953 network_type: RelayerNetworkType::Stellar,
954 policies: Some(RelayerNetworkPolicy::Stellar(RelayerStellarPolicy {
955 min_balance: Some(50000000),
956 max_fee: Some(250000),
957 timeout_seconds: Some(180),
958 concurrent_transactions: None,
959 allowed_tokens: None,
960 fee_payment_strategy: Some(StellarFeePaymentStrategy::Relayer),
961 slippage_percentage: None,
962 fee_margin_percentage: None,
963 swap_config: None,
964 })),
965 signer_id: "stellar_signer".to_string(),
966 notification_id: Some("stellar_notification".to_string()),
967 custom_rpc_urls: None,
968 };
969
970 let repo_stellar = RelayerRepoModel::from(original_stellar.clone());
971 let recovered_stellar = Relayer::from(repo_stellar);
972
973 assert_eq!(original_stellar.id, recovered_stellar.id);
974 assert_eq!(
975 original_stellar.network_type,
976 recovered_stellar.network_type
977 );
978 assert_eq!(
979 original_stellar.notification_id,
980 recovered_stellar.notification_id
981 );
982 }
983}