1use super::{
15 DisabledReason, Relayer, RelayerEvmPolicy, RelayerNetworkPolicy, RelayerNetworkType,
16 RelayerRepoModel, RelayerSolanaPolicy, RelayerSolanaSwapConfig, RelayerStellarPolicy,
17 RelayerStellarSwapConfig, RpcConfig, SolanaAllowedTokensPolicy, SolanaFeePaymentStrategy,
18 StellarAllowedTokensPolicy, StellarFeePaymentStrategy,
19};
20use crate::constants::{
21 DEFAULT_EVM_GAS_LIMIT_ESTIMATION, DEFAULT_EVM_MIN_BALANCE, DEFAULT_SOLANA_MAX_TX_DATA_SIZE,
22 DEFAULT_SOLANA_MIN_BALANCE, DEFAULT_STELLAR_MIN_BALANCE,
23};
24use serde::{Deserialize, Serialize};
25use utoipa::ToSchema;
26
27#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
29pub struct DeletePendingTransactionsResponse {
30 pub queued_for_cancellation_transaction_ids: Vec<String>,
31 pub failed_to_queue_transaction_ids: Vec<String>,
32 pub total_processed: u32,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
38#[serde(untagged)]
39pub enum RelayerNetworkPolicyResponse {
40 Evm(EvmPolicyResponse),
43 Stellar(StellarPolicyResponse),
45 Solana(SolanaPolicyResponse),
47}
48
49impl From<RelayerNetworkPolicy> for RelayerNetworkPolicyResponse {
50 fn from(policy: RelayerNetworkPolicy) -> Self {
51 match policy {
52 RelayerNetworkPolicy::Evm(evm_policy) => {
53 RelayerNetworkPolicyResponse::Evm(evm_policy.into())
54 }
55 RelayerNetworkPolicy::Solana(solana_policy) => {
56 RelayerNetworkPolicyResponse::Solana(solana_policy.into())
57 }
58 RelayerNetworkPolicy::Stellar(stellar_policy) => {
59 RelayerNetworkPolicyResponse::Stellar(stellar_policy.into())
60 }
61 }
62 }
63}
64
65#[derive(Debug, Serialize, Clone, PartialEq, ToSchema)]
67pub struct RelayerResponse {
68 pub id: String,
69 pub name: String,
70 pub network: String,
71 pub network_type: RelayerNetworkType,
72 pub paused: bool,
73 #[serde(skip_serializing_if = "Option::is_none")]
76 #[schema(nullable = false)]
77 pub policies: Option<RelayerNetworkPolicyResponse>,
78 pub signer_id: String,
79 #[serde(skip_serializing_if = "Option::is_none")]
80 #[schema(nullable = false)]
81 pub notification_id: Option<String>,
82 #[serde(skip_serializing_if = "Option::is_none")]
83 #[schema(nullable = false)]
84 pub custom_rpc_urls: Option<Vec<RpcConfig>>,
85 #[schema(nullable = false)]
87 pub address: Option<String>,
88 #[schema(nullable = false)]
89 pub system_disabled: Option<bool>,
90 #[serde(skip_serializing_if = "Option::is_none")]
91 #[schema(nullable = false)]
92 pub disabled_reason: Option<DisabledReason>,
93}
94
95#[cfg(test)]
96impl Default for RelayerResponse {
97 fn default() -> Self {
98 Self {
99 id: String::new(),
100 name: String::new(),
101 network: String::new(),
102 network_type: RelayerNetworkType::Evm, paused: false,
104 policies: None,
105 signer_id: String::new(),
106 notification_id: None,
107 custom_rpc_urls: None,
108 address: None,
109 system_disabled: None,
110 disabled_reason: None,
111 }
112 }
113}
114
115#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
117#[serde(tag = "network_type")]
118pub enum RelayerStatus {
119 #[serde(rename = "evm")]
120 Evm {
121 balance: String,
122 pending_transactions_count: u64,
123 last_confirmed_transaction_timestamp: Option<String>,
124 system_disabled: bool,
125 paused: bool,
126 nonce: String,
127 },
128 #[serde(rename = "stellar")]
129 Stellar {
130 balance: String,
131 pending_transactions_count: u64,
132 last_confirmed_transaction_timestamp: Option<String>,
133 system_disabled: bool,
134 paused: bool,
135 sequence_number: String,
136 },
137 #[serde(rename = "solana")]
138 Solana {
139 balance: String,
140 pending_transactions_count: u64,
141 last_confirmed_transaction_timestamp: Option<String>,
142 system_disabled: bool,
143 paused: bool,
144 },
145}
146
147fn convert_policy_to_response(
149 policy: RelayerNetworkPolicy,
150 network_type: RelayerNetworkType,
151) -> RelayerNetworkPolicyResponse {
152 match (policy, network_type) {
153 (RelayerNetworkPolicy::Evm(evm_policy), RelayerNetworkType::Evm) => {
154 RelayerNetworkPolicyResponse::Evm(EvmPolicyResponse::from(evm_policy))
155 }
156 (RelayerNetworkPolicy::Solana(solana_policy), RelayerNetworkType::Solana) => {
157 RelayerNetworkPolicyResponse::Solana(SolanaPolicyResponse::from(solana_policy))
158 }
159 (RelayerNetworkPolicy::Stellar(stellar_policy), RelayerNetworkType::Stellar) => {
160 RelayerNetworkPolicyResponse::Stellar(StellarPolicyResponse::from(stellar_policy))
161 }
162 (RelayerNetworkPolicy::Evm(evm_policy), _) => {
164 RelayerNetworkPolicyResponse::Evm(EvmPolicyResponse::from(evm_policy))
165 }
166 (RelayerNetworkPolicy::Solana(solana_policy), _) => {
167 RelayerNetworkPolicyResponse::Solana(SolanaPolicyResponse::from(solana_policy))
168 }
169 (RelayerNetworkPolicy::Stellar(stellar_policy), _) => {
170 RelayerNetworkPolicyResponse::Stellar(StellarPolicyResponse::from(stellar_policy))
171 }
172 }
173}
174
175impl From<Relayer> for RelayerResponse {
176 fn from(relayer: Relayer) -> Self {
177 Self {
178 id: relayer.id.clone(),
179 name: relayer.name.clone(),
180 network: relayer.network.clone(),
181 network_type: relayer.network_type,
182 paused: relayer.paused,
183 policies: relayer
184 .policies
185 .map(|policy| convert_policy_to_response(policy, relayer.network_type)),
186 signer_id: relayer.signer_id,
187 notification_id: relayer.notification_id,
188 custom_rpc_urls: relayer.custom_rpc_urls,
189 address: None,
190 system_disabled: None,
191 disabled_reason: None,
192 }
193 }
194}
195
196impl From<RelayerRepoModel> for RelayerResponse {
197 fn from(model: RelayerRepoModel) -> Self {
198 let policies = if is_empty_policy(&model.policies) {
200 None } else {
202 Some(convert_policy_to_response(
203 model.policies.clone(),
204 model.network_type,
205 ))
206 };
207
208 Self {
209 id: model.id,
210 name: model.name,
211 network: model.network,
212 network_type: model.network_type,
213 paused: model.paused,
214 policies,
215 signer_id: model.signer_id,
216 notification_id: model.notification_id,
217 custom_rpc_urls: model.custom_rpc_urls,
218 address: Some(model.address),
219 system_disabled: Some(model.system_disabled),
220 disabled_reason: model.disabled_reason,
221 }
222 }
223}
224
225impl<'de> serde::Deserialize<'de> for RelayerResponse {
227 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
228 where
229 D: serde::Deserializer<'de>,
230 {
231 use serde::de::Error;
232 use serde_json::Value;
233
234 let value: Value = Value::deserialize(deserializer)?;
236
237 let network_type: RelayerNetworkType = value
239 .get("network_type")
240 .and_then(|v| serde_json::from_value(v.clone()).ok())
241 .ok_or_else(|| D::Error::missing_field("network_type"))?;
242
243 let policies = if let Some(policies_value) = value.get("policies") {
245 if policies_value.is_null() {
246 None
247 } else {
248 let policy_response = match network_type {
250 RelayerNetworkType::Evm => {
251 let evm_policy: EvmPolicyResponse =
252 serde_json::from_value(policies_value.clone())
253 .map_err(D::Error::custom)?;
254 RelayerNetworkPolicyResponse::Evm(evm_policy)
255 }
256 RelayerNetworkType::Solana => {
257 let solana_policy: SolanaPolicyResponse =
258 serde_json::from_value(policies_value.clone())
259 .map_err(D::Error::custom)?;
260 RelayerNetworkPolicyResponse::Solana(solana_policy)
261 }
262 RelayerNetworkType::Stellar => {
263 let stellar_policy: StellarPolicyResponse =
264 serde_json::from_value(policies_value.clone())
265 .map_err(D::Error::custom)?;
266 RelayerNetworkPolicyResponse::Stellar(stellar_policy)
267 }
268 };
269 Some(policy_response)
270 }
271 } else {
272 None
273 };
274
275 Ok(RelayerResponse {
277 id: value
278 .get("id")
279 .and_then(|v| serde_json::from_value(v.clone()).ok())
280 .ok_or_else(|| D::Error::missing_field("id"))?,
281 name: value
282 .get("name")
283 .and_then(|v| serde_json::from_value(v.clone()).ok())
284 .ok_or_else(|| D::Error::missing_field("name"))?,
285 network: value
286 .get("network")
287 .and_then(|v| serde_json::from_value(v.clone()).ok())
288 .ok_or_else(|| D::Error::missing_field("network"))?,
289 network_type,
290 paused: value
291 .get("paused")
292 .and_then(|v| serde_json::from_value(v.clone()).ok())
293 .ok_or_else(|| D::Error::missing_field("paused"))?,
294 policies,
295 signer_id: value
296 .get("signer_id")
297 .and_then(|v| serde_json::from_value(v.clone()).ok())
298 .ok_or_else(|| D::Error::missing_field("signer_id"))?,
299 notification_id: value
300 .get("notification_id")
301 .and_then(|v| serde_json::from_value(v.clone()).ok())
302 .unwrap_or(None),
303 custom_rpc_urls: value
304 .get("custom_rpc_urls")
305 .and_then(|v| serde_json::from_value(v.clone()).ok())
306 .unwrap_or(None),
307 address: value
308 .get("address")
309 .and_then(|v| serde_json::from_value(v.clone()).ok())
310 .unwrap_or(None),
311 system_disabled: value
312 .get("system_disabled")
313 .and_then(|v| serde_json::from_value(v.clone()).ok())
314 .unwrap_or(None),
315 disabled_reason: value
316 .get("disabled_reason")
317 .and_then(|v| serde_json::from_value(v.clone()).ok())
318 .unwrap_or(None),
319 })
320 }
321}
322
323fn is_empty_policy(policy: &RelayerNetworkPolicy) -> bool {
325 match policy {
326 RelayerNetworkPolicy::Evm(evm_policy) => {
327 evm_policy.min_balance.is_none()
328 && evm_policy.gas_limit_estimation.is_none()
329 && evm_policy.gas_price_cap.is_none()
330 && evm_policy.whitelist_receivers.is_none()
331 && evm_policy.eip1559_pricing.is_none()
332 && evm_policy.private_transactions.is_none()
333 }
334 RelayerNetworkPolicy::Solana(solana_policy) => {
335 solana_policy.allowed_programs.is_none()
336 && solana_policy.max_signatures.is_none()
337 && solana_policy.max_tx_data_size.is_none()
338 && solana_policy.min_balance.is_none()
339 && solana_policy.allowed_tokens.is_none()
340 && solana_policy.fee_payment_strategy.is_none()
341 && solana_policy.fee_margin_percentage.is_none()
342 && solana_policy.allowed_accounts.is_none()
343 && solana_policy.disallowed_accounts.is_none()
344 && solana_policy.max_allowed_fee_lamports.is_none()
345 && solana_policy.swap_config.is_none()
346 }
347 RelayerNetworkPolicy::Stellar(stellar_policy) => {
348 stellar_policy.min_balance.is_none()
349 && stellar_policy.max_fee.is_none()
350 && stellar_policy.timeout_seconds.is_none()
351 && stellar_policy.concurrent_transactions.is_none()
352 && stellar_policy.allowed_tokens.is_none()
353 && stellar_policy.fee_payment_strategy.is_none()
354 && stellar_policy.slippage_percentage.is_none()
355 && stellar_policy.fee_margin_percentage.is_none()
356 && stellar_policy.swap_config.is_none()
357 }
358 }
359}
360
361#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
363pub struct NetworkPolicyResponse {
364 #[serde(flatten)]
365 pub policy: RelayerNetworkPolicy,
366}
367
368fn default_evm_min_balance() -> u128 {
370 DEFAULT_EVM_MIN_BALANCE
371}
372
373fn default_evm_gas_limit_estimation() -> bool {
374 DEFAULT_EVM_GAS_LIMIT_ESTIMATION
375}
376
377fn default_solana_min_balance() -> u64 {
379 DEFAULT_SOLANA_MIN_BALANCE
380}
381
382fn default_stellar_min_balance() -> u64 {
384 DEFAULT_STELLAR_MIN_BALANCE
385}
386
387fn default_solana_max_tx_data_size() -> u16 {
389 DEFAULT_SOLANA_MAX_TX_DATA_SIZE
390}
391#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
393#[serde(deny_unknown_fields)]
394pub struct EvmPolicyResponse {
395 #[serde(
396 default = "default_evm_min_balance",
397 serialize_with = "crate::utils::serialize_u128_as_number",
398 deserialize_with = "crate::utils::deserialize_u128_as_number"
399 )]
400 #[schema(nullable = false)]
401 pub min_balance: u128,
402 #[serde(default = "default_evm_gas_limit_estimation")]
403 #[schema(nullable = false)]
404 pub gas_limit_estimation: bool,
405 #[serde(
406 skip_serializing_if = "Option::is_none",
407 serialize_with = "crate::utils::serialize_optional_u128_as_number",
408 deserialize_with = "crate::utils::deserialize_optional_u128_as_number",
409 default
410 )]
411 #[schema(nullable = false)]
412 pub gas_price_cap: Option<u128>,
413 #[serde(skip_serializing_if = "Option::is_none")]
414 #[schema(nullable = false)]
415 pub whitelist_receivers: Option<Vec<String>>,
416 #[serde(skip_serializing_if = "Option::is_none")]
417 #[schema(nullable = false)]
418 pub eip1559_pricing: Option<bool>,
419 #[serde(skip_serializing_if = "Option::is_none")]
420 #[schema(nullable = false)]
421 pub private_transactions: Option<bool>,
422}
423
424#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
426#[serde(deny_unknown_fields)]
427pub struct SolanaPolicyResponse {
428 #[serde(skip_serializing_if = "Option::is_none")]
429 #[schema(nullable = false)]
430 pub allowed_programs: Option<Vec<String>>,
431 #[serde(skip_serializing_if = "Option::is_none")]
432 #[schema(nullable = false)]
433 pub max_signatures: Option<u8>,
434 #[schema(nullable = false)]
435 #[serde(default = "default_solana_max_tx_data_size")]
436 pub max_tx_data_size: u16,
437 #[serde(default = "default_solana_min_balance")]
438 #[schema(nullable = false)]
439 pub min_balance: u64,
440 #[serde(skip_serializing_if = "Option::is_none")]
441 #[schema(nullable = false)]
442 pub allowed_tokens: Option<Vec<SolanaAllowedTokensPolicy>>,
443 #[serde(skip_serializing_if = "Option::is_none")]
444 #[schema(nullable = false)]
445 pub fee_payment_strategy: Option<SolanaFeePaymentStrategy>,
446 #[serde(skip_serializing_if = "Option::is_none")]
447 #[schema(nullable = false)]
448 pub fee_margin_percentage: Option<f32>,
449 #[serde(skip_serializing_if = "Option::is_none")]
450 #[schema(nullable = false)]
451 pub allowed_accounts: Option<Vec<String>>,
452 #[serde(skip_serializing_if = "Option::is_none")]
453 #[schema(nullable = false)]
454 pub disallowed_accounts: Option<Vec<String>>,
455 #[serde(skip_serializing_if = "Option::is_none")]
456 #[schema(nullable = false)]
457 pub max_allowed_fee_lamports: Option<u64>,
458 #[serde(skip_serializing_if = "Option::is_none")]
459 #[schema(nullable = false)]
460 pub swap_config: Option<RelayerSolanaSwapConfig>,
461}
462
463#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
465#[serde(deny_unknown_fields)]
466pub struct StellarPolicyResponse {
467 #[serde(skip_serializing_if = "Option::is_none")]
468 #[schema(nullable = false)]
469 pub max_fee: Option<u32>,
470 #[serde(skip_serializing_if = "Option::is_none")]
471 #[schema(nullable = false)]
472 pub timeout_seconds: Option<u64>,
473 #[serde(default = "default_stellar_min_balance")]
474 #[schema(nullable = false)]
475 pub min_balance: u64,
476 #[serde(skip_serializing_if = "Option::is_none")]
477 #[schema(nullable = false)]
478 pub concurrent_transactions: Option<bool>,
479 #[serde(skip_serializing_if = "Option::is_none")]
480 #[schema(nullable = false)]
481 pub allowed_tokens: Option<Vec<StellarAllowedTokensPolicy>>,
482 #[serde(skip_serializing_if = "Option::is_none")]
483 #[schema(nullable = false)]
484 pub fee_payment_strategy: Option<StellarFeePaymentStrategy>,
485 #[serde(skip_serializing_if = "Option::is_none")]
486 #[schema(nullable = false)]
487 pub slippage_percentage: Option<f32>,
488 #[serde(skip_serializing_if = "Option::is_none")]
489 #[schema(nullable = false)]
490 pub fee_margin_percentage: Option<f32>,
491 #[serde(skip_serializing_if = "Option::is_none")]
492 #[schema(nullable = false)]
493 pub swap_config: Option<RelayerStellarSwapConfig>,
494}
495
496impl From<RelayerEvmPolicy> for EvmPolicyResponse {
497 fn from(policy: RelayerEvmPolicy) -> Self {
498 Self {
499 min_balance: policy.min_balance.unwrap_or(DEFAULT_EVM_MIN_BALANCE),
500 gas_limit_estimation: policy
501 .gas_limit_estimation
502 .unwrap_or(DEFAULT_EVM_GAS_LIMIT_ESTIMATION),
503 gas_price_cap: policy.gas_price_cap,
504 whitelist_receivers: policy.whitelist_receivers,
505 eip1559_pricing: policy.eip1559_pricing,
506 private_transactions: policy.private_transactions,
507 }
508 }
509}
510
511impl From<RelayerSolanaPolicy> for SolanaPolicyResponse {
512 fn from(policy: RelayerSolanaPolicy) -> Self {
513 Self {
514 allowed_programs: policy.allowed_programs,
515 max_signatures: policy.max_signatures,
516 max_tx_data_size: policy
517 .max_tx_data_size
518 .unwrap_or(DEFAULT_SOLANA_MAX_TX_DATA_SIZE),
519 min_balance: policy.min_balance.unwrap_or(DEFAULT_SOLANA_MIN_BALANCE),
520 allowed_tokens: policy.allowed_tokens,
521 fee_payment_strategy: policy.fee_payment_strategy,
522 fee_margin_percentage: policy.fee_margin_percentage,
523 allowed_accounts: policy.allowed_accounts,
524 disallowed_accounts: policy.disallowed_accounts,
525 max_allowed_fee_lamports: policy.max_allowed_fee_lamports,
526 swap_config: policy.swap_config,
527 }
528 }
529}
530
531impl From<RelayerStellarPolicy> for StellarPolicyResponse {
532 fn from(policy: RelayerStellarPolicy) -> Self {
533 Self {
534 min_balance: policy.min_balance.unwrap_or(DEFAULT_STELLAR_MIN_BALANCE),
535 max_fee: policy.max_fee,
536 timeout_seconds: policy.timeout_seconds,
537 concurrent_transactions: policy.concurrent_transactions,
538 allowed_tokens: policy.allowed_tokens,
539 fee_payment_strategy: policy.fee_payment_strategy,
540 slippage_percentage: policy.slippage_percentage,
541 fee_margin_percentage: policy.fee_margin_percentage,
542 swap_config: policy.swap_config,
543 }
544 }
545}
546
547#[cfg(test)]
548mod tests {
549 use super::*;
550 use crate::models::{
551 relayer::{
552 RelayerEvmPolicy, RelayerSolanaPolicy, RelayerSolanaSwapConfig, RelayerStellarPolicy,
553 SolanaAllowedTokensPolicy, SolanaFeePaymentStrategy, SolanaSwapStrategy,
554 StellarAllowedTokensPolicy, StellarFeePaymentStrategy, StellarSwapStrategy,
555 },
556 StellarTokenKind, StellarTokenMetadata,
557 };
558
559 #[test]
560 fn test_from_domain_relayer() {
561 let relayer = Relayer::new(
562 "test-relayer".to_string(),
563 "Test Relayer".to_string(),
564 "mainnet".to_string(),
565 false,
566 RelayerNetworkType::Evm,
567 Some(RelayerNetworkPolicy::Evm(RelayerEvmPolicy {
568 gas_price_cap: Some(100_000_000_000),
569 whitelist_receivers: None,
570 eip1559_pricing: Some(true),
571 private_transactions: None,
572 min_balance: None,
573 gas_limit_estimation: None,
574 })),
575 "test-signer".to_string(),
576 None,
577 None,
578 );
579
580 let response: RelayerResponse = relayer.clone().into();
581
582 assert_eq!(response.id, relayer.id);
583 assert_eq!(response.name, relayer.name);
584 assert_eq!(response.network, relayer.network);
585 assert_eq!(response.network_type, relayer.network_type);
586 assert_eq!(response.paused, relayer.paused);
587 assert_eq!(
588 response.policies,
589 Some(RelayerNetworkPolicyResponse::Evm(
590 RelayerEvmPolicy {
591 gas_price_cap: Some(100_000_000_000),
592 whitelist_receivers: None,
593 eip1559_pricing: Some(true),
594 private_transactions: None,
595 min_balance: Some(DEFAULT_EVM_MIN_BALANCE),
596 gas_limit_estimation: Some(DEFAULT_EVM_GAS_LIMIT_ESTIMATION),
597 }
598 .into()
599 ))
600 );
601 assert_eq!(response.signer_id, relayer.signer_id);
602 assert_eq!(response.notification_id, relayer.notification_id);
603 assert_eq!(response.custom_rpc_urls, relayer.custom_rpc_urls);
604 assert_eq!(response.address, None);
605 assert_eq!(response.system_disabled, None);
606 }
607
608 #[test]
609 fn test_from_domain_relayer_solana() {
610 let relayer = Relayer::new(
611 "test-solana-relayer".to_string(),
612 "Test Solana Relayer".to_string(),
613 "mainnet".to_string(),
614 false,
615 RelayerNetworkType::Solana,
616 Some(RelayerNetworkPolicy::Solana(RelayerSolanaPolicy {
617 allowed_programs: Some(vec!["11111111111111111111111111111111".to_string()]),
618 max_signatures: Some(5),
619 min_balance: Some(1000000),
620 fee_payment_strategy: Some(SolanaFeePaymentStrategy::Relayer),
621 allowed_tokens: Some(vec![SolanaAllowedTokensPolicy::new(
622 "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v".to_string(),
623 Some(100000),
624 None,
625 )]),
626 max_tx_data_size: None,
627 fee_margin_percentage: None,
628 allowed_accounts: None,
629 disallowed_accounts: None,
630 max_allowed_fee_lamports: None,
631 swap_config: None,
632 })),
633 "test-signer".to_string(),
634 None,
635 None,
636 );
637
638 let response: RelayerResponse = relayer.clone().into();
639
640 assert_eq!(response.id, relayer.id);
641 assert_eq!(response.network_type, RelayerNetworkType::Solana);
642 assert!(response.policies.is_some());
643
644 if let Some(RelayerNetworkPolicyResponse::Solana(solana_response)) = response.policies {
645 assert_eq!(solana_response.min_balance, 1000000);
646 assert_eq!(solana_response.max_signatures, Some(5));
647 } else {
648 panic!("Expected Solana policy response");
649 }
650 }
651
652 #[test]
653 fn test_from_domain_relayer_stellar() {
654 let relayer = Relayer::new(
655 "test-stellar-relayer".to_string(),
656 "Test Stellar Relayer".to_string(),
657 "mainnet".to_string(),
658 false,
659 RelayerNetworkType::Stellar,
660 Some(RelayerNetworkPolicy::Stellar(RelayerStellarPolicy {
661 min_balance: Some(20000000),
662 max_fee: Some(100000),
663 timeout_seconds: Some(30),
664 concurrent_transactions: None,
665 allowed_tokens: None,
666 fee_payment_strategy: Some(StellarFeePaymentStrategy::Relayer),
667 slippage_percentage: None,
668 fee_margin_percentage: None,
669 swap_config: None,
670 })),
671 "test-signer".to_string(),
672 None,
673 None,
674 );
675
676 let response: RelayerResponse = relayer.clone().into();
677
678 assert_eq!(response.id, relayer.id);
679 assert_eq!(response.network_type, RelayerNetworkType::Stellar);
680 assert!(response.policies.is_some());
681
682 if let Some(RelayerNetworkPolicyResponse::Stellar(stellar_response)) = response.policies {
683 assert_eq!(stellar_response.min_balance, 20000000);
684 } else {
685 panic!("Expected Stellar policy response");
686 }
687 }
688
689 #[test]
690 fn test_response_serialization() {
691 let response = RelayerResponse {
692 id: "test-relayer".to_string(),
693 name: "Test Relayer".to_string(),
694 network: "mainnet".to_string(),
695 network_type: RelayerNetworkType::Evm,
696 paused: false,
697 policies: Some(RelayerNetworkPolicyResponse::Evm(EvmPolicyResponse {
698 gas_price_cap: Some(50000000000),
699 whitelist_receivers: None,
700 eip1559_pricing: Some(true),
701 private_transactions: None,
702 min_balance: DEFAULT_EVM_MIN_BALANCE,
703 gas_limit_estimation: DEFAULT_EVM_GAS_LIMIT_ESTIMATION,
704 })),
705 signer_id: "test-signer".to_string(),
706 notification_id: None,
707 custom_rpc_urls: None,
708 address: Some("0x123...".to_string()),
709 system_disabled: Some(false),
710 ..Default::default()
711 };
712
713 let serialized = serde_json::to_string(&response).unwrap();
715 assert!(!serialized.is_empty());
716
717 let deserialized: RelayerResponse = serde_json::from_str(&serialized).unwrap();
719 assert_eq!(response.id, deserialized.id);
720 assert_eq!(response.name, deserialized.name);
721 }
722
723 #[test]
724 fn test_solana_response_serialization() {
725 let response = RelayerResponse {
726 id: "test-solana-relayer".to_string(),
727 name: "Test Solana Relayer".to_string(),
728 network: "mainnet".to_string(),
729 network_type: RelayerNetworkType::Solana,
730 paused: false,
731 policies: Some(RelayerNetworkPolicyResponse::Solana(SolanaPolicyResponse {
732 allowed_programs: Some(vec!["11111111111111111111111111111111".to_string()]),
733 max_signatures: Some(5),
734 max_tx_data_size: DEFAULT_SOLANA_MAX_TX_DATA_SIZE,
735 min_balance: 1000000,
736 allowed_tokens: Some(vec![SolanaAllowedTokensPolicy::new(
737 "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v".to_string(),
738 Some(100000),
739 None,
740 )]),
741 fee_payment_strategy: Some(SolanaFeePaymentStrategy::Relayer),
742 fee_margin_percentage: Some(5.0),
743 allowed_accounts: None,
744 disallowed_accounts: None,
745 max_allowed_fee_lamports: Some(500000),
746 swap_config: Some(RelayerSolanaSwapConfig {
747 strategy: Some(SolanaSwapStrategy::JupiterSwap),
748 cron_schedule: Some("0 0 * * *".to_string()),
749 min_balance_threshold: Some(500000),
750 jupiter_swap_options: None,
751 }),
752 })),
753 signer_id: "test-signer".to_string(),
754 notification_id: None,
755 custom_rpc_urls: None,
756 address: Some("SolanaAddress123...".to_string()),
757 system_disabled: Some(false),
758 ..Default::default()
759 };
760
761 let serialized = serde_json::to_string(&response).unwrap();
763 assert!(!serialized.is_empty());
764
765 let deserialized: RelayerResponse = serde_json::from_str(&serialized).unwrap();
767 assert_eq!(response.id, deserialized.id);
768 assert_eq!(response.network_type, RelayerNetworkType::Solana);
769 }
770
771 #[test]
772 fn test_stellar_response_serialization() {
773 let response = RelayerResponse {
774 id: "test-stellar-relayer".to_string(),
775 name: "Test Stellar Relayer".to_string(),
776 network: "mainnet".to_string(),
777 network_type: RelayerNetworkType::Stellar,
778 paused: false,
779 policies: Some(RelayerNetworkPolicyResponse::Stellar(
780 StellarPolicyResponse {
781 max_fee: Some(5000),
782 timeout_seconds: None,
783 min_balance: 20000000,
784 concurrent_transactions: None,
785 allowed_tokens: None,
786 fee_payment_strategy: None,
787 slippage_percentage: None,
788 fee_margin_percentage: None,
789 swap_config: None,
790 },
791 )),
792 signer_id: "test-signer".to_string(),
793 notification_id: None,
794 custom_rpc_urls: None,
795 address: Some("GXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".to_string()),
796 system_disabled: Some(false),
797 ..Default::default()
798 };
799
800 let serialized = serde_json::to_string(&response).unwrap();
802 assert!(!serialized.is_empty());
803
804 let deserialized: RelayerResponse = serde_json::from_str(&serialized).unwrap();
806 assert_eq!(response.id, deserialized.id);
807 assert_eq!(response.network_type, RelayerNetworkType::Stellar);
808
809 if let Some(RelayerNetworkPolicyResponse::Stellar(stellar_policy)) = deserialized.policies {
811 assert_eq!(stellar_policy.min_balance, 20000000);
812 assert_eq!(stellar_policy.max_fee, Some(5000));
813 assert_eq!(stellar_policy.timeout_seconds, None);
814 } else {
815 panic!("Expected Stellar policy in deserialized response");
816 }
817 }
818
819 #[test]
820 fn test_response_without_redundant_network_type() {
821 let response = RelayerResponse {
822 id: "test-relayer".to_string(),
823 name: "Test Relayer".to_string(),
824 network: "mainnet".to_string(),
825 network_type: RelayerNetworkType::Evm,
826 paused: false,
827 policies: Some(RelayerNetworkPolicyResponse::Evm(EvmPolicyResponse {
828 gas_price_cap: Some(100_000_000_000),
829 whitelist_receivers: None,
830 eip1559_pricing: Some(true),
831 private_transactions: None,
832 min_balance: DEFAULT_EVM_MIN_BALANCE,
833 gas_limit_estimation: DEFAULT_EVM_GAS_LIMIT_ESTIMATION,
834 })),
835 signer_id: "test-signer".to_string(),
836 notification_id: None,
837 custom_rpc_urls: None,
838 address: Some("0x123...".to_string()),
839 system_disabled: Some(false),
840 ..Default::default()
841 };
842
843 let serialized = serde_json::to_string_pretty(&response).unwrap();
844
845 assert!(serialized.contains(r#""network_type": "evm""#));
846
847 let network_type_count = serialized.matches(r#""network_type""#).count();
849 assert_eq!(
850 network_type_count, 1,
851 "Should only have one network_type field at top level, not in policies"
852 );
853
854 assert!(serialized.contains(r#""gas_price_cap": 100000000000"#));
855 assert!(serialized.contains(r#""eip1559_pricing": true"#));
856 }
857
858 #[test]
859 fn test_solana_response_without_redundant_network_type() {
860 let response = RelayerResponse {
861 id: "test-solana-relayer".to_string(),
862 name: "Test Solana Relayer".to_string(),
863 network: "mainnet".to_string(),
864 network_type: RelayerNetworkType::Solana,
865 paused: false,
866 policies: Some(RelayerNetworkPolicyResponse::Solana(SolanaPolicyResponse {
867 allowed_programs: Some(vec!["11111111111111111111111111111111".to_string()]),
868 max_signatures: Some(5),
869 max_tx_data_size: DEFAULT_SOLANA_MAX_TX_DATA_SIZE,
870 min_balance: 1000000,
871 allowed_tokens: None,
872 fee_payment_strategy: Some(SolanaFeePaymentStrategy::Relayer),
873 fee_margin_percentage: None,
874 allowed_accounts: None,
875 disallowed_accounts: None,
876 max_allowed_fee_lamports: None,
877 swap_config: None,
878 })),
879 signer_id: "test-signer".to_string(),
880 notification_id: None,
881 custom_rpc_urls: None,
882 address: Some("SolanaAddress123...".to_string()),
883 system_disabled: Some(false),
884 ..Default::default()
885 };
886
887 let serialized = serde_json::to_string_pretty(&response).unwrap();
888
889 assert!(serialized.contains(r#""network_type": "solana""#));
890
891 let network_type_count = serialized.matches(r#""network_type""#).count();
893 assert_eq!(
894 network_type_count, 1,
895 "Should only have one network_type field at top level, not in policies"
896 );
897
898 assert!(serialized.contains(r#""max_signatures": 5"#));
899 assert!(serialized.contains(r#""fee_payment_strategy": "relayer""#));
900 }
901
902 #[test]
903 fn test_stellar_response_without_redundant_network_type() {
904 let response = RelayerResponse {
905 id: "test-stellar-relayer".to_string(),
906 name: "Test Stellar Relayer".to_string(),
907 network: "mainnet".to_string(),
908 network_type: RelayerNetworkType::Stellar,
909 paused: false,
910 policies: Some(RelayerNetworkPolicyResponse::Stellar(
911 StellarPolicyResponse {
912 min_balance: 20000000,
913 max_fee: Some(100000),
914 timeout_seconds: Some(30),
915 concurrent_transactions: None,
916 allowed_tokens: None,
917 fee_payment_strategy: None,
918 slippage_percentage: None,
919 fee_margin_percentage: None,
920 swap_config: None,
921 },
922 )),
923 signer_id: "test-signer".to_string(),
924 notification_id: None,
925 custom_rpc_urls: None,
926 address: Some("GXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".to_string()),
927 system_disabled: Some(false),
928 ..Default::default()
929 };
930
931 let serialized = serde_json::to_string_pretty(&response).unwrap();
932
933 assert!(serialized.contains(r#""network_type": "stellar""#));
934
935 let network_type_count = serialized.matches(r#""network_type""#).count();
937 assert_eq!(
938 network_type_count, 1,
939 "Should only have one network_type field at top level, not in policies"
940 );
941
942 assert!(serialized.contains(r#""min_balance": 20000000"#));
943 assert!(serialized.contains(r#""max_fee": 100000"#));
944 assert!(serialized.contains(r#""timeout_seconds": 30"#));
945 }
946
947 #[test]
948 fn test_empty_policies_not_returned_in_response() {
949 let repo_model = RelayerRepoModel {
951 id: "test-relayer".to_string(),
952 name: "Test Relayer".to_string(),
953 network: "mainnet".to_string(),
954 network_type: RelayerNetworkType::Evm,
955 paused: false,
956 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default()), signer_id: "test-signer".to_string(),
958 notification_id: None,
959 custom_rpc_urls: None,
960 address: "0x123...".to_string(),
961 system_disabled: false,
962 ..Default::default()
963 };
964
965 let response = RelayerResponse::from(repo_model);
967
968 assert_eq!(response.policies, None);
970
971 let serialized = serde_json::to_string(&response).unwrap();
973 assert!(
974 !serialized.contains("policies"),
975 "Empty policies should not appear in JSON response"
976 );
977 }
978
979 #[test]
980 fn test_empty_solana_policies_not_returned_in_response() {
981 let repo_model = RelayerRepoModel {
983 id: "test-solana-relayer".to_string(),
984 name: "Test Solana Relayer".to_string(),
985 network: "mainnet".to_string(),
986 network_type: RelayerNetworkType::Solana,
987 paused: false,
988 policies: RelayerNetworkPolicy::Solana(RelayerSolanaPolicy::default()), signer_id: "test-signer".to_string(),
990 notification_id: None,
991 custom_rpc_urls: None,
992 address: "SolanaAddress123...".to_string(),
993 system_disabled: false,
994 ..Default::default()
995 };
996
997 let response = RelayerResponse::from(repo_model);
999
1000 assert_eq!(response.policies, None);
1002
1003 let serialized = serde_json::to_string(&response).unwrap();
1005 assert!(
1006 !serialized.contains("policies"),
1007 "Empty Solana policies should not appear in JSON response"
1008 );
1009 }
1010
1011 #[test]
1012 fn test_empty_stellar_policies_not_returned_in_response() {
1013 let repo_model = RelayerRepoModel {
1015 id: "test-stellar-relayer".to_string(),
1016 name: "Test Stellar Relayer".to_string(),
1017 network: "mainnet".to_string(),
1018 network_type: RelayerNetworkType::Stellar,
1019 paused: false,
1020 policies: RelayerNetworkPolicy::Stellar(RelayerStellarPolicy::default()), signer_id: "test-signer".to_string(),
1022 notification_id: None,
1023 custom_rpc_urls: None,
1024 address: "GXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".to_string(),
1025 system_disabled: false,
1026 ..Default::default()
1027 };
1028
1029 let response = RelayerResponse::from(repo_model);
1031
1032 assert_eq!(response.policies, None);
1034
1035 let serialized = serde_json::to_string(&response).unwrap();
1037 assert!(
1038 !serialized.contains("policies"),
1039 "Empty Stellar policies should not appear in JSON response"
1040 );
1041 }
1042
1043 #[test]
1044 fn test_user_provided_policies_returned_in_response() {
1045 let repo_model = RelayerRepoModel {
1047 id: "test-relayer".to_string(),
1048 name: "Test Relayer".to_string(),
1049 network: "mainnet".to_string(),
1050 network_type: RelayerNetworkType::Evm,
1051 paused: false,
1052 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy {
1053 gas_price_cap: Some(100_000_000_000),
1054 eip1559_pricing: Some(true),
1055 min_balance: None, gas_limit_estimation: None,
1057 whitelist_receivers: None,
1058 private_transactions: None,
1059 }),
1060 signer_id: "test-signer".to_string(),
1061 notification_id: None,
1062 custom_rpc_urls: None,
1063 address: "0x123...".to_string(),
1064 system_disabled: false,
1065 ..Default::default()
1066 };
1067
1068 let response = RelayerResponse::from(repo_model);
1070
1071 assert!(response.policies.is_some());
1073
1074 let serialized = serde_json::to_string(&response).unwrap();
1076 assert!(
1077 serialized.contains("policies"),
1078 "User-provided policies should appear in JSON response"
1079 );
1080 assert!(
1081 serialized.contains("gas_price_cap"),
1082 "User-provided policy values should appear in JSON response"
1083 );
1084 }
1085
1086 #[test]
1087 fn test_user_provided_solana_policies_returned_in_response() {
1088 let repo_model = RelayerRepoModel {
1090 id: "test-solana-relayer".to_string(),
1091 name: "Test Solana Relayer".to_string(),
1092 network: "mainnet".to_string(),
1093 network_type: RelayerNetworkType::Solana,
1094 paused: false,
1095 policies: RelayerNetworkPolicy::Solana(RelayerSolanaPolicy {
1096 max_signatures: Some(5),
1097 fee_payment_strategy: Some(SolanaFeePaymentStrategy::Relayer),
1098 min_balance: Some(1000000),
1099 allowed_programs: None, max_tx_data_size: None,
1101 allowed_tokens: None,
1102 fee_margin_percentage: None,
1103 allowed_accounts: None,
1104 disallowed_accounts: None,
1105 max_allowed_fee_lamports: None,
1106 swap_config: None,
1107 }),
1108 signer_id: "test-signer".to_string(),
1109 notification_id: None,
1110 custom_rpc_urls: None,
1111 address: "SolanaAddress123...".to_string(),
1112 system_disabled: false,
1113 ..Default::default()
1114 };
1115
1116 let response = RelayerResponse::from(repo_model);
1118
1119 assert!(response.policies.is_some());
1121
1122 let serialized = serde_json::to_string(&response).unwrap();
1124 assert!(
1125 serialized.contains("policies"),
1126 "User-provided Solana policies should appear in JSON response"
1127 );
1128 assert!(
1129 serialized.contains("max_signatures"),
1130 "User-provided Solana policy values should appear in JSON response"
1131 );
1132 assert!(
1133 serialized.contains("fee_payment_strategy"),
1134 "User-provided Solana policy values should appear in JSON response"
1135 );
1136 }
1137
1138 #[test]
1139 fn test_user_provided_stellar_policies_returned_in_response() {
1140 let repo_model = RelayerRepoModel {
1142 id: "test-stellar-relayer".to_string(),
1143 name: "Test Stellar Relayer".to_string(),
1144 network: "mainnet".to_string(),
1145 network_type: RelayerNetworkType::Stellar,
1146 paused: false,
1147 policies: RelayerNetworkPolicy::Stellar(RelayerStellarPolicy {
1148 max_fee: Some(100000),
1149 timeout_seconds: Some(30),
1150 min_balance: Some(20000000),
1151 concurrent_transactions: Some(true),
1152 allowed_tokens: Some(vec![StellarAllowedTokensPolicy::new(
1153 "USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN".to_string(),
1154 Some(StellarTokenMetadata {
1155 kind: StellarTokenKind::Classic {
1156 code: "USDC".to_string(),
1157 issuer: "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
1158 .to_string(),
1159 },
1160 decimals: 6,
1161 canonical_asset_id:
1162 "USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
1163 .to_string(),
1164 }),
1165 None,
1166 None,
1167 )]),
1168 fee_payment_strategy: Some(StellarFeePaymentStrategy::Relayer),
1169 slippage_percentage: Some(0.5),
1170 fee_margin_percentage: Some(2.0),
1171 swap_config: Some(RelayerStellarSwapConfig {
1172 strategies: vec![StellarSwapStrategy::Soroswap],
1173 cron_schedule: Some("0 0 * * *".to_string()),
1174 min_balance_threshold: Some(10000000),
1175 }),
1176 }),
1177 signer_id: "test-signer".to_string(),
1178 notification_id: None,
1179 custom_rpc_urls: None,
1180 address: "GXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".to_string(),
1181 system_disabled: false,
1182 ..Default::default()
1183 };
1184
1185 let response = RelayerResponse::from(repo_model);
1187
1188 assert!(response.policies.is_some());
1190
1191 let serialized = serde_json::to_string(&response).unwrap();
1193 assert!(
1194 serialized.contains("policies"),
1195 "User-provided Stellar policies should appear in JSON response"
1196 );
1197 assert!(
1198 serialized.contains("max_fee"),
1199 "User-provided Stellar policy values should appear in JSON response"
1200 );
1201 assert!(
1202 serialized.contains("timeout_seconds"),
1203 "User-provided Stellar policy values should appear in JSON response"
1204 );
1205 assert!(
1206 serialized.contains("allowed_tokens"),
1207 "User-provided Stellar policy values should appear in JSON response"
1208 );
1209 assert!(
1210 serialized.contains("fee_payment_strategy"),
1211 "User-provided Stellar policy values should appear in JSON response"
1212 );
1213 assert!(
1214 serialized.contains("slippage_percentage"),
1215 "User-provided Stellar policy values should appear in JSON response"
1216 );
1217 assert!(
1218 serialized.contains("fee_margin_percentage"),
1219 "User-provided Stellar policy values should appear in JSON response"
1220 );
1221 assert!(
1222 serialized.contains("swap_config"),
1223 "User-provided Stellar policy values should appear in JSON response"
1224 );
1225 }
1226
1227 #[test]
1228 fn test_stellar_fee_payment_strategy_explicitly_set_vs_omitted() {
1229 let policy_with_user = RelayerStellarPolicy {
1231 min_balance: Some(20000000),
1232 max_fee: Some(100000),
1233 timeout_seconds: Some(30),
1234 concurrent_transactions: None,
1235 allowed_tokens: None,
1236 fee_payment_strategy: Some(StellarFeePaymentStrategy::User),
1237 slippage_percentage: None,
1238 fee_margin_percentage: None,
1239 swap_config: None,
1240 };
1241
1242 let response_with_user = StellarPolicyResponse::from(policy_with_user);
1243 let serialized_with_user = serde_json::to_string(&response_with_user).unwrap();
1244 assert!(
1245 serialized_with_user.contains(r#""fee_payment_strategy":"user""#),
1246 "Explicitly set User fee_payment_strategy should appear in JSON response"
1247 );
1248
1249 let policy_with_relayer = RelayerStellarPolicy {
1251 min_balance: Some(20000000),
1252 max_fee: Some(100000),
1253 timeout_seconds: Some(30),
1254 concurrent_transactions: None,
1255 allowed_tokens: None,
1256 fee_payment_strategy: Some(StellarFeePaymentStrategy::Relayer),
1257 slippage_percentage: None,
1258 fee_margin_percentage: None,
1259 swap_config: None,
1260 };
1261
1262 let response_with_relayer = StellarPolicyResponse::from(policy_with_relayer);
1263 let serialized_with_relayer = serde_json::to_string(&response_with_relayer).unwrap();
1264 assert!(
1265 serialized_with_relayer.contains(r#""fee_payment_strategy":"relayer""#),
1266 "Explicitly set Relayer fee_payment_strategy should appear in JSON response"
1267 );
1268
1269 let policy_omitted = RelayerStellarPolicy {
1271 min_balance: Some(20000000),
1272 max_fee: Some(100000),
1273 timeout_seconds: Some(30),
1274 concurrent_transactions: None,
1275 allowed_tokens: None,
1276 fee_payment_strategy: None,
1277 slippage_percentage: None,
1278 fee_margin_percentage: None,
1279 swap_config: None,
1280 };
1281
1282 let response_omitted = StellarPolicyResponse::from(policy_omitted);
1283 let serialized_omitted = serde_json::to_string(&response_omitted).unwrap();
1284 assert!(
1285 !serialized_omitted.contains("fee_payment_strategy"),
1286 "Omitted fee_payment_strategy (None) should NOT appear in JSON response"
1287 );
1288
1289 let empty_policy = RelayerStellarPolicy::default();
1291 assert!(
1292 is_empty_policy(&RelayerNetworkPolicy::Stellar(empty_policy)),
1293 "Policy with all None values should be considered empty"
1294 );
1295
1296 let policy_with_user_only = RelayerStellarPolicy {
1297 fee_payment_strategy: Some(StellarFeePaymentStrategy::User),
1298 ..Default::default()
1299 };
1300 assert!(
1301 !is_empty_policy(&RelayerNetworkPolicy::Stellar(policy_with_user_only)),
1302 "Policy with explicitly set User fee_payment_strategy should NOT be considered empty"
1303 );
1304
1305 let policy_with_relayer_only = RelayerStellarPolicy {
1306 fee_payment_strategy: Some(StellarFeePaymentStrategy::Relayer),
1307 ..Default::default()
1308 };
1309 assert!(
1310 !is_empty_policy(&RelayerNetworkPolicy::Stellar(policy_with_relayer_only)),
1311 "Policy with explicitly set Relayer fee_payment_strategy should NOT be considered empty"
1312 );
1313 }
1314
1315 #[test]
1316 fn test_relayer_status_serialization() {
1317 let evm_status = RelayerStatus::Evm {
1319 balance: "1000000000000000000".to_string(),
1320 pending_transactions_count: 5,
1321 last_confirmed_transaction_timestamp: Some("2024-01-01T00:00:00Z".to_string()),
1322 system_disabled: false,
1323 paused: false,
1324 nonce: "42".to_string(),
1325 };
1326
1327 let serialized = serde_json::to_string(&evm_status).unwrap();
1328 assert!(serialized.contains(r#""network_type":"evm""#));
1329 assert!(serialized.contains(r#""nonce":"42""#));
1330 assert!(serialized.contains(r#""balance":"1000000000000000000""#));
1331
1332 let solana_status = RelayerStatus::Solana {
1334 balance: "5000000000".to_string(),
1335 pending_transactions_count: 3,
1336 last_confirmed_transaction_timestamp: None,
1337 system_disabled: false,
1338 paused: true,
1339 };
1340
1341 let serialized = serde_json::to_string(&solana_status).unwrap();
1342 assert!(serialized.contains(r#""network_type":"solana""#));
1343 assert!(serialized.contains(r#""balance":"5000000000""#));
1344 assert!(serialized.contains(r#""paused":true"#));
1345
1346 let stellar_status = RelayerStatus::Stellar {
1348 balance: "1000000000".to_string(),
1349 pending_transactions_count: 2,
1350 last_confirmed_transaction_timestamp: Some("2024-01-01T12:00:00Z".to_string()),
1351 system_disabled: true,
1352 paused: false,
1353 sequence_number: "123456789".to_string(),
1354 };
1355
1356 let serialized = serde_json::to_string(&stellar_status).unwrap();
1357 assert!(serialized.contains(r#""network_type":"stellar""#));
1358 assert!(serialized.contains(r#""sequence_number":"123456789""#));
1359 assert!(serialized.contains(r#""system_disabled":true"#));
1360 }
1361
1362 #[test]
1363 fn test_relayer_status_deserialization() {
1364 let evm_json = r#"{
1366 "network_type": "evm",
1367 "balance": "1000000000000000000",
1368 "pending_transactions_count": 5,
1369 "last_confirmed_transaction_timestamp": "2024-01-01T00:00:00Z",
1370 "system_disabled": false,
1371 "paused": false,
1372 "nonce": "42"
1373 }"#;
1374
1375 let status: RelayerStatus = serde_json::from_str(evm_json).unwrap();
1376 if let RelayerStatus::Evm { nonce, balance, .. } = status {
1377 assert_eq!(nonce, "42");
1378 assert_eq!(balance, "1000000000000000000");
1379 } else {
1380 panic!("Expected EVM status");
1381 }
1382
1383 let solana_json = r#"{
1385 "network_type": "solana",
1386 "balance": "5000000000",
1387 "pending_transactions_count": 3,
1388 "last_confirmed_transaction_timestamp": null,
1389 "system_disabled": false,
1390 "paused": true
1391 }"#;
1392
1393 let status: RelayerStatus = serde_json::from_str(solana_json).unwrap();
1394 if let RelayerStatus::Solana {
1395 balance, paused, ..
1396 } = status
1397 {
1398 assert_eq!(balance, "5000000000");
1399 assert!(paused);
1400 } else {
1401 panic!("Expected Solana status");
1402 }
1403
1404 let stellar_json = r#"{
1406 "network_type": "stellar",
1407 "balance": "1000000000",
1408 "pending_transactions_count": 2,
1409 "last_confirmed_transaction_timestamp": "2024-01-01T12:00:00Z",
1410 "system_disabled": true,
1411 "paused": false,
1412 "sequence_number": "123456789"
1413 }"#;
1414
1415 let status: RelayerStatus = serde_json::from_str(stellar_json).unwrap();
1416 if let RelayerStatus::Stellar {
1417 sequence_number,
1418 system_disabled,
1419 ..
1420 } = status
1421 {
1422 assert_eq!(sequence_number, "123456789");
1423 assert!(system_disabled);
1424 } else {
1425 panic!("Expected Stellar status");
1426 }
1427 }
1428}