sui_sdk/
sui_client_config.rs1use std::fmt::{Display, Formatter, Write};
5
6use anyhow::anyhow;
7use serde::{Deserialize, Serialize};
8use serde_with::serde_as;
9
10use crate::{SUI_DEVNET_URL, SUI_LOCAL_NETWORK_URL, SUI_TESTNET_URL, SuiClient, SuiClientBuilder};
11use sui_config::Config;
12use sui_keys::keystore::{AccountKeystore, Keystore};
13use sui_types::base_types::*;
14
15#[serde_as]
16#[derive(Serialize, Deserialize)]
17pub struct SuiClientConfig {
18 pub keystore: Keystore,
20 pub external_keys: Option<Keystore>,
22 pub envs: Vec<SuiEnv>,
24 pub active_env: Option<String>,
26 pub active_address: Option<SuiAddress>,
28}
29
30impl SuiClientConfig {
31 pub fn new(keystore: Keystore) -> Self {
32 SuiClientConfig {
33 keystore,
34 external_keys: None,
35 envs: vec![],
36 active_env: None,
37 active_address: None,
38 }
39 }
40
41 pub fn get_env(&self, alias: &Option<String>) -> Option<&SuiEnv> {
42 if let Some(alias) = alias {
43 self.envs.iter().find(|env| &env.alias == alias)
44 } else {
45 self.envs.first()
46 }
47 }
48
49 pub fn get_active_env(&self) -> Result<&SuiEnv, anyhow::Error> {
50 self.get_env(&self.active_env).ok_or_else(|| {
51 anyhow!(
52 "Environment configuration not found for env [{}]",
53 self.active_env.as_deref().unwrap_or("None")
54 )
55 })
56 }
57
58 pub fn add_env(&mut self, env: SuiEnv) {
59 if !self
60 .envs
61 .iter()
62 .any(|other_env| other_env.alias == env.alias)
63 {
64 self.envs.push(env)
65 }
66 }
67
68 pub fn update_env_chain_id(
70 &mut self,
71 alias: &str,
72 chain_id: String,
73 ) -> Result<(), anyhow::Error> {
74 let env = self
75 .envs
76 .iter_mut()
77 .find(|env| env.alias == alias)
78 .ok_or_else(|| anyhow!("Environment {} not found", alias))?;
79 env.chain_id = Some(chain_id);
80 Ok(())
81 }
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct SuiEnv {
86 pub alias: String,
87 pub rpc: String,
88 pub ws: Option<String>,
89 pub basic_auth: Option<String>,
91 #[serde(skip_serializing_if = "Option::is_none")]
93 pub chain_id: Option<String>,
94}
95
96impl SuiEnv {
97 pub async fn create_rpc_client(
98 &self,
99 request_timeout: Option<std::time::Duration>,
100 max_concurrent_requests: Option<u64>,
101 ) -> Result<SuiClient, anyhow::Error> {
102 let mut builder = SuiClientBuilder::default();
103 if let Some(request_timeout) = request_timeout {
104 builder = builder.request_timeout(request_timeout);
105 }
106 if let Some(ws_url) = &self.ws {
107 builder = builder.ws_url(ws_url);
108 }
109 if let Some(basic_auth) = &self.basic_auth {
110 let fields: Vec<_> = basic_auth.split(':').collect();
111 if fields.len() != 2 {
112 return Err(anyhow!(
113 "Basic auth should be in the format `username:password`"
114 ));
115 }
116 builder = builder.basic_auth(fields[0], fields[1]);
117 }
118
119 if let Some(max_concurrent_requests) = max_concurrent_requests {
120 builder = builder.max_concurrent_requests(max_concurrent_requests as usize);
121 }
122 Ok(builder.build(&self.rpc).await?)
123 }
124
125 pub fn devnet() -> Self {
126 Self {
127 alias: "devnet".to_string(),
128 rpc: SUI_DEVNET_URL.into(),
129 ws: None,
130 basic_auth: None,
131 chain_id: None,
132 }
133 }
134 pub fn testnet() -> Self {
135 Self {
136 alias: "testnet".to_string(),
137 rpc: SUI_TESTNET_URL.into(),
138 ws: None,
139 basic_auth: None,
140 chain_id: None,
141 }
142 }
143
144 pub fn localnet() -> Self {
145 Self {
146 alias: "local".to_string(),
147 rpc: SUI_LOCAL_NETWORK_URL.into(),
148 ws: None,
149 basic_auth: None,
150 chain_id: None,
151 }
152 }
153}
154
155impl Display for SuiEnv {
156 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
157 let mut writer = String::new();
158 writeln!(writer, "Active environment : {}", self.alias)?;
159 write!(writer, "RPC URL: {}", self.rpc)?;
160 if let Some(ws) = &self.ws {
161 writeln!(writer)?;
162 write!(writer, "Websocket URL: {ws}")?;
163 }
164 if let Some(basic_auth) = &self.basic_auth {
165 writeln!(writer)?;
166 write!(writer, "Basic Auth: {}", basic_auth)?;
167 }
168 if let Some(chain_id) = &self.chain_id {
169 writeln!(writer)?;
170 write!(writer, "Chain ID: {}", chain_id)?;
171 }
172 write!(f, "{}", writer)
173 }
174}
175
176impl Config for SuiClientConfig {}
177
178impl Display for SuiClientConfig {
179 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
180 let mut writer = String::new();
181
182 writeln!(
183 writer,
184 "Managed addresses : {}",
185 self.keystore.addresses().len()
186 )?;
187 write!(writer, "Active address: ")?;
188 match self.active_address {
189 Some(r) => writeln!(writer, "{}", r)?,
190 None => writeln!(writer, "None")?,
191 };
192 writeln!(writer, "{}", self.keystore)?;
193 if let Ok(env) = self.get_active_env() {
194 write!(writer, "{}", env)?;
195 }
196 write!(f, "{}", writer)
197 }
198}