openzeppelin_relayer/models/network/stellar/
network.rs1use crate::models::{NetworkConfigData, NetworkRepoModel, RepositoryError};
2use core::time::Duration;
3use serde::{Deserialize, Serialize};
4use sha2::{Digest, Sha256};
5use soroban_rs::xdr::Hash;
6
7#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
8pub struct StellarNetwork {
9 pub network: String,
11 pub rpc_urls: Vec<String>,
13 pub explorer_urls: Option<Vec<String>>,
15 pub average_blocktime_ms: u64,
17 pub is_testnet: bool,
19 pub tags: Vec<String>,
21 pub passphrase: String,
23 pub horizon_url: Option<String>,
25}
26
27impl TryFrom<NetworkRepoModel> for StellarNetwork {
28 type Error = RepositoryError;
29
30 fn try_from(network_repo: NetworkRepoModel) -> Result<Self, Self::Error> {
38 match &network_repo.config {
39 NetworkConfigData::Stellar(stellar_config) => {
40 let common = &stellar_config.common;
41
42 let rpc_urls = common.rpc_urls.clone().ok_or_else(|| {
43 RepositoryError::InvalidData(format!(
44 "Stellar network '{}' has no rpc_urls",
45 network_repo.name
46 ))
47 })?;
48
49 let average_blocktime_ms = common.average_blocktime_ms.ok_or_else(|| {
50 RepositoryError::InvalidData(format!(
51 "Stellar network '{}' has no average_blocktime_ms",
52 network_repo.name
53 ))
54 })?;
55
56 let passphrase = stellar_config.passphrase.clone().ok_or_else(|| {
57 RepositoryError::InvalidData(format!(
58 "Stellar network '{}' has no passphrase",
59 network_repo.name
60 ))
61 })?;
62
63 Ok(StellarNetwork {
64 network: common.network.clone(),
65 rpc_urls,
66 explorer_urls: common.explorer_urls.clone(),
67 average_blocktime_ms,
68 is_testnet: common.is_testnet.unwrap_or(false),
69 tags: common.tags.clone().unwrap_or_default(),
70 passphrase,
71 horizon_url: stellar_config.horizon_url.clone(),
72 })
73 }
74 _ => Err(RepositoryError::InvalidData(format!(
75 "Network '{}' is not a Stellar network",
76 network_repo.name
77 ))),
78 }
79 }
80}
81
82impl StellarNetwork {
83 pub fn network_id(&self) -> Hash {
84 let passphrase = self.passphrase.clone();
85 let hash_bytes: [u8; 32] = Sha256::digest(passphrase.as_bytes()).into();
86 Hash(hash_bytes)
87 }
88
89 pub fn average_blocktime(&self) -> Option<Duration> {
90 Some(Duration::from_millis(self.average_blocktime_ms))
91 }
92
93 pub fn public_rpc_urls(&self) -> Option<&[String]> {
94 if self.rpc_urls.is_empty() {
95 None
96 } else {
97 Some(&self.rpc_urls)
98 }
99 }
100
101 pub fn explorer_urls(&self) -> Option<&[String]> {
102 self.explorer_urls.as_deref()
103 }
104
105 pub fn is_testnet(&self) -> bool {
106 self.is_testnet
107 }
108}