cosm_script/data_structures/
network.rs1use crate::cosm_denom_format;
2use crate::error::CosmScriptError;
3use cosmrs::Denom;
4use serde::{Deserialize, Serialize};
5use serde_json::{from_reader, from_value, json, to_value, Value};
6use std::{env, fs::File, str::FromStr};
7use tonic::transport::Channel;
8
9#[derive(Clone, Debug)]
10pub struct Network {
11 pub kind: NetworkKind,
13 pub id: String,
15 pub grpc_channel: Channel,
17 pub chain: Chain,
19 pub gas_denom: Denom,
21 pub gas_price: f64,
23 pub lcd_url: Option<String>,
25 pub fcd_url: Option<String>,
26}
27
28impl Network {
29 pub fn get(&self) -> Result<Value, CosmScriptError> {
30 let file = File::open(&self.chain.file_path)
31 .unwrap_or_else(|_| panic!("file should be present at {}", self.chain.file_path));
32 let json: serde_json::Value = from_reader(file)?;
33 Ok(json[&self.chain.chain_id]["networks"][&self.kind.to_string()].clone())
34 }
35
36 pub fn set(&self, value: Value) -> Result<(), CosmScriptError> {
37 let file = File::open(&self.chain.file_path)
38 .unwrap_or_else(|_| panic!("file should be present at {}", self.chain.file_path));
39 let mut json: serde_json::Value = from_reader(file).unwrap();
40 json[&self.chain.chain_id]["networks"][&self.kind.to_string()] = json!(value);
41 serde_json::to_writer_pretty(File::create(&self.chain.file_path)?, &json)?;
42 Ok(())
43 }
44
45 pub fn get_latest_version(&self, contract_name: &str) -> Result<u64, CosmScriptError> {
47 let network = self.get()?;
48 let maybe_code_id = network["code_ids"].get(contract_name);
49 match maybe_code_id {
50 Some(code_id) => Ok(code_id.as_u64().unwrap()),
51 None => Err(CosmScriptError::CodeIdNotInFile(contract_name.to_owned())),
52 }
53 }
54
55 pub fn set_contract_version(
57 &self,
58 contract_name: &str,
59 code_id: u64,
60 ) -> Result<(), CosmScriptError> {
61 let mut network = self.get()?;
62 network["code_ids"][contract_name] = to_value(code_id)?;
63 self.set(network)
64 }
65}
66
67#[derive(Clone, Debug, Serialize, Deserialize)]
68pub struct NetworkInfo {
69 pub id: String,
71 #[serde(with = "cosm_denom_format")]
73 pub gas_denom: Denom,
74 pub gas_price: f64,
76 pub grpc_url: String,
77 pub lcd_url: Option<String>,
79 pub fcd_url: Option<String>,
80}
81
82impl Default for NetworkInfo {
83 fn default() -> Self {
84 Self {
85 gas_denom: Denom::from_str("").unwrap(),
86 id: String::default(),
87 gas_price: 0f64,
88 grpc_url: String::default(),
89 lcd_url: None,
90 fcd_url: None,
91 }
92 }
93}
94
95impl NetworkInfo {
96 pub async fn into_network(
97 self,
98 kind: NetworkKind,
99 chain: &Chain,
100 ) -> Result<Network, CosmScriptError> {
101 let grpc_channel = Channel::from_shared(self.grpc_url)
102 .unwrap()
103 .connect()
104 .await?;
105
106 Ok(Network {
107 kind,
108 grpc_channel,
109 chain: chain.clone(),
110 id: self.id,
111 gas_denom: self.gas_denom,
112 gas_price: self.gas_price,
113 lcd_url: self.lcd_url,
114 fcd_url: self.fcd_url,
115 })
116 }
117}
118
119#[derive(Clone, Debug)]
120pub struct Chain {
121 pub chain_id: String,
123 pub pub_addr_prefix: String,
125 pub coin_type: u32,
127
128 pub file_path: String,
129}
130
131#[derive(Clone, Debug, Serialize, Deserialize, Default)]
132pub struct ChainInfo {
133 pub pub_addr_prefix: String,
135 pub coin_type: u32,
137}
138
139impl Chain {
140 pub async fn new(chain_id: &str, store_path: &str) -> Result<Self, CosmScriptError> {
141 let file =
142 File::open(store_path).unwrap_or_else(|_| panic!("file not present at {}", store_path));
143 let mut config: serde_json::Value = from_reader(file)?;
144
145 match config.get(chain_id) {
146 Some(chain) => {
147 let info: ChainInfo = from_value(chain["info"].clone())?;
148 if info.pub_addr_prefix == "FILL" {
149 return Err(CosmScriptError::NewChain(store_path.into()));
150 };
151 Ok(Self {
152 chain_id: chain_id.into(),
153 pub_addr_prefix: info.pub_addr_prefix,
154 coin_type: info.coin_type,
155 file_path: store_path.into(),
156 })
157 }
158 None => {
159 let info = ChainInfo {
160 coin_type: 118u32,
161 pub_addr_prefix: "FILL".into(),
162 };
163 config[chain_id] = json!(
164 {
165 "info": info,
166 "networks": {}
167 }
168 );
169 serde_json::to_writer_pretty(File::create(&store_path)?, &config)?;
170 Err(CosmScriptError::NewChain(store_path.into()))
171 }
172 }
173 }
174
175 pub async fn network(&self) -> Result<Network, CosmScriptError> {
176 let file = File::open(&self.file_path)
177 .unwrap_or_else(|_| panic!("file present at {}", self.file_path));
178 let mut config: serde_json::Value = from_reader(file)?;
179
180 let network_kind = NetworkKind::new()?;
181
182 let network = config[&self.chain_id]["networks"].get(network_kind.to_string());
183
184 match network {
185 Some(network) => {
186 let info: NetworkInfo = from_value(network["info"].clone())?;
187 if info.grpc_url == String::default() {
188 return Err(CosmScriptError::NewNetwork(self.file_path.clone()));
189 }
190 info.into_network(network_kind, self).await
191 }
192 None => {
194 let info = NetworkInfo::default();
195 config[&self.chain_id]["networks"][network_kind.to_string()] = json!(
196 {
197 "info": info,
198 "code_ids": {},
199 "deployments": {}
200 }
201 );
202 serde_json::to_writer_pretty(File::create(&self.file_path)?, &config)?;
203 Err(CosmScriptError::NewNetwork(self.file_path.clone()))
204 }
205 }
206 }
207}
208
209#[derive(Clone, Debug, Serialize, Deserialize)]
210pub enum NetworkKind {
211 Local,
212 Mainnet,
213 Testnet,
214}
215
216impl NetworkKind {
217 pub fn new() -> Result<Self, CosmScriptError> {
218 let network_id = env::var("NETWORK")?;
219 let network = match network_id.as_str() {
220 "testnet" => NetworkKind::Testnet,
221 "mainnet" => NetworkKind::Mainnet,
222 _ => NetworkKind::Local,
223 };
224 Ok(network)
225 }
226
227 pub fn mnemonic_name(&self) -> &str {
228 match *self {
229 NetworkKind::Local => "LOCAL_MNEMONIC",
230 NetworkKind::Mainnet => "MAIN_MNEMONIC",
231 NetworkKind::Testnet => "TEST_MNEMONIC",
232 }
233 }
234
235 pub fn multisig_name(&self) -> &str {
236 match *self {
237 NetworkKind::Local => "LOCAL_MULTISIG",
238 NetworkKind::Mainnet => "MAIN_MULTISIG",
239 NetworkKind::Testnet => "TEST_MULTISIG",
240 }
241 }
242}
243
244impl ToString for NetworkKind {
245 fn to_string(&self) -> String {
246 match *self {
247 NetworkKind::Local => "local",
248 NetworkKind::Mainnet => "mainnet",
249 NetworkKind::Testnet => "testnet",
250 }
251 .into()
252 }
253}