pop_chains/
deployer_providers.rs1use std::time::{SystemTime, UNIX_EPOCH};
4use strum::{EnumMessage as _, EnumProperty as _};
5use strum_macros::{AsRefStr, Display, EnumMessage, EnumProperty, EnumString, VariantArray};
6
7#[derive(
9 AsRefStr,
10 Clone,
11 Debug,
12 Display,
13 EnumMessage,
14 EnumString,
15 EnumProperty,
16 Eq,
17 PartialEq,
18 VariantArray,
19)]
20pub enum DeploymentProvider {
21 #[strum(
24 ascii_case_insensitive,
25 serialize = "pdp",
26 message = "Polkadot Deployment Portal",
27 detailed_message = "Effortlessly deploy Polkadot Native Chains on the Polkadot Cloud",
28 props(
29 BaseURL = "https://staging.deploypolkadot.xyz",
30 CollatorKeysURI = "/api/public/v1/parachains/{para_id}/collators/{chain_name}",
31 DeployURI = "/api/public/v1/parachains/{para_id}/resources",
32 )
33 )]
34 PDP,
35}
36
37impl DeploymentProvider {
38 pub fn name(&self) -> &'static str {
40 self.get_message().unwrap_or_default()
41 }
42
43 pub fn description(&self) -> &'static str {
45 self.get_detailed_message().unwrap_or_default()
46 }
47
48 pub fn base_url(&self) -> &'static str {
50 self.get_str("BaseURL").unwrap_or("")
51 }
52
53 pub fn get_collator_keys_uri(&self, relay_chain_name: &str, id: u32) -> String {
59 self.get_str("CollatorKeysURI")
60 .map(|template| {
61 template
62 .replace("{para_id}", &id.to_string())
63 .replace("{chain_name}", relay_chain_name)
64 })
65 .unwrap_or_default()
66 }
67
68 pub fn get_deploy_uri(&self, id: u32) -> String {
73 self.get_str("DeployURI")
74 .map(|template| template.replace("{para_id}", &id.to_string()))
75 .unwrap_or_default()
76 }
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumString, Display, VariantArray, clap::ValueEnum)]
81pub enum SupportedChains {
82 PASEO,
84 WESTEND,
86 KUSAMA,
88 POLKADOT,
90}
91
92const PASEO_RPC_URLS: &[&str] = &[
94 "wss://paseo.dotters.network",
95 "wss://rpc.ibp.network/paseo",
96 "wss://pas-rpc.stakeworld.io",
97 "wss://paseo-rpc.dwellir.com",
98 "wss://paseo.rpc.amforc.com",
99];
100
101const WESTEND_RPC_URLS: &[&str] = &[
102 "wss://westend-rpc.polkadot.io",
103 "wss://westend-rpc.dwellir.com",
104 "wss://westend-rpc-tn.dwellir.com",
105 "wss://rpc.ibp.network/westend",
106 "wss://westend.dotters.network",
107];
108
109const KUSAMA_RPC_URLS: &[&str] = &[
110 "wss://kusama-rpc.publicnode.com",
111 "wss://kusama-rpc.dwellir.com",
112 "wss://kusama-rpc-tn.dwellir.com",
113 "wss://rpc.ibp.network/kusama",
114 "wss://kusama.dotters.network",
115];
116
117const POLKADOT_RPC_URLS: &[&str] = &[
118 "wss://polkadot-rpc.publicnode.com",
119 "wss://polkadot-public-rpc.blockops.network/ws",
120 "wss://polkadot-rpc.dwellir.com",
121 "wss://rpc.ibp.network/polkadot",
122 "wss://polkadot.dotters.network",
123];
124
125impl SupportedChains {
126 pub fn get_rpc_url(&self) -> Option<String> {
128 let chain_urls = self.rpc_urls();
129 chain_urls
131 .get(
132 (SystemTime::now().duration_since(UNIX_EPOCH).ok()?.as_millis() as usize) %
133 chain_urls.len(),
134 )
135 .map(|s| s.to_string())
136 }
137 pub fn rpc_urls(&self) -> &'static [&'static str] {
139 match self {
140 SupportedChains::PASEO => PASEO_RPC_URLS,
141 SupportedChains::WESTEND => WESTEND_RPC_URLS,
142 SupportedChains::KUSAMA => KUSAMA_RPC_URLS,
143 SupportedChains::POLKADOT => POLKADOT_RPC_URLS,
144 }
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151 use strum::VariantArray;
152
153 #[test]
154 fn get_name_works() {
155 assert_eq!(DeploymentProvider::PDP.name(), "Polkadot Deployment Portal");
156 }
157
158 #[test]
159 fn get_description_works() {
160 assert_eq!(
161 DeploymentProvider::PDP.description(),
162 "Effortlessly deploy Polkadot Native Chains on the Polkadot Cloud"
163 );
164 }
165
166 #[test]
167 fn base_url_works() {
168 let provider = DeploymentProvider::PDP;
169 assert_eq!(provider.base_url(), "https://staging.deploypolkadot.xyz");
170 }
171
172 #[test]
173 fn get_collator_keys_uri_works() {
174 let provider = DeploymentProvider::PDP;
175 assert_eq!(
176 provider.get_collator_keys_uri("paseo", 2000),
177 "/api/public/v1/parachains/2000/collators/paseo"
178 );
179 }
180
181 #[test]
182 fn get_deploy_uri_works() {
183 let provider = DeploymentProvider::PDP;
184 assert_eq!(provider.get_deploy_uri(2000), "/api/public/v1/parachains/2000/resources");
185 }
186
187 #[test]
188 fn ensures_get_rpc_url_returns_valid_url() {
189 for chain in SupportedChains::VARIANTS {
190 let rpc = chain.get_rpc_url();
191 assert!(rpc.is_some() && chain.rpc_urls().contains(&rpc.as_deref().unwrap()));
192 }
193 }
194
195 #[test]
196 fn rpc_urls_returns_valid_wss_endpoints_for_all_variants() {
197 for chain in SupportedChains::VARIANTS {
198 let urls = chain.rpc_urls();
199 assert!(!urls.is_empty(), "rpc_urls() should return at least one URL for {:?}", chain);
200 for url in urls {
201 assert!(
202 url.starts_with("wss://"),
203 "RPC URL should use wss:// scheme, got: {}",
204 url
205 );
206 }
207 }
208 }
209}