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}
24
25impl TryFrom<NetworkRepoModel> for StellarNetwork {
26 type Error = RepositoryError;
27
28 fn try_from(network_repo: NetworkRepoModel) -> Result<Self, Self::Error> {
36 match &network_repo.config {
37 NetworkConfigData::Stellar(stellar_config) => {
38 let common = &stellar_config.common;
39
40 let rpc_urls = common.rpc_urls.clone().ok_or_else(|| {
41 RepositoryError::InvalidData(format!(
42 "Stellar network '{}' has no rpc_urls",
43 network_repo.name
44 ))
45 })?;
46
47 let average_blocktime_ms = common.average_blocktime_ms.ok_or_else(|| {
48 RepositoryError::InvalidData(format!(
49 "Stellar network '{}' has no average_blocktime_ms",
50 network_repo.name
51 ))
52 })?;
53
54 let passphrase = stellar_config.passphrase.clone().ok_or_else(|| {
55 RepositoryError::InvalidData(format!(
56 "Stellar network '{}' has no passphrase",
57 network_repo.name
58 ))
59 })?;
60
61 Ok(StellarNetwork {
62 network: common.network.clone(),
63 rpc_urls,
64 explorer_urls: common.explorer_urls.clone(),
65 average_blocktime_ms,
66 is_testnet: common.is_testnet.unwrap_or(false),
67 tags: common.tags.clone().unwrap_or_default(),
68 passphrase,
69 })
70 }
71 _ => Err(RepositoryError::InvalidData(format!(
72 "Network '{}' is not a Stellar network",
73 network_repo.name
74 ))),
75 }
76 }
77}
78
79impl StellarNetwork {
80 pub fn network_id(&self) -> Hash {
81 let passphrase = self.passphrase.clone();
82 let hash_bytes: [u8; 32] = Sha256::digest(passphrase.as_bytes()).into();
83 Hash(hash_bytes)
84 }
85
86 pub fn average_blocktime(&self) -> Option<Duration> {
87 Some(Duration::from_millis(self.average_blocktime_ms))
88 }
89
90 pub fn public_rpc_urls(&self) -> Option<&[String]> {
91 if self.rpc_urls.is_empty() {
92 None
93 } else {
94 Some(&self.rpc_urls)
95 }
96 }
97
98 pub fn explorer_urls(&self) -> Option<&[String]> {
99 self.explorer_urls.as_deref()
100 }
101
102 pub fn is_testnet(&self) -> bool {
103 self.is_testnet
104 }
105}