1use crate::{
21 error::{self, Error},
22 OutputType,
23};
24use serde_json::json;
25use sp_core::{
26 crypto::{
27 unwrap_or_default_ss58_version, ExposeSecret, SecretString, Ss58AddressFormat, Ss58Codec,
28 Zeroize,
29 },
30 hexdisplay::HexDisplay,
31 Pair,
32};
33use sp_runtime::{traits::IdentifyAccount, MultiSigner};
34use std::path::PathBuf;
35
36pub type PublicFor<P> = <P as sp_core::Pair>::Public;
38pub type SeedFor<P> = <P as sp_core::Pair>::Seed;
40
41pub fn read_uri(uri: Option<&String>) -> error::Result<String> {
43 let uri = if let Some(uri) = uri {
44 let file = PathBuf::from(&uri);
45 if file.is_file() {
46 std::fs::read_to_string(uri)?.trim_end().to_owned()
47 } else {
48 uri.into()
49 }
50 } else {
51 rpassword::prompt_password("URI: ")?
52 };
53
54 Ok(uri)
55}
56
57pub fn print_from_uri<Pair>(
67 uri: &str,
68 password: Option<SecretString>,
69 network_override: Option<Ss58AddressFormat>,
70 output: OutputType,
71) where
72 Pair: sp_core::Pair,
73 Pair::Public: Into<MultiSigner>,
74{
75 let password = password.as_ref().map(|s| s.expose_secret().as_str());
76 let network_id = String::from(unwrap_or_default_ss58_version(network_override));
77 if let Ok((pair, seed)) = Pair::from_phrase(uri, password) {
78 let public_key = pair.public();
79 let network_override = unwrap_or_default_ss58_version(network_override);
80
81 match output {
82 OutputType::Json => {
83 let json = json!({
84 "secretPhrase": uri,
85 "networkId": network_id,
86 "secretSeed": format_seed::<Pair>(seed),
87 "publicKey": format_public_key::<Pair>(public_key.clone()),
88 "ss58PublicKey": public_key.to_ss58check_with_version(network_override),
89 "accountId": format_account_id::<Pair>(public_key),
90 "ss58Address": pair.public().into().into_account().to_ss58check_with_version(network_override),
91 });
92 println!(
93 "{}",
94 serde_json::to_string_pretty(&json).expect("Json pretty print failed")
95 );
96 },
97 OutputType::Text => {
98 println!(
99 "Secret phrase: {}\n \
100 Network ID: {}\n \
101 Secret seed: {}\n \
102 Public key (hex): {}\n \
103 Account ID: {}\n \
104 Public key (SS58): {}\n \
105 SS58 Address: {}",
106 uri,
107 network_id,
108 format_seed::<Pair>(seed),
109 format_public_key::<Pair>(public_key.clone()),
110 format_account_id::<Pair>(public_key.clone()),
111 public_key.to_ss58check_with_version(network_override),
112 pair.public().into().into_account().to_ss58check_with_version(network_override),
113 );
114 },
115 }
116 } else if let Ok((pair, seed)) = Pair::from_string_with_seed(uri, password) {
117 let public_key = pair.public();
118 let network_override = unwrap_or_default_ss58_version(network_override);
119
120 match output {
121 OutputType::Json => {
122 let json = json!({
123 "secretKeyUri": uri,
124 "networkId": network_id,
125 "secretSeed": if let Some(seed) = seed { format_seed::<Pair>(seed) } else { "n/a".into() },
126 "publicKey": format_public_key::<Pair>(public_key.clone()),
127 "ss58PublicKey": public_key.to_ss58check_with_version(network_override),
128 "accountId": format_account_id::<Pair>(public_key),
129 "ss58Address": pair.public().into().into_account().to_ss58check_with_version(network_override),
130 });
131 println!(
132 "{}",
133 serde_json::to_string_pretty(&json).expect("Json pretty print failed")
134 );
135 },
136 OutputType::Text => {
137 println!(
138 "Secret Key URI `{}` is account:\n \
139 Network ID: {}\n \
140 Secret seed: {}\n \
141 Public key (hex): {}\n \
142 Account ID: {}\n \
143 Public key (SS58): {}\n \
144 SS58 Address: {}",
145 uri,
146 network_id,
147 if let Some(seed) = seed { format_seed::<Pair>(seed) } else { "n/a".into() },
148 format_public_key::<Pair>(public_key.clone()),
149 format_account_id::<Pair>(public_key.clone()),
150 public_key.to_ss58check_with_version(network_override),
151 pair.public().into().into_account().to_ss58check_with_version(network_override),
152 );
153 },
154 }
155 } else if let Ok((public_key, network)) = Pair::Public::from_string_with_version(uri) {
156 let network_override = network_override.unwrap_or(network);
157
158 match output {
159 OutputType::Json => {
160 let json = json!({
161 "publicKeyUri": uri,
162 "networkId": String::from(network_override),
163 "publicKey": format_public_key::<Pair>(public_key.clone()),
164 "accountId": format_account_id::<Pair>(public_key.clone()),
165 "ss58PublicKey": public_key.to_ss58check_with_version(network_override),
166 "ss58Address": public_key.to_ss58check_with_version(network_override),
167 });
168
169 println!(
170 "{}",
171 serde_json::to_string_pretty(&json).expect("Json pretty print failed")
172 );
173 },
174 OutputType::Text => {
175 println!(
176 "Public Key URI `{}` is account:\n \
177 Network ID/Version: {}\n \
178 Public key (hex): {}\n \
179 Account ID: {}\n \
180 Public key (SS58): {}\n \
181 SS58 Address: {}",
182 uri,
183 String::from(network_override),
184 format_public_key::<Pair>(public_key.clone()),
185 format_account_id::<Pair>(public_key.clone()),
186 public_key.to_ss58check_with_version(network_override),
187 public_key.to_ss58check_with_version(network_override),
188 );
189 },
190 }
191 } else {
192 println!("Invalid phrase/URI given");
193 }
194}
195
196pub fn print_from_public<Pair>(
198 public_str: &str,
199 network_override: Option<Ss58AddressFormat>,
200 output: OutputType,
201) -> Result<(), Error>
202where
203 Pair: sp_core::Pair,
204 Pair::Public: Into<MultiSigner>,
205{
206 let public = array_bytes::hex2bytes(public_str)?;
207
208 let public_key = Pair::Public::try_from(&public)
209 .map_err(|_| "Failed to construct public key from given hex")?;
210
211 let network_override = unwrap_or_default_ss58_version(network_override);
212
213 match output {
214 OutputType::Json => {
215 let json = json!({
216 "networkId": String::from(network_override),
217 "publicKey": format_public_key::<Pair>(public_key.clone()),
218 "accountId": format_account_id::<Pair>(public_key.clone()),
219 "ss58PublicKey": public_key.to_ss58check_with_version(network_override),
220 "ss58Address": public_key.to_ss58check_with_version(network_override),
221 });
222
223 println!("{}", serde_json::to_string_pretty(&json).expect("Json pretty print failed"));
224 },
225 OutputType::Text => {
226 println!(
227 "Network ID/Version: {}\n \
228 Public key (hex): {}\n \
229 Account ID: {}\n \
230 Public key (SS58): {}\n \
231 SS58 Address: {}",
232 String::from(network_override),
233 format_public_key::<Pair>(public_key.clone()),
234 format_account_id::<Pair>(public_key.clone()),
235 public_key.to_ss58check_with_version(network_override),
236 public_key.to_ss58check_with_version(network_override),
237 );
238 },
239 }
240
241 Ok(())
242}
243
244pub fn pair_from_suri<P: Pair>(suri: &str, password: Option<SecretString>) -> Result<P, Error> {
246 let result = if let Some(pass) = password {
247 let mut pass_str = pass.expose_secret().clone();
248 let pair = P::from_string(suri, Some(&pass_str));
249 pass_str.zeroize();
250 pair
251 } else {
252 P::from_string(suri, None)
253 };
254
255 Ok(result.map_err(|err| format!("Invalid phrase {:?}", err))?)
256}
257
258pub fn format_seed<P: sp_core::Pair>(seed: SeedFor<P>) -> String {
260 format!("0x{}", HexDisplay::from(&seed.as_ref()))
261}
262
263fn format_public_key<P: sp_core::Pair>(public_key: PublicFor<P>) -> String {
265 format!("0x{}", HexDisplay::from(&public_key.as_ref()))
266}
267
268fn format_account_id<P: sp_core::Pair>(public_key: PublicFor<P>) -> String
270where
271 PublicFor<P>: Into<MultiSigner>,
272{
273 format!("0x{}", HexDisplay::from(&public_key.into().into_account().as_ref()))
274}
275
276#[macro_export]
278macro_rules! with_crypto_scheme {
279 (
280 $scheme:expr,
281 $method:ident ( $($params:expr),* $(,)?) $(,)?
282 ) => {
283 $crate::with_crypto_scheme!($scheme, $method<>($($params),*))
284 };
285 (
286 $scheme:expr,
287 $method:ident<$($generics:ty),*>( $( $params:expr ),* $(,)?) $(,)?
288 ) => {
289 match $scheme {
290 $crate::CryptoScheme::Ecdsa => {
291 $method::<sp_core::ecdsa::Pair, $($generics),*>($($params),*)
292 }
293 $crate::CryptoScheme::Sr25519 => {
294 $method::<sp_core::sr25519::Pair, $($generics),*>($($params),*)
295 }
296 $crate::CryptoScheme::Ed25519 => {
297 $method::<sp_core::ed25519::Pair, $($generics),*>($($params),*)
298 }
299 }
300 };
301}