From f7e93274bf8eba091a9590a16eec82497ca3347a Mon Sep 17 00:00:00 2001 From: tuxmain <tuxmain@zettascript.org> Date: Thu, 16 Mar 2023 23:03:58 +0100 Subject: [PATCH] style: rustfmt config --- rustfmt.toml | 9 + src/cache.rs | 96 +++-- src/commands/collective.rs | 175 ++++---- src/commands/expire.rs | 350 ++++++++-------- src/commands/identity.rs | 146 +++---- src/commands/net_test.rs | 166 ++++---- src/commands/oneshot.rs | 196 ++++----- src/commands/revocation.rs | 26 +- src/commands/smith.rs | 276 ++++++------ src/commands/sudo.rs | 18 +- src/commands/transfer.rs | 102 ++--- src/indexer.rs | 60 +-- src/keys.rs | 182 ++++---- src/main.rs | 838 ++++++++++++++++++------------------- 14 files changed, 1325 insertions(+), 1315 deletions(-) create mode 100644 rustfmt.toml diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..522c7de --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,9 @@ +hard_tabs = true +newline_style = "unix" + +unstable_features = true +format_code_in_doc_comments = true +format_macro_bodies = true +format_macro_matchers = true +format_strings = true +imports_granularity = "Crate" diff --git a/src/cache.rs b/src/cache.rs index 88ac9ab..b77206d 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,59 +1,57 @@ -use crate::gdev; -use crate::indexer::*; -use crate::Client; +use crate::{gdev, indexer::*, Client}; use anyhow::{anyhow, Result}; use std::collections::{hash_map, HashMap}; pub struct IdentityCache<'a> { - client: &'a Client, - identities: HashMap<u32, String>, - indexer: Option<Indexer<'a>>, + client: &'a Client, + identities: HashMap<u32, String>, + indexer: Option<Indexer<'a>>, } impl<'a> IdentityCache<'a> { - pub fn new(client: &'a Client, indexer: Option<Indexer<'a>>) -> Self { - Self { - client, - identities: HashMap::new(), - indexer, - } - } + pub fn new(client: &'a Client, indexer: Option<Indexer<'a>>) -> Self { + Self { + client, + identities: HashMap::new(), + indexer, + } + } - pub async fn fetch_identity( - &mut self, - identity_id: u32, - parent_hash: sp_core::H256, - ) -> Result<String> { - Ok(match self.identities.entry(identity_id) { - hash_map::Entry::Occupied(entry) => entry.get().clone(), - hash_map::Entry::Vacant(entry) => entry - .insert({ - let pubkey = self - .client - .storage() - .fetch( - &gdev::storage().identity().identities(identity_id), - Some(parent_hash), - ) - .await? - .ok_or_else(|| anyhow!("Identity {} not found", identity_id))? - .owner_key - .to_string(); - format!( - "“ {} â€", - if let Some(indexer) = &self.indexer { - if let Ok(Some(username)) = indexer.username_by_pubkey(&pubkey).await { - username - } else { - pubkey - } - } else { - pubkey - } - ) - }) - .clone(), - }) - } + pub async fn fetch_identity( + &mut self, + identity_id: u32, + parent_hash: sp_core::H256, + ) -> Result<String> { + Ok(match self.identities.entry(identity_id) { + hash_map::Entry::Occupied(entry) => entry.get().clone(), + hash_map::Entry::Vacant(entry) => entry + .insert({ + let pubkey = self + .client + .storage() + .fetch( + &gdev::storage().identity().identities(identity_id), + Some(parent_hash), + ) + .await? + .ok_or_else(|| anyhow!("Identity {} not found", identity_id))? + .owner_key + .to_string(); + format!( + "“ {} â€", + if let Some(indexer) = &self.indexer { + if let Ok(Some(username)) = indexer.username_by_pubkey(&pubkey).await { + username + } else { + pubkey + } + } else { + pubkey + } + ) + }) + .clone(), + }) + } } diff --git a/src/commands/collective.rs b/src/commands/collective.rs index b8eceab..70dd364 100644 --- a/src/commands/collective.rs +++ b/src/commands/collective.rs @@ -1,112 +1,111 @@ use crate::{gdev, indexer::*, Args, Client}; use anyhow::Result; -use sp_core::sr25519::Pair; -use sp_core::H256; +use sp_core::{sr25519::Pair, H256}; use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; pub async fn technical_committee_members(client: Client, args: &Args) -> Result<()> { - let parent_hash = client - .storage() - .fetch(&gdev::storage().system().parent_hash(), None) - .await? - .unwrap(); + let parent_hash = client + .storage() + .fetch(&gdev::storage().system().parent_hash(), None) + .await? + .unwrap(); - let gql_client = reqwest::Client::builder() - .user_agent("gcli/0.1.0") - .build()?; + let gql_client = reqwest::Client::builder() + .user_agent("gcli/0.1.0") + .build()?; - let indexer = if args.no_indexer { - None - } else { - Some(Indexer { - gql_client, - gql_url: &args.indexer, - }) - }; + let indexer = if args.no_indexer { + None + } else { + Some(Indexer { + gql_client, + gql_url: &args.indexer, + }) + }; - for account_id in client - .storage() - .fetch( - &gdev::storage().technical_committee().members(), - Some(parent_hash), - ) - .await? - .unwrap_or_default() - { - println!( - "{}", - if let Some(indexer) = &indexer { - indexer - .username_by_pubkey(&account_id.to_string()) - .await - .ok() - .flatten() - } else { - client - .storage() - .fetch( - &gdev::storage().identity().identity_index_of(&account_id), - Some(parent_hash), - ) - .await - .ok() - .flatten() - .map(|identity_id| format!("{identity_id}")) - } - .unwrap_or_else(|| account_id.to_string(),) - ); - } + for account_id in client + .storage() + .fetch( + &gdev::storage().technical_committee().members(), + Some(parent_hash), + ) + .await? + .unwrap_or_default() + { + println!( + "{}", + if let Some(indexer) = &indexer { + indexer + .username_by_pubkey(&account_id.to_string()) + .await + .ok() + .flatten() + } else { + client + .storage() + .fetch( + &gdev::storage().identity().identity_index_of(&account_id), + Some(parent_hash), + ) + .await + .ok() + .flatten() + .map(|identity_id| format!("{identity_id}")) + } + .unwrap_or_else(|| account_id.to_string(),) + ); + } - Ok(()) + Ok(()) } // TODO: // * better formatting (format pubkeys to SS58 and add usernames) // * display proposals indices pub async fn technical_committee_proposals(client: Client) -> Result<()> { - let parent_hash = client - .storage() - .fetch(&gdev::storage().system().parent_hash(), None) - .await? - .unwrap(); + let parent_hash = client + .storage() + .fetch(&gdev::storage().system().parent_hash(), None) + .await? + .unwrap(); - let mut proposals_iter = client - .storage() - .iter( - gdev::storage() - .technical_committee() - .proposal_of(H256::default()), - 10, - Some(parent_hash), - ) - .await?; - while let Some((proposal_hash, proposal)) = proposals_iter.next().await? { - println!("{}", hex::encode(&proposal_hash.0[32..64])); - println!("{proposal:#?}"); - println!(); - } + let mut proposals_iter = client + .storage() + .iter( + gdev::storage() + .technical_committee() + .proposal_of(H256::default()), + 10, + Some(parent_hash), + ) + .await?; + while let Some((proposal_hash, proposal)) = proposals_iter.next().await? { + println!("{}", hex::encode(&proposal_hash.0[32..64])); + println!("{proposal:#?}"); + println!(); + } - Ok(()) + Ok(()) } pub async fn technical_committee_vote( - pair: Pair, - client: Client, - proposal_hash: H256, - proposal_index: u32, - vote: bool, + pair: Pair, + client: Client, + proposal_hash: H256, + proposal_index: u32, + vote: bool, ) -> Result<()> { - client - .tx() - .sign_and_submit_then_watch( - &gdev::tx() - .technical_committee() - .vote(proposal_hash, proposal_index, vote), - &PairSigner::new(pair), - BaseExtrinsicParamsBuilder::new(), - ) - .await?; + client + .tx() + .sign_and_submit_then_watch( + &gdev::tx() + .technical_committee() + .vote(proposal_hash, proposal_index, vote), + &PairSigner::new(pair), + BaseExtrinsicParamsBuilder::new(), + ) + .await?; - Ok(()) + Ok(()) } diff --git a/src/commands/expire.rs b/src/commands/expire.rs index 7e97a29..207bfbf 100644 --- a/src/commands/expire.rs +++ b/src/commands/expire.rs @@ -5,192 +5,192 @@ use futures::join; use std::collections::BTreeMap; pub async fn monitor_expirations( - client: Client, - blocks: u32, - sessions: u32, - args: &Args, + client: Client, + blocks: u32, + sessions: u32, + args: &Args, ) -> Result<()> { - let gql_client = reqwest::Client::builder() - .user_agent("gcli/0.1.0") - .build()?; + let gql_client = reqwest::Client::builder() + .user_agent("gcli/0.1.0") + .build()?; - let parent_hash = client - .storage() - .fetch(&gdev::storage().system().parent_hash(), None) - .await? - .unwrap(); - let addr_current_block = gdev::storage().system().number(); - let addr_current_session = gdev::storage().session().current_index(); - let (current_block, current_session) = join!( - client - .storage() - .fetch(&addr_current_block, Some(parent_hash)), - client - .storage() - .fetch(&addr_current_session, Some(parent_hash),) - ); - let current_block = current_block?.unwrap(); - let current_session = current_session?.unwrap(); + let parent_hash = client + .storage() + .fetch(&gdev::storage().system().parent_hash(), None) + .await? + .unwrap(); + let addr_current_block = gdev::storage().system().number(); + let addr_current_session = gdev::storage().session().current_index(); + let (current_block, current_session) = join!( + client + .storage() + .fetch(&addr_current_block, Some(parent_hash)), + client + .storage() + .fetch(&addr_current_session, Some(parent_hash),) + ); + let current_block = current_block?.unwrap(); + let current_session = current_session?.unwrap(); - let end_block = current_block + blocks; - let end_session = current_session + sessions; + let end_block = current_block + blocks; + let end_session = current_session + sessions; - let mut identity_cache = cache::IdentityCache::new( - &client, - if args.no_indexer { - None - } else { - Some(Indexer { - gql_client, - gql_url: &args.indexer, - }) - }, - ); + let mut identity_cache = cache::IdentityCache::new( + &client, + if args.no_indexer { + None + } else { + Some(Indexer { + gql_client, + gql_url: &args.indexer, + }) + }, + ); - // Rotate keys - let mut must_rotate_keys_before_iter = client - .storage() - .iter( - gdev::storage() - .authority_members() - .must_rotate_keys_before(0), - 10, - Some(parent_hash), - ) - .await?; - let mut must_rotate_keys_before = BTreeMap::new(); - while let Some((k, v)) = must_rotate_keys_before_iter.next().await? { - let session_index = u32::from_le_bytes(k.as_ref()[40..44].try_into().unwrap()); - if session_index < end_session { - must_rotate_keys_before.insert(session_index - current_session, v); - } - } + // Rotate keys + let mut must_rotate_keys_before_iter = client + .storage() + .iter( + gdev::storage() + .authority_members() + .must_rotate_keys_before(0), + 10, + Some(parent_hash), + ) + .await?; + let mut must_rotate_keys_before = BTreeMap::new(); + while let Some((k, v)) = must_rotate_keys_before_iter.next().await? { + let session_index = u32::from_le_bytes(k.as_ref()[40..44].try_into().unwrap()); + if session_index < end_session { + must_rotate_keys_before.insert(session_index - current_session, v); + } + } - println!("\nAuthority members:"); - for (sessions_left, identity_ids) in must_rotate_keys_before { - println!("Must rotate keys before {sessions_left} sessions:"); - for identity_id in identity_ids { - println!( - " {} ({})", - identity_cache - .fetch_identity(identity_id, parent_hash) - .await - .unwrap_or_else(|_| "?".into()), - identity_id - ); - } - } + println!("\nAuthority members:"); + for (sessions_left, identity_ids) in must_rotate_keys_before { + println!("Must rotate keys before {sessions_left} sessions:"); + for identity_id in identity_ids { + println!( + " {} ({})", + identity_cache + .fetch_identity(identity_id, parent_hash) + .await + .unwrap_or_else(|_| "?".into()), + identity_id + ); + } + } - // Certifications - let mut basic_certs_iter = client - .storage() - .iter( - gdev::storage().cert().storage_certs_removable_on(0), - 10, - Some(parent_hash), - ) - .await?; - let mut basic_certs = BTreeMap::new(); - while let Some((k, v)) = basic_certs_iter.next().await? { - let block_number = u32::from_le_bytes(k.as_ref()[40..44].try_into().unwrap()); - if block_number < end_block { - basic_certs.insert(block_number - current_block, v); - } - } + // Certifications + let mut basic_certs_iter = client + .storage() + .iter( + gdev::storage().cert().storage_certs_removable_on(0), + 10, + Some(parent_hash), + ) + .await?; + let mut basic_certs = BTreeMap::new(); + while let Some((k, v)) = basic_certs_iter.next().await? { + let block_number = u32::from_le_bytes(k.as_ref()[40..44].try_into().unwrap()); + if block_number < end_block { + basic_certs.insert(block_number - current_block, v); + } + } - let mut smith_certs_iter = client - .storage() - .iter( - gdev::storage().smiths_cert().storage_certs_removable_on(0), - 10, - Some(parent_hash), - ) - .await?; - let mut smith_certs = BTreeMap::new(); - while let Some((k, v)) = smith_certs_iter.next().await? { - let block_number = u32::from_le_bytes(k.as_ref()[40..44].try_into().unwrap()); - if block_number < end_block { - smith_certs.insert(block_number - current_block, v); - } - } + let mut smith_certs_iter = client + .storage() + .iter( + gdev::storage().smiths_cert().storage_certs_removable_on(0), + 10, + Some(parent_hash), + ) + .await?; + let mut smith_certs = BTreeMap::new(); + while let Some((k, v)) = smith_certs_iter.next().await? { + let block_number = u32::from_le_bytes(k.as_ref()[40..44].try_into().unwrap()); + if block_number < end_block { + smith_certs.insert(block_number - current_block, v); + } + } - for (title, certs) in [ - ("Certifications", basic_certs), - ("Smith certifications", smith_certs), - ] { - println!("\n{title}:"); - for (blocks_left, certs) in certs { - println!("{blocks_left} blocks before expiration:"); - for (issuer_id, receiver_id) in certs { - println!( - " {} ({}) -> {} ({})", - identity_cache - .fetch_identity(issuer_id, parent_hash) - .await - .unwrap_or_else(|_| "?".into()), - issuer_id, - identity_cache - .fetch_identity(receiver_id, parent_hash) - .await - .unwrap_or_else(|_| "?".into()), - receiver_id, - ); - } - } - } + for (title, certs) in [ + ("Certifications", basic_certs), + ("Smith certifications", smith_certs), + ] { + println!("\n{title}:"); + for (blocks_left, certs) in certs { + println!("{blocks_left} blocks before expiration:"); + for (issuer_id, receiver_id) in certs { + println!( + " {} ({}) -> {} ({})", + identity_cache + .fetch_identity(issuer_id, parent_hash) + .await + .unwrap_or_else(|_| "?".into()), + issuer_id, + identity_cache + .fetch_identity(receiver_id, parent_hash) + .await + .unwrap_or_else(|_| "?".into()), + receiver_id, + ); + } + } + } - // Memberships - let mut basic_membership_iter = client - .storage() - .iter( - gdev::storage().membership().memberships_expire_on(0), - 10, - Some(parent_hash), - ) - .await?; - let mut basic_memberships = BTreeMap::new(); - while let Some((k, v)) = basic_membership_iter.next().await? { - let block_number = u32::from_le_bytes(k.as_ref()[40..44].try_into().unwrap()); - if block_number < end_block { - basic_memberships.insert(block_number - current_block, v); - } - } + // Memberships + let mut basic_membership_iter = client + .storage() + .iter( + gdev::storage().membership().memberships_expire_on(0), + 10, + Some(parent_hash), + ) + .await?; + let mut basic_memberships = BTreeMap::new(); + while let Some((k, v)) = basic_membership_iter.next().await? { + let block_number = u32::from_le_bytes(k.as_ref()[40..44].try_into().unwrap()); + if block_number < end_block { + basic_memberships.insert(block_number - current_block, v); + } + } - let mut smith_membership_iter = client - .storage() - .iter( - gdev::storage().smiths_membership().memberships_expire_on(0), - 10, - Some(parent_hash), - ) - .await?; - let mut smith_memberships = BTreeMap::new(); - while let Some((k, v)) = smith_membership_iter.next().await? { - let block_number = u32::from_le_bytes(k.as_ref()[40..44].try_into().unwrap()); - if block_number < end_block { - smith_memberships.insert(block_number - current_block, v); - } - } + let mut smith_membership_iter = client + .storage() + .iter( + gdev::storage().smiths_membership().memberships_expire_on(0), + 10, + Some(parent_hash), + ) + .await?; + let mut smith_memberships = BTreeMap::new(); + while let Some((k, v)) = smith_membership_iter.next().await? { + let block_number = u32::from_le_bytes(k.as_ref()[40..44].try_into().unwrap()); + if block_number < end_block { + smith_memberships.insert(block_number - current_block, v); + } + } - for (title, memberships) in [ - ("Memberships", basic_memberships), - ("Smith memberships", smith_memberships), - ] { - println!("\n{title}:"); - for (blocks_left, membership) in memberships { - println!("{blocks_left} blocks before expiration:"); - for identity_id in membership { - println!( - " {} ({})", - identity_cache - .fetch_identity(identity_id, parent_hash) - .await - .unwrap_or_else(|_| "?".into()), - identity_id, - ); - } - } - } + for (title, memberships) in [ + ("Memberships", basic_memberships), + ("Smith memberships", smith_memberships), + ] { + println!("\n{title}:"); + for (blocks_left, membership) in memberships { + println!("{blocks_left} blocks before expiration:"); + for identity_id in membership { + println!( + " {} ({})", + identity_cache + .fetch_identity(identity_id, parent_hash) + .await + .unwrap_or_else(|_| "?".into()), + identity_id, + ); + } + } + } - Ok(()) + Ok(()) } diff --git a/src/commands/identity.rs b/src/commands/identity.rs index ef22673..0fa2755 100644 --- a/src/commands/identity.rs +++ b/src/commands/identity.rs @@ -5,85 +5,85 @@ use sp_core::crypto::AccountId32; use std::str::FromStr; pub async fn get_identity( - client: Client, - mut account_id: Option<AccountId32>, - mut identity_id: Option<u32>, - mut username: Option<String>, - args: &Args, + client: Client, + mut account_id: Option<AccountId32>, + mut identity_id: Option<u32>, + mut username: Option<String>, + args: &Args, ) -> Result<()> { - let parent_hash = client - .storage() - .fetch(&gdev::storage().system().parent_hash(), None) - .await? - .unwrap(); + let parent_hash = client + .storage() + .fetch(&gdev::storage().system().parent_hash(), None) + .await? + .unwrap(); - let gql_client = reqwest::Client::builder() - .user_agent("gcli/0.1.0") - .build()?; + let gql_client = reqwest::Client::builder() + .user_agent("gcli/0.1.0") + .build()?; - let indexer = if args.no_indexer { - None - } else { - Some(Indexer { - gql_client, - gql_url: &args.indexer, - }) - }; + let indexer = if args.no_indexer { + None + } else { + Some(Indexer { + gql_client, + gql_url: &args.indexer, + }) + }; - if let Some(account_id) = &account_id { - identity_id = client - .storage() - .fetch( - &gdev::storage().identity().identity_index_of(account_id), - Some(parent_hash), - ) - .await?; - } else if let Some(identity_id) = &identity_id { - account_id = client - .storage() - .fetch( - &gdev::storage().identity().identities(identity_id), - Some(parent_hash), - ) - .await? - .map(|idty| idty.owner_key); - } else if let Some(username) = &username { - let indexer = indexer.as_ref().ok_or(anyhow!( - "Cannot fetch identity from username without indexer." - ))?; - if let Some(pubkey) = indexer.pubkey_by_username(username).await? { - let some_account_id = AccountId32::from_str(&pubkey).map_err(|e| anyhow!(e))?; - identity_id = client - .storage() - .fetch( - &gdev::storage() - .identity() - .identity_index_of(&some_account_id), - Some(parent_hash), - ) - .await?; - account_id = Some(some_account_id); - } - } else { - return Err(anyhow!("One argument is needed to fetch the identity.")); - } + if let Some(account_id) = &account_id { + identity_id = client + .storage() + .fetch( + &gdev::storage().identity().identity_index_of(account_id), + Some(parent_hash), + ) + .await?; + } else if let Some(identity_id) = &identity_id { + account_id = client + .storage() + .fetch( + &gdev::storage().identity().identities(identity_id), + Some(parent_hash), + ) + .await? + .map(|idty| idty.owner_key); + } else if let Some(username) = &username { + let indexer = indexer.as_ref().ok_or(anyhow!( + "Cannot fetch identity from username without indexer." + ))?; + if let Some(pubkey) = indexer.pubkey_by_username(username).await? { + let some_account_id = AccountId32::from_str(&pubkey).map_err(|e| anyhow!(e))?; + identity_id = client + .storage() + .fetch( + &gdev::storage() + .identity() + .identity_index_of(&some_account_id), + Some(parent_hash), + ) + .await?; + account_id = Some(some_account_id); + } + } else { + return Err(anyhow!("One argument is needed to fetch the identity.")); + } - println!( - "Account id: {}", - account_id - .as_ref() - .map_or(String::new(), AccountId32::to_string) - ); - println!( - "Identity id: {}", - identity_id.map_or(String::new(), |identity_id| format!("{identity_id}")) - ); + println!( + "Account id: {}", + account_id + .as_ref() + .map_or(String::new(), AccountId32::to_string) + ); + println!( + "Identity id: {}", + identity_id.map_or(String::new(), |identity_id| format!("{identity_id}")) + ); - if let (Some(indexer), Some(account_id), None) = (&indexer, &account_id, &username) { - username = indexer.username_by_pubkey(&account_id.to_string()).await?; - } + if let (Some(indexer), Some(account_id), None) = (&indexer, &account_id, &username) { + username = indexer.username_by_pubkey(&account_id.to_string()).await?; + } - println!("Username: {}", username.unwrap_or_default()); + println!("Username: {}", username.unwrap_or_default()); - Ok(()) + Ok(()) } diff --git a/src/commands/net_test.rs b/src/commands/net_test.rs index 7258907..335e0d6 100644 --- a/src/commands/net_test.rs +++ b/src/commands/net_test.rs @@ -2,97 +2,99 @@ use crate::{gdev, Client, GdevConfig}; use anyhow::{anyhow, Result}; use sp_core::{crypto::AccountId32, sr25519::Pair, DeriveJunction, Pair as _}; -use subxt::ext::sp_runtime::MultiAddress; -use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; +use subxt::{ + ext::sp_runtime::MultiAddress, + tx::{BaseExtrinsicParamsBuilder, PairSigner}, +}; pub async fn repart( - pair: Pair, - client: Client, - target: u32, - actual_repart: Option<u32>, + pair: Pair, + client: Client, + target: u32, + actual_repart: Option<u32>, ) -> Result<()> { - let mut pairs = Vec::new(); - for i in actual_repart.unwrap_or_default()..target { - let pair_i = pair - .derive(std::iter::once(DeriveJunction::hard::<u32>(i)), None) - .map_err(|_| anyhow!("Fail to derive //{}", i))? - .0; - pairs.push((i, pair_i)); - } + let mut pairs = Vec::new(); + for i in actual_repart.unwrap_or_default()..target { + let pair_i = pair + .derive(std::iter::once(DeriveJunction::hard::<u32>(i)), None) + .map_err(|_| anyhow!("Fail to derive //{}", i))? + .0; + pairs.push((i, pair_i)); + } - for (i, pair_i) in &pairs { - /*let _ = api - .tx() - .balances() - .transfer(MultiAddress::Id(pair_i.public().into()), 501)? - .sign_and_submit_then_watch(&signer, BaseExtrinsicParamsBuilder::new()) - .await? - .wait_for_in_block() - .await?; - signer.increment_nonce();*/ + for (i, pair_i) in &pairs { + /*let _ = api + .tx() + .balances() + .transfer(MultiAddress::Id(pair_i.public().into()), 501)? + .sign_and_submit_then_watch(&signer, BaseExtrinsicParamsBuilder::new()) + .await? + .wait_for_in_block() + .await?; + signer.increment_nonce();*/ - if let Some(pair_i_account) = client - .storage() - .fetch( - &gdev::storage().system().account(&pair_i.public().into()), - None, - ) - .await? - { - logs::info!("account //{} balance: {}", i, pair_i_account.data.free); - } - } + if let Some(pair_i_account) = client + .storage() + .fetch( + &gdev::storage().system().account(&pair_i.public().into()), + None, + ) + .await? + { + logs::info!("account //{} balance: {}", i, pair_i_account.data.free); + } + } - Ok(()) + Ok(()) } pub async fn spam_roll(pair: Pair, client: Client, actual_repart: usize) -> Result<()> { - let mut nonce = 0; - let mut pairs = - Vec::<(PairSigner<GdevConfig, Pair>, AccountId32)>::with_capacity(actual_repart); - for i in 0..actual_repart { - let pair_i = pair - .derive(std::iter::once(DeriveJunction::hard::<u32>(i as u32)), None) - .map_err(|_| anyhow!("Fail to derive //{}", i))? - .0; - let account_id_i = pair_i.public().into(); - pairs.push((PairSigner::new(pair_i), account_id_i)); - } + let mut nonce = 0; + let mut pairs = + Vec::<(PairSigner<GdevConfig, Pair>, AccountId32)>::with_capacity(actual_repart); + for i in 0..actual_repart { + let pair_i = pair + .derive(std::iter::once(DeriveJunction::hard::<u32>(i as u32)), None) + .map_err(|_| anyhow!("Fail to derive //{}", i))? + .0; + let account_id_i = pair_i.public().into(); + pairs.push((PairSigner::new(pair_i), account_id_i)); + } - loop { - let mut watchers = Vec::with_capacity(actual_repart); - for i in 0..(actual_repart - 1) { - let dest: AccountId32 = pairs[i + 1].1.clone(); - let watcher = client - .tx() - .create_signed_with_nonce( - &gdev::tx().balances().transfer(MultiAddress::Id(dest), 1), - &pairs[i].0, - nonce, - BaseExtrinsicParamsBuilder::new(), - )? - .submit_and_watch() - .await?; - nonce += 1; - logs::info!("send 1 cent from //{} to //{}", i, i + 1); - watchers.push(watcher); - } - let dest: AccountId32 = pairs[0].1.clone(); - let watcher = client - .tx() - .sign_and_submit_then_watch( - &gdev::tx().balances().transfer(MultiAddress::Id(dest), 1), - &pairs[actual_repart - 1].0, - BaseExtrinsicParamsBuilder::new(), - ) - .await?; - nonce += 1; - logs::info!("send 1 cent from //{} to //0", actual_repart - 1); - watchers.push(watcher); + loop { + let mut watchers = Vec::with_capacity(actual_repart); + for i in 0..(actual_repart - 1) { + let dest: AccountId32 = pairs[i + 1].1.clone(); + let watcher = client + .tx() + .create_signed_with_nonce( + &gdev::tx().balances().transfer(MultiAddress::Id(dest), 1), + &pairs[i].0, + nonce, + BaseExtrinsicParamsBuilder::new(), + )? + .submit_and_watch() + .await?; + nonce += 1; + logs::info!("send 1 cent from //{} to //{}", i, i + 1); + watchers.push(watcher); + } + let dest: AccountId32 = pairs[0].1.clone(); + let watcher = client + .tx() + .sign_and_submit_then_watch( + &gdev::tx().balances().transfer(MultiAddress::Id(dest), 1), + &pairs[actual_repart - 1].0, + BaseExtrinsicParamsBuilder::new(), + ) + .await?; + nonce += 1; + logs::info!("send 1 cent from //{} to //0", actual_repart - 1); + watchers.push(watcher); - // Wait all transactions - for watcher in watchers { - watcher.wait_for_in_block().await?; - } - } + // Wait all transactions + for watcher in watchers { + watcher.wait_for_in_block().await?; + } + } } diff --git a/src/commands/oneshot.rs b/src/commands/oneshot.rs index 3e6d3c3..640cf9f 100644 --- a/src/commands/oneshot.rs +++ b/src/commands/oneshot.rs @@ -5,118 +5,118 @@ use sp_core::{crypto::AccountId32, sr25519::Pair}; use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; pub async fn create_oneshot_account( - pair: Pair, - client: Client, - balance: u64, - dest: AccountId32, + pair: Pair, + client: Client, + balance: u64, + dest: AccountId32, ) -> Result<()> { - client - .tx() - .sign_and_submit_then_watch( - &gdev::tx() - .oneshot_account() - .create_oneshot_account(dest.into(), balance), - &PairSigner::new(pair), - BaseExtrinsicParamsBuilder::new(), - ) - .await?; + client + .tx() + .sign_and_submit_then_watch( + &gdev::tx() + .oneshot_account() + .create_oneshot_account(dest.into(), balance), + &PairSigner::new(pair), + BaseExtrinsicParamsBuilder::new(), + ) + .await?; - Ok(()) + Ok(()) } pub async fn consume_oneshot_account( - pair: Pair, - client: Client, - dest: AccountId32, - dest_oneshot: bool, + pair: Pair, + client: Client, + dest: AccountId32, + dest_oneshot: bool, ) -> Result<()> { - let number = client - .storage() - .fetch(&gdev::storage().system().number(), None) - .await? - .unwrap(); - client - .tx() - .sign_and_submit_then_watch( - &gdev::tx().oneshot_account().consume_oneshot_account( - number, - if dest_oneshot { - gdev::runtime_types::pallet_oneshot_account::types::Account::Oneshot( - dest.into(), - ) - } else { - gdev::runtime_types::pallet_oneshot_account::types::Account::Normal(dest.into()) - }, - ), - &PairSigner::new(pair), - BaseExtrinsicParamsBuilder::new(), - ) - .await?; + let number = client + .storage() + .fetch(&gdev::storage().system().number(), None) + .await? + .unwrap(); + client + .tx() + .sign_and_submit_then_watch( + &gdev::tx().oneshot_account().consume_oneshot_account( + number, + if dest_oneshot { + gdev::runtime_types::pallet_oneshot_account::types::Account::Oneshot( + dest.into(), + ) + } else { + gdev::runtime_types::pallet_oneshot_account::types::Account::Normal(dest.into()) + }, + ), + &PairSigner::new(pair), + BaseExtrinsicParamsBuilder::new(), + ) + .await?; - Ok(()) + Ok(()) } pub async fn consume_oneshot_account_with_remaining( - pair: Pair, - client: Client, - balance: u64, - dest: AccountId32, - dest_oneshot: bool, - remaining_to: AccountId32, - remaining_to_oneshot: bool, + pair: Pair, + client: Client, + balance: u64, + dest: AccountId32, + dest_oneshot: bool, + remaining_to: AccountId32, + remaining_to_oneshot: bool, ) -> Result<()> { - let number = client - .storage() - .fetch(&gdev::storage().system().number(), None) - .await? - .unwrap(); - client - .tx() - .sign_and_submit_then_watch( - &gdev::tx() - .oneshot_account() - .consume_oneshot_account_with_remaining( - number, - if dest_oneshot { - gdev::runtime_types::pallet_oneshot_account::types::Account::Oneshot( - dest.into(), - ) - } else { - gdev::runtime_types::pallet_oneshot_account::types::Account::Normal( - dest.into(), - ) - }, - if remaining_to_oneshot { - gdev::runtime_types::pallet_oneshot_account::types::Account::Oneshot( - remaining_to.into(), - ) - } else { - gdev::runtime_types::pallet_oneshot_account::types::Account::Normal( - remaining_to.into(), - ) - }, - balance, - ), - &PairSigner::new(pair), - BaseExtrinsicParamsBuilder::new(), - ) - .await?; + let number = client + .storage() + .fetch(&gdev::storage().system().number(), None) + .await? + .unwrap(); + client + .tx() + .sign_and_submit_then_watch( + &gdev::tx() + .oneshot_account() + .consume_oneshot_account_with_remaining( + number, + if dest_oneshot { + gdev::runtime_types::pallet_oneshot_account::types::Account::Oneshot( + dest.into(), + ) + } else { + gdev::runtime_types::pallet_oneshot_account::types::Account::Normal( + dest.into(), + ) + }, + if remaining_to_oneshot { + gdev::runtime_types::pallet_oneshot_account::types::Account::Oneshot( + remaining_to.into(), + ) + } else { + gdev::runtime_types::pallet_oneshot_account::types::Account::Normal( + remaining_to.into(), + ) + }, + balance, + ), + &PairSigner::new(pair), + BaseExtrinsicParamsBuilder::new(), + ) + .await?; - Ok(()) + Ok(()) } pub async fn oneshot_account_balance(client: Client, account: AccountId32) -> Result<()> { - logs::info!( - "{}", - client - .storage() - .fetch( - &gdev::storage().oneshot_account().oneshot_accounts(&account), - None - ) - .await? - .unwrap_or(0) - ); + logs::info!( + "{}", + client + .storage() + .fetch( + &gdev::storage().oneshot_account().oneshot_accounts(&account), + None + ) + .await? + .unwrap_or(0) + ); - Ok(()) + Ok(()) } diff --git a/src/commands/revocation.rs b/src/commands/revocation.rs index 7595a6b..b20ef0c 100644 --- a/src/commands/revocation.rs +++ b/src/commands/revocation.rs @@ -5,19 +5,19 @@ use futures::join; use sp_core::{sr25519::Pair, Encode, Pair as _}; pub async fn gen_revoc_doc(api: &Client, pair: &Pair) -> Result<()> { - let account_id: sp_core::crypto::AccountId32 = pair.public().into(); - let addr_idty_index = gdev::storage().identity().identity_index_of(&account_id); - let addr_block_hash = gdev::storage().system().block_hash(0); - let (idty_index, genesis_hash) = join!( - api.storage().fetch(&addr_idty_index, None,), - api.storage().fetch(&addr_block_hash, None) - ); - let idty_index = idty_index?.unwrap(); - let genesis_hash = genesis_hash?.unwrap(); - let payload = (b"revo", genesis_hash, idty_index).encode(); - let signature = pair.sign(&payload); + let account_id: sp_core::crypto::AccountId32 = pair.public().into(); + let addr_idty_index = gdev::storage().identity().identity_index_of(&account_id); + let addr_block_hash = gdev::storage().system().block_hash(0); + let (idty_index, genesis_hash) = join!( + api.storage().fetch(&addr_idty_index, None,), + api.storage().fetch(&addr_block_hash, None) + ); + let idty_index = idty_index?.unwrap(); + let genesis_hash = genesis_hash?.unwrap(); + let payload = (b"revo", genesis_hash, idty_index).encode(); + let signature = pair.sign(&payload); - println!("0x{}", hex::encode(signature)); + println!("0x{}", hex::encode(signature)); - Ok(()) + Ok(()) } diff --git a/src/commands/smith.rs b/src/commands/smith.rs index 929ea03..463c179 100644 --- a/src/commands/smith.rs +++ b/src/commands/smith.rs @@ -8,157 +8,157 @@ use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; type SessionKeys = [u8; 128]; pub async fn rotate_keys(client: &Client) -> Result<SessionKeys> { - client - .rpc() - .rotate_keys() - .await? - .deref() - .try_into() - .map_err(|e| anyhow!("Session keys have wrong length: {:?}", e)) + client + .rpc() + .rotate_keys() + .await? + .deref() + .try_into() + .map_err(|e| anyhow!("Session keys have wrong length: {:?}", e)) } pub async fn set_session_keys(pair: Pair, client: Client, session_keys: SessionKeys) -> Result<()> { - client - .tx() - .sign_and_submit_then_watch( - &gdev::tx() - .authority_members() - .set_session_keys(session_keys), - &PairSigner::new(pair), - BaseExtrinsicParamsBuilder::new(), - ) - .await?; - - Ok(()) + client + .tx() + .sign_and_submit_then_watch( + &gdev::tx() + .authority_members() + .set_session_keys(session_keys), + &PairSigner::new(pair), + BaseExtrinsicParamsBuilder::new(), + ) + .await?; + + Ok(()) } pub async fn update_session_keys(pair: Pair, client: Client) -> Result<()> { - let session_keys = rotate_keys(&client).await?; - set_session_keys(pair, client, session_keys).await + let session_keys = rotate_keys(&client).await?; + set_session_keys(pair, client, session_keys).await } pub async fn go_online(pair: Pair, client: Client) -> Result<()> { - if client - .storage() - .fetch( - &gdev::storage() - .session() - .next_keys(AccountId32::from(pair.public())), - None, - ) - .await? - .is_none() - { - return Err(anyhow!("This account has not set session keys!")); - } - - client - .tx() - .sign_and_submit_then_watch( - &gdev::tx().authority_members().go_online(), - &PairSigner::new(pair), - BaseExtrinsicParamsBuilder::new(), - ) - .await?; - - Ok(()) + if client + .storage() + .fetch( + &gdev::storage() + .session() + .next_keys(AccountId32::from(pair.public())), + None, + ) + .await? + .is_none() + { + return Err(anyhow!("This account has not set session keys!")); + } + + client + .tx() + .sign_and_submit_then_watch( + &gdev::tx().authority_members().go_online(), + &PairSigner::new(pair), + BaseExtrinsicParamsBuilder::new(), + ) + .await?; + + Ok(()) } pub async fn go_offline(pair: Pair, client: Client) -> Result<()> { - client - .tx() - .sign_and_submit_then_watch( - &gdev::tx().authority_members().go_offline(), - &PairSigner::new(pair), - BaseExtrinsicParamsBuilder::new(), - ) - .await?; - - Ok(()) + client + .tx() + .sign_and_submit_then_watch( + &gdev::tx().authority_members().go_offline(), + &PairSigner::new(pair), + BaseExtrinsicParamsBuilder::new(), + ) + .await?; + + Ok(()) } pub async fn online(client: Client, args: &Args) -> Result<()> { - let parent_hash = client - .storage() - .fetch(&gdev::storage().system().parent_hash(), None) - .await? - .unwrap(); - - let gql_client = reqwest::Client::builder() - .user_agent("gcli/0.1.0") - .build()?; - - let mut identity_cache = cache::IdentityCache::new( - &client, - if args.no_indexer { - None - } else { - Some(Indexer { - gql_client, - gql_url: &args.indexer, - }) - }, - ); - - let online_authorities = client - .storage() - .fetch( - &gdev::storage().authority_members().online_authorities(), - Some(parent_hash), - ) - .await? - .unwrap_or_default(); - - println!("Online:"); - for identity_id in online_authorities { - println!( - " {}", - identity_cache - .fetch_identity(identity_id, parent_hash) - .await - .unwrap_or_else(|_| format!("{identity_id}")) - ); - } - - let incoming_authorities = client - .storage() - .fetch( - &gdev::storage().authority_members().incoming_authorities(), - Some(parent_hash), - ) - .await? - .unwrap_or_default(); - - println!("Incoming:"); - for identity_id in incoming_authorities { - println!( - " {}", - identity_cache - .fetch_identity(identity_id, parent_hash) - .await - .unwrap_or_else(|_| format!("{identity_id}")) - ); - } - - let outgoing_authorities = client - .storage() - .fetch( - &gdev::storage().authority_members().outgoing_authorities(), - Some(parent_hash), - ) - .await? - .unwrap_or_default(); - - println!("Outgoing:"); - for identity_id in outgoing_authorities { - println!( - " {}", - identity_cache - .fetch_identity(identity_id, parent_hash) - .await - .unwrap_or_else(|_| format!("{identity_id}")) - ); - } - - Ok(()) + let parent_hash = client + .storage() + .fetch(&gdev::storage().system().parent_hash(), None) + .await? + .unwrap(); + + let gql_client = reqwest::Client::builder() + .user_agent("gcli/0.1.0") + .build()?; + + let mut identity_cache = cache::IdentityCache::new( + &client, + if args.no_indexer { + None + } else { + Some(Indexer { + gql_client, + gql_url: &args.indexer, + }) + }, + ); + + let online_authorities = client + .storage() + .fetch( + &gdev::storage().authority_members().online_authorities(), + Some(parent_hash), + ) + .await? + .unwrap_or_default(); + + println!("Online:"); + for identity_id in online_authorities { + println!( + " {}", + identity_cache + .fetch_identity(identity_id, parent_hash) + .await + .unwrap_or_else(|_| format!("{identity_id}")) + ); + } + + let incoming_authorities = client + .storage() + .fetch( + &gdev::storage().authority_members().incoming_authorities(), + Some(parent_hash), + ) + .await? + .unwrap_or_default(); + + println!("Incoming:"); + for identity_id in incoming_authorities { + println!( + " {}", + identity_cache + .fetch_identity(identity_id, parent_hash) + .await + .unwrap_or_else(|_| format!("{identity_id}")) + ); + } + + let outgoing_authorities = client + .storage() + .fetch( + &gdev::storage().authority_members().outgoing_authorities(), + Some(parent_hash), + ) + .await? + .unwrap_or_default(); + + println!("Outgoing:"); + for identity_id in outgoing_authorities { + println!( + " {}", + identity_cache + .fetch_identity(identity_id, parent_hash) + .await + .unwrap_or_else(|_| format!("{identity_id}")) + ); + } + + Ok(()) } diff --git a/src/commands/sudo.rs b/src/commands/sudo.rs index ee06cdf..7987a08 100644 --- a/src/commands/sudo.rs +++ b/src/commands/sudo.rs @@ -5,14 +5,14 @@ use sp_core::{crypto::AccountId32, sr25519::Pair}; use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; pub async fn set_key(pair: Pair, client: Client, new_key: AccountId32) -> Result<()> { - client - .tx() - .sign_and_submit_then_watch( - &gdev::tx().sudo().set_key(new_key.into()), - &PairSigner::new(pair), - BaseExtrinsicParamsBuilder::new(), - ) - .await?; + client + .tx() + .sign_and_submit_then_watch( + &gdev::tx().sudo().set_key(new_key.into()), + &PairSigner::new(pair), + BaseExtrinsicParamsBuilder::new(), + ) + .await?; - Ok(()) + Ok(()) } diff --git a/src/commands/transfer.rs b/src/commands/transfer.rs index 82ea9e1..4e51cf3 100644 --- a/src/commands/transfer.rs +++ b/src/commands/transfer.rs @@ -8,63 +8,63 @@ type Call = gdev::runtime_types::gdev_runtime::Call; type BalancesCall = gdev::runtime_types::pallet_balances::pallet::Call; pub async fn transfer( - pair: Pair, - client: Client, - balance: u64, - dest: AccountId32, - keep_alive: bool, + pair: Pair, + client: Client, + balance: u64, + dest: AccountId32, + keep_alive: bool, ) -> Result<()> { - if keep_alive { - client - .tx() - .sign_and_submit_then_watch( - &gdev::tx().balances().transfer(dest.into(), balance), - &PairSigner::new(pair), - BaseExtrinsicParamsBuilder::new(), - ) - .await?; - } else { - client - .tx() - .sign_and_submit_then_watch( - &gdev::tx() - .balances() - .transfer_keep_alive(dest.into(), balance), - &PairSigner::new(pair), - BaseExtrinsicParamsBuilder::new(), - ) - .await?; - } + if keep_alive { + client + .tx() + .sign_and_submit_then_watch( + &gdev::tx().balances().transfer(dest.into(), balance), + &PairSigner::new(pair), + BaseExtrinsicParamsBuilder::new(), + ) + .await?; + } else { + client + .tx() + .sign_and_submit_then_watch( + &gdev::tx() + .balances() + .transfer_keep_alive(dest.into(), balance), + &PairSigner::new(pair), + BaseExtrinsicParamsBuilder::new(), + ) + .await?; + } - Ok(()) + Ok(()) } pub async fn transfer_multiple( - pair: Pair, - client: Client, - amount: u64, - dests: Vec<AccountId32>, + pair: Pair, + client: Client, + amount: u64, + dests: Vec<AccountId32>, ) -> Result<()> { - // build the list of transactions from the destination accounts - let transactions: Vec<Call> = dests - .into_iter() - .map(|dest| { - Call::Balances(BalancesCall::transfer_keep_alive { - dest: dest.into(), - value: amount, - }) - }) - .collect(); + // build the list of transactions from the destination accounts + let transactions: Vec<Call> = dests + .into_iter() + .map(|dest| { + Call::Balances(BalancesCall::transfer_keep_alive { + dest: dest.into(), + value: amount, + }) + }) + .collect(); - // wrap these calls in a batch call - client - .tx() - .sign_and_submit_then_watch( - &gdev::tx().utility().batch(transactions), - &PairSigner::new(pair.clone()), - BaseExtrinsicParamsBuilder::new(), - ) - .await?; + // wrap these calls in a batch call + client + .tx() + .sign_and_submit_then_watch( + &gdev::tx().utility().batch(transactions), + &PairSigner::new(pair.clone()), + BaseExtrinsicParamsBuilder::new(), + ) + .await?; - Ok(()) + Ok(()) } diff --git a/src/indexer.rs b/src/indexer.rs index d66cd11..0a48b0e 100644 --- a/src/indexer.rs +++ b/src/indexer.rs @@ -4,47 +4,47 @@ use anyhow::Result; #[derive(GraphQLQuery)] #[graphql( - schema_path = "res/indexer-schema.json", - query_path = "res/indexer-queries.graphql" + schema_path = "res/indexer-schema.json", + query_path = "res/indexer-queries.graphql" )] pub struct IdentityNameByPubkey; #[derive(GraphQLQuery)] #[graphql( - schema_path = "res/indexer-schema.json", - query_path = "res/indexer-queries.graphql" + schema_path = "res/indexer-schema.json", + query_path = "res/indexer-queries.graphql" )] pub struct IdentityPubkeyByName; pub struct Indexer<'a> { - pub gql_client: reqwest::Client, - pub gql_url: &'a str, + pub gql_client: reqwest::Client, + pub gql_url: &'a str, } impl<'a> Indexer<'a> { - pub async fn username_by_pubkey(&self, pubkey: &str) -> Result<Option<String>> { - Ok(post_graphql::<IdentityNameByPubkey, _>( - &self.gql_client, - self.gql_url, - identity_name_by_pubkey::Variables { - pubkey: pubkey.to_string(), - }, - ) - .await? - .data - .and_then(|data| data.identity.into_iter().next().map(|idty| idty.name))) - } + pub async fn username_by_pubkey(&self, pubkey: &str) -> Result<Option<String>> { + Ok(post_graphql::<IdentityNameByPubkey, _>( + &self.gql_client, + self.gql_url, + identity_name_by_pubkey::Variables { + pubkey: pubkey.to_string(), + }, + ) + .await? + .data + .and_then(|data| data.identity.into_iter().next().map(|idty| idty.name))) + } - pub async fn pubkey_by_username(&self, username: &str) -> Result<Option<String>> { - Ok(post_graphql::<IdentityPubkeyByName, _>( - &self.gql_client, - self.gql_url, - identity_pubkey_by_name::Variables { - name: username.to_string(), - }, - ) - .await? - .data - .and_then(|data| data.identity_by_pk.map(|idty| idty.pubkey))) - } + pub async fn pubkey_by_username(&self, username: &str) -> Result<Option<String>> { + Ok(post_graphql::<IdentityPubkeyByName, _>( + &self.gql_client, + self.gql_url, + identity_pubkey_by_name::Variables { + name: username.to_string(), + }, + ) + .await? + .data + .and_then(|data| data.identity_by_pk.map(|idty| idty.pubkey))) + } } diff --git a/src/keys.rs b/src/keys.rs index d9bebdd..fcb2f9a 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -1,125 +1,127 @@ use anyhow::{anyhow, Result}; use clap::builder::OsStr; -use sp_core::crypto::{AccountId32, Ss58Codec}; -use sp_core::{crypto::Pair as _, sr25519::Pair}; +use sp_core::{ + crypto::{AccountId32, Pair as _, Ss58Codec}, + sr25519::Pair, +}; use std::str::FromStr; #[allow(dead_code)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum NeededKeys { - None, - Public, - Secret, + None, + Public, + Secret, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum SecretFormat { - /// Raw 32B seed - Seed, - /// Substrate secret key or BIP39 mnemonic (optionally followed by derivation path) - Substrate, + /// Raw 32B seed + Seed, + /// Substrate secret key or BIP39 mnemonic (optionally followed by derivation path) + Substrate, } impl FromStr for SecretFormat { - type Err = std::io::Error; + type Err = std::io::Error; - fn from_str(s: &str) -> std::io::Result<Self> { - match s { - "seed" => Ok(SecretFormat::Seed), - "substrate" => Ok(SecretFormat::Substrate), - _ => Err(std::io::Error::from(std::io::ErrorKind::InvalidInput)), - } - } + fn from_str(s: &str) -> std::io::Result<Self> { + match s { + "seed" => Ok(SecretFormat::Seed), + "substrate" => Ok(SecretFormat::Substrate), + _ => Err(std::io::Error::from(std::io::ErrorKind::InvalidInput)), + } + } } impl From<SecretFormat> for &'static str { - fn from(val: SecretFormat) -> &'static str { - match val { - SecretFormat::Seed => "seed", - SecretFormat::Substrate => "substrate", - } - } + fn from(val: SecretFormat) -> &'static str { + match val { + SecretFormat::Seed => "seed", + SecretFormat::Substrate => "substrate", + } + } } impl From<SecretFormat> for OsStr { - fn from(val: SecretFormat) -> OsStr { - OsStr::from(Into::<&str>::into(val)) - } + fn from(val: SecretFormat) -> OsStr { + OsStr::from(Into::<&str>::into(val)) + } } pub fn pair_from_str(secret_format: SecretFormat, secret: &str) -> Result<Pair> { - match secret_format { - SecretFormat::Seed => { - let mut seed = [0; 32]; - hex::decode_to_slice(secret, &mut seed).map_err(|_| anyhow!("Invalid secret"))?; - let pair = Pair::from_seed(&seed); - Ok(pair) - } - SecretFormat::Substrate => { - Pair::from_string(secret, None).map_err(|_| anyhow!("Invalid secret")) - } - } + match secret_format { + SecretFormat::Seed => { + let mut seed = [0; 32]; + hex::decode_to_slice(secret, &mut seed).map_err(|_| anyhow!("Invalid secret"))?; + let pair = Pair::from_seed(&seed); + Ok(pair) + } + SecretFormat::Substrate => { + Pair::from_string(secret, None).map_err(|_| anyhow!("Invalid secret")) + } + } } pub fn prompt_secret(secret_format: SecretFormat) -> Pair { - let mut line = String::new(); - loop { - println!("Secret key ({secret_format:?}): "); - std::io::stdin().read_line(&mut line).unwrap(); - match pair_from_str(secret_format, line.trim()) { - Ok(pair) => return pair, - Err(_) => println!("Invalid secret"), - } - line.clear(); - } + let mut line = String::new(); + loop { + println!("Secret key ({secret_format:?}): "); + std::io::stdin().read_line(&mut line).unwrap(); + match pair_from_str(secret_format, line.trim()) { + Ok(pair) => return pair, + Err(_) => println!("Invalid secret"), + } + line.clear(); + } } pub fn get_keys( - secret_format: SecretFormat, - address: &Option<String>, - secret: &Option<String>, - needed_keys: NeededKeys, + secret_format: SecretFormat, + address: &Option<String>, + secret: &Option<String>, + needed_keys: NeededKeys, ) -> Result<(Option<AccountId32>, Option<Pair>)> { - // Get from args - let mut account_id = match (address, secret) { - (Some(address), Some(secret)) => { - let pair = pair_from_str(secret_format, secret)?; - let address = AccountId32::from_string(address) - .map_err(|_| anyhow!("Invalid address {}", address))?; - assert_eq!( - address, - pair.public().into(), - "Secret and address do not match." - ); - return Ok((Some(pair.public().into()), Some(pair))); - } - (None, Some(secret)) => { - let pair = pair_from_str(secret_format, secret)?; - return Ok((Some(pair.public().into()), Some(pair))); - } - (Some(address), None) => Some( - AccountId32::from_str(address).map_err(|_| anyhow!("Invalid address {}", address))?, - ), - (None, None) => None, - }; + // Get from args + let mut account_id = match (address, secret) { + (Some(address), Some(secret)) => { + let pair = pair_from_str(secret_format, secret)?; + let address = AccountId32::from_string(address) + .map_err(|_| anyhow!("Invalid address {}", address))?; + assert_eq!( + address, + pair.public().into(), + "Secret and address do not match." + ); + return Ok((Some(pair.public().into()), Some(pair))); + } + (None, Some(secret)) => { + let pair = pair_from_str(secret_format, secret)?; + return Ok((Some(pair.public().into()), Some(pair))); + } + (Some(address), None) => Some( + AccountId32::from_str(address).map_err(|_| anyhow!("Invalid address {}", address))?, + ), + (None, None) => None, + }; - // Prompt - if needed_keys == NeededKeys::Secret - || (account_id.is_none() && needed_keys == NeededKeys::Public) - { - loop { - let pair = prompt_secret(secret_format); + // Prompt + if needed_keys == NeededKeys::Secret + || (account_id.is_none() && needed_keys == NeededKeys::Public) + { + loop { + let pair = prompt_secret(secret_format); - if let Some(account_id) = &account_id { - if account_id != &pair.public().into() { - println!("Secret and address do not match."); - } - } else { - account_id = Some(pair.public().into()); - return Ok((account_id, Some(pair))); - } - } - } + if let Some(account_id) = &account_id { + if account_id != &pair.public().into() { + println!("Secret and address do not match."); + } + } else { + account_id = Some(pair.public().into()); + return Ok((account_id, Some(pair))); + } + } + } - Ok((account_id, None)) + Ok((account_id, None)) } diff --git a/src/main.rs b/src/main.rs index 07b1adc..5ce099e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,452 +17,452 @@ pub type Client = subxt::OnlineClient<GdevConfig>; pub enum GdevConfig {} impl subxt::config::Config for GdevConfig { - type Index = u32; - type BlockNumber = u32; - type Hash = sp_core::H256; - type Hashing = subxt::ext::sp_runtime::traits::BlakeTwo256; - type AccountId = subxt::ext::sp_runtime::AccountId32; - type Address = subxt::ext::sp_runtime::MultiAddress<Self::AccountId, u32>; - type Header = subxt::ext::sp_runtime::generic::Header< - Self::BlockNumber, - subxt::ext::sp_runtime::traits::BlakeTwo256, - >; - type Signature = subxt::ext::sp_runtime::MultiSignature; - type ExtrinsicParams = subxt::tx::BaseExtrinsicParams<Self, Tip>; + type Index = u32; + type BlockNumber = u32; + type Hash = sp_core::H256; + type Hashing = subxt::ext::sp_runtime::traits::BlakeTwo256; + type AccountId = subxt::ext::sp_runtime::AccountId32; + type Address = subxt::ext::sp_runtime::MultiAddress<Self::AccountId, u32>; + type Header = subxt::ext::sp_runtime::generic::Header< + Self::BlockNumber, + subxt::ext::sp_runtime::traits::BlakeTwo256, + >; + type Signature = subxt::ext::sp_runtime::MultiSignature; + type ExtrinsicParams = subxt::tx::BaseExtrinsicParams<Self, Tip>; } #[derive(Copy, Clone, Debug, Default, Encode)] pub struct Tip { - #[codec(compact)] - tip: u64, + #[codec(compact)] + tip: u64, } impl Tip { - pub fn new(amount: u64) -> Self { - Tip { tip: amount } - } + pub fn new(amount: u64) -> Self { + Tip { tip: amount } + } } impl From<u64> for Tip { - fn from(n: u64) -> Self { - Self::new(n) - } + fn from(n: u64) -> Self { + Self::new(n) + } } #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] pub struct Args { - #[clap(subcommand)] - pub subcommand: Subcommand, + #[clap(subcommand)] + pub subcommand: Subcommand, - /// Indexer URL - #[clap( - short, - long, - default_value = "https://gdev-indexer.p2p.legal/v1/graphql" - )] - indexer: String, - /// Do not use indexer - #[clap(long)] - no_indexer: bool, - /// Secret key or BIP39 mnemonic - /// (eventually followed by derivation path) - #[clap(short, long)] - secret: Option<String>, - /// Secret key format (seed, substrate) - #[clap(short = 'S', long, default_value = SecretFormat::Substrate)] - secret_format: SecretFormat, - /// Address - #[clap(short, long)] - address: Option<String>, - /// Websocket RPC endpoint - #[clap(short, long, default_value = "ws://localhost:9944")] - url: String, + /// Indexer URL + #[clap( + short, + long, + default_value = "https://gdev-indexer.p2p.legal/v1/graphql" + )] + indexer: String, + /// Do not use indexer + #[clap(long)] + no_indexer: bool, + /// Secret key or BIP39 mnemonic + /// (eventually followed by derivation path) + #[clap(short, long)] + secret: Option<String>, + /// Secret key format (seed, substrate) + #[clap(short = 'S', long, default_value = SecretFormat::Substrate)] + secret_format: SecretFormat, + /// Address + #[clap(short, long)] + address: Option<String>, + /// Websocket RPC endpoint + #[clap(short, long, default_value = "ws://localhost:9944")] + url: String, } #[derive(Debug, clap::Subcommand)] pub enum Subcommand { - CreateOneshot { - balance: u64, - dest: sp_core::crypto::AccountId32, - }, - ConsumeOneshot { - dest: sp_core::crypto::AccountId32, - #[clap(long = "oneshot")] - dest_oneshot: bool, - }, - ConsumeOneshotWithRemaining { - balance: u64, - dest: sp_core::crypto::AccountId32, - #[clap(long = "one")] - dest_oneshot: bool, - remaining_to: sp_core::crypto::AccountId32, - #[clap(long = "rem-one")] - remaining_to_oneshot: bool, - }, - /// List upcoming expirations that require an action - Expire { - /// Show certs that expire within less than this number of blocks - #[clap(short, long, default_value_t = 100800)] - blocks: u32, - /// Show authorities that should rotate keys within less than this number of sessions - #[clap(short, long, default_value_t = 100)] - sessions: u32, - }, - /// Fetch identity - Identity { - #[clap(short = 'p', long = "pubkey")] - account_id: Option<sp_core::crypto::AccountId32>, - #[clap(short = 'i', long = "identity")] - identity_id: Option<u32>, - #[clap(short = 'u', long = "username")] - username: Option<String>, - }, - /// Generate a revocation document for the provided account - GenRevocDoc, - GoOffline, - GoOnline, - OneshotBalance { - account: sp_core::crypto::AccountId32, - }, - /// List online authorities - Online, - #[clap(hide = true)] - Repart { - // Number of transactions per block to target - target: u32, - #[clap(short = 'o', long = "old-repart")] - // Old/actual repartition - actual_repart: Option<u32>, - }, - #[clap(hide = true)] - SpamRoll { - actual_repart: usize, - }, - SudoSetKey { - new_key: sp_core::crypto::AccountId32, - }, - /// List members of the technical committee - TechMembers, - /// List proposals to the technical committee - TechProposals, - /// Vote a proposal to the technical committee - TechVote { - /// Proposal hash - hash: H256, - /// Proposal index - index: u32, - /// Vote (0=against, 1=for) - vote: u8, - }, - Transfer { - /// Amount to transfer - amount: u64, - /// Destination address - dest: sp_core::crypto::AccountId32, - /// Prevent from going below account existential deposit - #[clap(short = 'k', long = "keep-alive")] - keep_alive: bool, - }, - /// Transfer the same amount for each space-separated address. - /// If an address appears mutiple times, it will get multiple times the same amount - TransferMultiple { - /// Amount given to each destination address - amount: u64, - /// List of target addresses - dests: Vec<sp_core::crypto::AccountId32>, - }, - /// Rotate and set session keys - UpdateKeys, + CreateOneshot { + balance: u64, + dest: sp_core::crypto::AccountId32, + }, + ConsumeOneshot { + dest: sp_core::crypto::AccountId32, + #[clap(long = "oneshot")] + dest_oneshot: bool, + }, + ConsumeOneshotWithRemaining { + balance: u64, + dest: sp_core::crypto::AccountId32, + #[clap(long = "one")] + dest_oneshot: bool, + remaining_to: sp_core::crypto::AccountId32, + #[clap(long = "rem-one")] + remaining_to_oneshot: bool, + }, + /// List upcoming expirations that require an action + Expire { + /// Show certs that expire within less than this number of blocks + #[clap(short, long, default_value_t = 100800)] + blocks: u32, + /// Show authorities that should rotate keys within less than this number of sessions + #[clap(short, long, default_value_t = 100)] + sessions: u32, + }, + /// Fetch identity + Identity { + #[clap(short = 'p', long = "pubkey")] + account_id: Option<sp_core::crypto::AccountId32>, + #[clap(short = 'i', long = "identity")] + identity_id: Option<u32>, + #[clap(short = 'u', long = "username")] + username: Option<String>, + }, + /// Generate a revocation document for the provided account + GenRevocDoc, + GoOffline, + GoOnline, + OneshotBalance { + account: sp_core::crypto::AccountId32, + }, + /// List online authorities + Online, + #[clap(hide = true)] + Repart { + // Number of transactions per block to target + target: u32, + #[clap(short = 'o', long = "old-repart")] + // Old/actual repartition + actual_repart: Option<u32>, + }, + #[clap(hide = true)] + SpamRoll { + actual_repart: usize, + }, + SudoSetKey { + new_key: sp_core::crypto::AccountId32, + }, + /// List members of the technical committee + TechMembers, + /// List proposals to the technical committee + TechProposals, + /// Vote a proposal to the technical committee + TechVote { + /// Proposal hash + hash: H256, + /// Proposal index + index: u32, + /// Vote (0=against, 1=for) + vote: u8, + }, + Transfer { + /// Amount to transfer + amount: u64, + /// Destination address + dest: sp_core::crypto::AccountId32, + /// Prevent from going below account existential deposit + #[clap(short = 'k', long = "keep-alive")] + keep_alive: bool, + }, + /// Transfer the same amount for each space-separated address. + /// If an address appears mutiple times, it will get multiple times the same amount + TransferMultiple { + /// Amount given to each destination address + amount: u64, + /// List of target addresses + dests: Vec<sp_core::crypto::AccountId32>, + }, + /// Rotate and set session keys + UpdateKeys, } #[tokio::main(flavor = "current_thread")] async fn main() -> Result<()> { - env_logger::init(); + env_logger::init(); - let args = Args::parse(); + let args = Args::parse(); - /*if let Some(account_id) = &account_id { - println!("Account address: {account_id}"); - }*/ + /*if let Some(account_id) = &account_id { + println!("Account address: {account_id}"); + }*/ - /*if let Some(account_id) = &account_id { - let account = client - .storage() - .fetch(&gdev::storage().system().account(account_id), None) - .await? - .expect("Cannot fetch account"); - logs::info!("Account free balance: {}", account.data.free); - }*/ + /*if let Some(account_id) = &account_id { + let account = client + .storage() + .fetch(&gdev::storage().system().account(account_id), None) + .await? + .expect("Cannot fetch account"); + logs::info!("Account free balance: {}", account.data.free); + }*/ - match args.subcommand { - Subcommand::CreateOneshot { balance, dest } => { - commands::oneshot::create_oneshot_account( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - Client::from_url(&args.url).await.unwrap(), - balance, - dest, - ) - .await? - } - Subcommand::ConsumeOneshot { dest, dest_oneshot } => { - commands::oneshot::consume_oneshot_account( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - Client::from_url(&args.url).await.unwrap(), - dest, - dest_oneshot, - ) - .await? - } - Subcommand::ConsumeOneshotWithRemaining { - balance, - dest, - dest_oneshot, - remaining_to, - remaining_to_oneshot, - } => { - commands::oneshot::consume_oneshot_account_with_remaining( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - Client::from_url(&args.url).await.unwrap(), - balance, - dest, - dest_oneshot, - remaining_to, - remaining_to_oneshot, - ) - .await? - } - Subcommand::Expire { blocks, sessions } => { - commands::expire::monitor_expirations( - Client::from_url(&args.url).await.unwrap(), - blocks, - sessions, - &args, - ) - .await? - } - Subcommand::Identity { - ref account_id, - identity_id, - ref username, - } => { - commands::identity::get_identity( - Client::from_url(&args.url).await.unwrap(), - account_id.clone(), - identity_id, - username.clone(), - &args, - ) - .await? - } - Subcommand::GenRevocDoc => { - commands::revocation::gen_revoc_doc( - &Client::from_url(&args.url).await.unwrap(), - &get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - ) - .await? - } - Subcommand::GoOffline => { - commands::smith::go_offline( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - Client::from_url(&args.url).await.unwrap(), - ) - .await? - } - Subcommand::GoOnline => { - commands::smith::go_online( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - Client::from_url(&args.url).await.unwrap(), - ) - .await? - } - Subcommand::OneshotBalance { account } => { - commands::oneshot::oneshot_account_balance( - Client::from_url(&args.url).await.unwrap(), - account, - ) - .await? - } - Subcommand::Online => { - commands::smith::online(Client::from_url(&args.url).await.unwrap(), &args).await? - } - Subcommand::Repart { - target, - actual_repart, - } => { - commands::net_test::repart( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - Client::from_url(&args.url).await.unwrap(), - target, - actual_repart, - ) - .await? - } - Subcommand::SpamRoll { actual_repart } => { - commands::net_test::spam_roll( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - Client::from_url(&args.url).await.unwrap(), - actual_repart, - ) - .await? - } - Subcommand::SudoSetKey { new_key } => { - commands::sudo::set_key( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - Client::from_url(&args.url).await.unwrap(), - new_key, - ) - .await? - } - Subcommand::TechMembers => { - commands::collective::technical_committee_members( - Client::from_url(&args.url).await.unwrap(), - &args, - ) - .await? - } - Subcommand::TechProposals => { - commands::collective::technical_committee_proposals( - Client::from_url(&args.url).await.unwrap(), - ) - .await? - } - Subcommand::TechVote { hash, index, vote } => { - let vote = match vote { - 0 => false, - 1 => true, - _ => panic!("Vote must be written 0 if you disagree, or 1 if you agree."), - }; - commands::collective::technical_committee_vote( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - Client::from_url(&args.url).await.unwrap(), - hash, //H256::from_str(&hash).expect("Invalid hash formatting"), - index, - vote, - ) - .await? - } - Subcommand::Transfer { - amount, - dest, - keep_alive, - } => { - commands::transfer::transfer( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - Client::from_url(&args.url).await.unwrap(), - amount, - dest, - keep_alive, - ) - .await? - } - Subcommand::TransferMultiple { amount, dests } => { - commands::transfer::transfer_multiple( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - Client::from_url(&args.url).await.unwrap(), - amount, - dests, - ) - .await? - } - Subcommand::UpdateKeys => commands::smith::update_session_keys( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - Client::from_url(&args.url).await.unwrap(), - ) - .await - .unwrap(), - } + match args.subcommand { + Subcommand::CreateOneshot { balance, dest } => { + commands::oneshot::create_oneshot_account( + get_keys( + args.secret_format, + &args.address, + &args.secret, + NeededKeys::Secret, + )? + .1 + .unwrap(), + Client::from_url(&args.url).await.unwrap(), + balance, + dest, + ) + .await? + } + Subcommand::ConsumeOneshot { dest, dest_oneshot } => { + commands::oneshot::consume_oneshot_account( + get_keys( + args.secret_format, + &args.address, + &args.secret, + NeededKeys::Secret, + )? + .1 + .unwrap(), + Client::from_url(&args.url).await.unwrap(), + dest, + dest_oneshot, + ) + .await? + } + Subcommand::ConsumeOneshotWithRemaining { + balance, + dest, + dest_oneshot, + remaining_to, + remaining_to_oneshot, + } => { + commands::oneshot::consume_oneshot_account_with_remaining( + get_keys( + args.secret_format, + &args.address, + &args.secret, + NeededKeys::Secret, + )? + .1 + .unwrap(), + Client::from_url(&args.url).await.unwrap(), + balance, + dest, + dest_oneshot, + remaining_to, + remaining_to_oneshot, + ) + .await? + } + Subcommand::Expire { blocks, sessions } => { + commands::expire::monitor_expirations( + Client::from_url(&args.url).await.unwrap(), + blocks, + sessions, + &args, + ) + .await? + } + Subcommand::Identity { + ref account_id, + identity_id, + ref username, + } => { + commands::identity::get_identity( + Client::from_url(&args.url).await.unwrap(), + account_id.clone(), + identity_id, + username.clone(), + &args, + ) + .await? + } + Subcommand::GenRevocDoc => { + commands::revocation::gen_revoc_doc( + &Client::from_url(&args.url).await.unwrap(), + &get_keys( + args.secret_format, + &args.address, + &args.secret, + NeededKeys::Secret, + )? + .1 + .unwrap(), + ) + .await? + } + Subcommand::GoOffline => { + commands::smith::go_offline( + get_keys( + args.secret_format, + &args.address, + &args.secret, + NeededKeys::Secret, + )? + .1 + .unwrap(), + Client::from_url(&args.url).await.unwrap(), + ) + .await? + } + Subcommand::GoOnline => { + commands::smith::go_online( + get_keys( + args.secret_format, + &args.address, + &args.secret, + NeededKeys::Secret, + )? + .1 + .unwrap(), + Client::from_url(&args.url).await.unwrap(), + ) + .await? + } + Subcommand::OneshotBalance { account } => { + commands::oneshot::oneshot_account_balance( + Client::from_url(&args.url).await.unwrap(), + account, + ) + .await? + } + Subcommand::Online => { + commands::smith::online(Client::from_url(&args.url).await.unwrap(), &args).await? + } + Subcommand::Repart { + target, + actual_repart, + } => { + commands::net_test::repart( + get_keys( + args.secret_format, + &args.address, + &args.secret, + NeededKeys::Secret, + )? + .1 + .unwrap(), + Client::from_url(&args.url).await.unwrap(), + target, + actual_repart, + ) + .await? + } + Subcommand::SpamRoll { actual_repart } => { + commands::net_test::spam_roll( + get_keys( + args.secret_format, + &args.address, + &args.secret, + NeededKeys::Secret, + )? + .1 + .unwrap(), + Client::from_url(&args.url).await.unwrap(), + actual_repart, + ) + .await? + } + Subcommand::SudoSetKey { new_key } => { + commands::sudo::set_key( + get_keys( + args.secret_format, + &args.address, + &args.secret, + NeededKeys::Secret, + )? + .1 + .unwrap(), + Client::from_url(&args.url).await.unwrap(), + new_key, + ) + .await? + } + Subcommand::TechMembers => { + commands::collective::technical_committee_members( + Client::from_url(&args.url).await.unwrap(), + &args, + ) + .await? + } + Subcommand::TechProposals => { + commands::collective::technical_committee_proposals( + Client::from_url(&args.url).await.unwrap(), + ) + .await? + } + Subcommand::TechVote { hash, index, vote } => { + let vote = match vote { + 0 => false, + 1 => true, + _ => panic!("Vote must be written 0 if you disagree, or 1 if you agree."), + }; + commands::collective::technical_committee_vote( + get_keys( + args.secret_format, + &args.address, + &args.secret, + NeededKeys::Secret, + )? + .1 + .unwrap(), + Client::from_url(&args.url).await.unwrap(), + hash, //H256::from_str(&hash).expect("Invalid hash formatting"), + index, + vote, + ) + .await? + } + Subcommand::Transfer { + amount, + dest, + keep_alive, + } => { + commands::transfer::transfer( + get_keys( + args.secret_format, + &args.address, + &args.secret, + NeededKeys::Secret, + )? + .1 + .unwrap(), + Client::from_url(&args.url).await.unwrap(), + amount, + dest, + keep_alive, + ) + .await? + } + Subcommand::TransferMultiple { amount, dests } => { + commands::transfer::transfer_multiple( + get_keys( + args.secret_format, + &args.address, + &args.secret, + NeededKeys::Secret, + )? + .1 + .unwrap(), + Client::from_url(&args.url).await.unwrap(), + amount, + dests, + ) + .await? + } + Subcommand::UpdateKeys => commands::smith::update_session_keys( + get_keys( + args.secret_format, + &args.address, + &args.secret, + NeededKeys::Secret, + )? + .1 + .unwrap(), + Client::from_url(&args.url).await.unwrap(), + ) + .await + .unwrap(), + } - Ok(()) + Ok(()) } -- GitLab