diff --git a/src/cache.rs b/src/cache.rs index 643f7a4a4d2b940d457f846d3f39cb0e71b5ee68..36d8c724a9c9eed3651055fc1f233bfa2832abb8 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -4,14 +4,14 @@ use crate::*; use anyhow::{anyhow, Result}; use std::collections::{hash_map, HashMap}; -pub struct IdentityCache<'a> { - client: &'a Client, +pub struct IdentityCache { + client: Client, identities: HashMap<u32, String>, - indexer: Option<Indexer<'a>>, + indexer: Option<Indexer>, } -impl<'a> IdentityCache<'a> { - pub fn new(client: &'a Client, indexer: Option<Indexer<'a>>) -> Self { +impl IdentityCache { + pub fn new(client: Client, indexer: Option<Indexer>) -> Self { Self { client, identities: HashMap::new(), diff --git a/src/commands.rs b/src/commands.rs index dc2ab80a11f89c838bf0c569de0333179223443d..18967d6f7c573910cd82808d5c12f35c3a25b8e9 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -5,6 +5,7 @@ pub mod identity; pub mod net_test; pub mod oneshot; pub mod revocation; +pub mod runtime; pub mod smith; pub mod sudo; pub mod transfer; diff --git a/src/commands/account.rs b/src/commands/account.rs index a04649c32764c02980a3e5616a73fb4f150ec1bb..3bad919407e37e81730eaae3e2e9168517c0d3e3 100644 --- a/src/commands/account.rs +++ b/src/commands/account.rs @@ -1,7 +1,6 @@ use crate::*; use anyhow::Result; -use sp_core::crypto::AccountId32; pub async fn get_balance(data: Data) -> Result<()> { let account_id = data.address(); @@ -18,8 +17,8 @@ pub async fn get_balance(data: Data) -> Result<()> { } pub async fn get_account_info( - client: Client, - account_id: &AccountId32, + client: &Client, + account_id: &AccountId, ) -> Result<Option<AccountInfo>> { Ok(client .storage() diff --git a/src/commands/collective.rs b/src/commands/collective.rs index a63b55b24873e0d57f23f33fc586abe06247c931..724a2d00dec3c270322338e6fea16ccba7ddfb0c 100644 --- a/src/commands/collective.rs +++ b/src/commands/collective.rs @@ -21,7 +21,7 @@ pub async fn technical_committee_members(client: Client, args: &Args) -> Result< } else { Some(Indexer { gql_client, - gql_url: &args.indexer, + gql_url: args.indexer.clone(), }) }; diff --git a/src/commands/expire.rs b/src/commands/expire.rs index f749f89068ed5971c56f80244f78013ee2129632..7cc964709c4d47fad066c1b51db2a58c4d89b5d6 100644 --- a/src/commands/expire.rs +++ b/src/commands/expire.rs @@ -37,13 +37,13 @@ pub async fn monitor_expirations( let end_session = current_session + sessions; let mut identity_cache = cache::IdentityCache::new( - &client, + client.clone(), if args.no_indexer { None } else { Some(Indexer { gql_client, - gql_url: &args.indexer, + gql_url: args.indexer.clone(), }) }, ); diff --git a/src/commands/identity.rs b/src/commands/identity.rs index 5f10aa622f47c497bd4efc4926968d3f993a7789..61e617a3f43c5b6329062cb9db99e89492ba7c8e 100644 --- a/src/commands/identity.rs +++ b/src/commands/identity.rs @@ -1,7 +1,7 @@ use crate::indexer::*; use crate::*; -use crate::commands::revocation::get_revoc_doc; +use crate::commands::revocation::generate_revoc_doc; use crate::runtime::runtime_types::common_runtime::entities::IdtyData; use crate::runtime::runtime_types::pallet_identity::types::*; use crate::runtime::runtime_types::sp_core::sr25519::Signature; @@ -12,7 +12,7 @@ use std::str::FromStr; use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; pub async fn get_identity( - client: Client, + client: &Client, mut account_id: Option<AccountId32>, mut identity_id: Option<u32>, mut username: Option<String>, @@ -26,7 +26,7 @@ pub async fn get_identity( gql_client: reqwest::Client::builder() .user_agent("gcli/0.1.0") .build()?, - gql_url: &args.indexer, + gql_url: args.indexer.clone(), }) }; @@ -82,7 +82,7 @@ pub async fn get_identity( } pub async fn get_idty_index_by_account_id( - client: Client, + client: &Client, account_id: &AccountId32, ) -> Result<Option<u32>> { Ok(client @@ -95,7 +95,7 @@ pub async fn get_idty_index_by_account_id( } pub async fn get_identity_by_index( - client: Client, + client: &Client, idty_index: u32, ) -> Result<Option<IdtyValue<u32, AccountId32, IdtyData>>> { Ok(client @@ -106,7 +106,7 @@ pub async fn get_identity_by_index( pub async fn create_identity( pair: Pair, - client: Client, + client: &Client, target: AccountId32, ) -> Result<TxProgress, subxt::Error> { client @@ -121,7 +121,7 @@ pub async fn create_identity( pub async fn confirm_identity( pair: Pair, - client: Client, + client: &Client, name: String, ) -> Result<TxProgress, subxt::Error> { client @@ -134,29 +134,23 @@ pub async fn confirm_identity( .await } -// TODO : use Result<TxProgress, subxt::Error> instead of Result<()> -pub async fn revoke_identity(pair: Pair, client: Client, account_id: AccountId32) -> Result<()> { - let (idty_index, signature) = get_revoc_doc(&client, &pair).await?; +/// generate revokation document and submit it immediately +pub async fn revoke_identity(data: Data) -> Result<TxProgress, subxt::Error> { + let (_payload, signature) = generate_revoc_doc(&data); // Transform signature to MultiSignature // TODO: this is a hack, we should be able to use the signature directly let signature = Signature(signature.0); let multisign = MultiSignature::Sr25519(signature); - client + data.client() .tx() .sign_and_submit_then_watch( &runtime::tx() .identity() - .revoke_identity(idty_index, account_id, multisign), - &PairSigner::new(pair), + .revoke_identity(data.idty_index(), data.address(), multisign), + &PairSigner::new(data.keypair()), BaseExtrinsicParamsBuilder::new(), ) - .await? - .wait_for_in_block() - .await? - .wait_for_success() - .await?; - - Ok(()) + .await } diff --git a/src/commands/revocation.rs b/src/commands/revocation.rs index 69a23041b00143a53d15233f22f78ff222712844..95e136855db951825364d48b3fb9cf0f12160f0f 100644 --- a/src/commands/revocation.rs +++ b/src/commands/revocation.rs @@ -1,31 +1,20 @@ use crate::*; -use anyhow::Result; -use futures::join; use sp_core::sr25519::Signature; -use sp_core::{sr25519::Pair, Encode, Pair as _}; -pub async fn generate_revoc_doc(api: &Client, pair: &Pair) -> Result<()> { - let signature = get_revoc_doc(api, pair).await?.1; +// TODO include prefix in RevocationPayload and use below +// use crate::runtime::runtime_types::pallet_identity::types::RevocationPayload; +type EncodedRevocationPayload = Vec<u8>; +pub fn print_revoc_sig(data: &Data) -> () { + let (_, signature) = generate_revoc_doc(data); + println!("revocation payload signature"); println!("0x{}", hex::encode(signature)); - - Ok(()) } -pub async fn get_revoc_doc(api: &Client, pair: &Pair) -> Result<(u32, Signature)> { - let account_id: sp_core::crypto::AccountId32 = pair.public().into(); - let addr_idty_index = runtime::storage().identity().identity_index_of(&account_id); - let addr_block_hash = runtime::storage().system().block_hash(0); - // Multiple fetches can be done in a single request. - 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); +pub fn generate_revoc_doc(data: &Data) -> (EncodedRevocationPayload, Signature) { + let payload = (b"revo", data.genesis_hash, data.idty_index()).encode(); + let signature = data.keypair().sign(&payload); - Ok((idty_index, signature)) + (payload, signature) } diff --git a/src/commands/runtime.rs b/src/commands/runtime.rs new file mode 100644 index 0000000000000000000000000000000000000000..be6ee976a62940c6faebae0986751322fc26e38f --- /dev/null +++ b/src/commands/runtime.rs @@ -0,0 +1,8 @@ +use crate::*; + +pub async fn runtime_info(_data: Data) -> () { + // TODO get information from runtime + // certification duration for example + println!("TODO"); + () +} diff --git a/src/commands/smith.rs b/src/commands/smith.rs index 3bc83d3d9ad100319e4ecdf055b9cd24472051ff..b45d49b984eda4021ee9707480905193acad6dcc 100644 --- a/src/commands/smith.rs +++ b/src/commands/smith.rs @@ -80,6 +80,7 @@ pub async fn go_offline(pair: Pair, client: Client) -> Result<()> { pub async fn online(client: Client, args: &Args) -> Result<()> { let parent_hash = client + .clone() .storage() .fetch(&runtime::storage().system().parent_hash(), None) .await? @@ -90,13 +91,13 @@ pub async fn online(client: Client, args: &Args) -> Result<()> { .build()?; let mut identity_cache = cache::IdentityCache::new( - &client, + client.clone(), if args.no_indexer { None } else { Some(Indexer { gql_client, - gql_url: &args.indexer, + gql_url: args.indexer.clone(), }) }, ); @@ -169,7 +170,7 @@ pub async fn online(client: Client, args: &Args) -> Result<()> { } /// submit a certification and track progress -pub async fn cert(client: Client, pair: Pair, issuer: u32, receiver: u32) -> Result<()> { +pub async fn cert(client: &Client, pair: Pair, issuer: u32, receiver: u32) -> Result<()> { let mut progress = client .tx() .sign_and_submit_then_watch( diff --git a/src/commands/sudo.rs b/src/commands/sudo.rs index 728708fe50cb5fd343340dc967a37aa43d53f69c..89bc43f7d3040ab488405628fb099a5220483467 100644 --- a/src/commands/sudo.rs +++ b/src/commands/sudo.rs @@ -4,7 +4,7 @@ use anyhow::Result; 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<()> { +pub async fn set_key(pair: Pair, client: &Client, new_key: AccountId32) -> Result<()> { client .tx() .sign_and_submit_then_watch( diff --git a/src/data.rs b/src/data.rs new file mode 100644 index 0000000000000000000000000000000000000000..58d1418bef97c2aa3bc4f50c1826eb6ec1c763e8 --- /dev/null +++ b/src/data.rs @@ -0,0 +1,166 @@ +use crate::*; + +// data derived from command arguments + +/// Data of current command +/// can also include fetched information +#[derive(Default)] +pub struct Data { + // command line arguments + pub args: Args, + // rpc to substrate client + pub client: Option<Client>, + // graphql to duniter-indexer + pub indexer: Option<Indexer>, + // user address + pub address: Option<AccountId>, + // user keypair + pub keypair: Option<Pair>, + // user identity index + pub idty_index: Option<u32>, + // token decimals + pub token_decimals: u32, + // token symbol + pub token_symbol: String, + // genesis hash + pub genesis_hash: Hash, +} + +/// system properties defined in client specs +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct SystemProperties { + token_decimals: u32, + token_symbol: String, +} + +// implement helper functions for Data +impl Data { + /// --- constructor --- + pub fn new(args: Args) -> Self { + Self { + args, + token_decimals: 0, + token_symbol: "tokens".into(), + ..Default::default() + } + } + // --- getters --- + // the "unwrap" should not fail if data is well prepared + pub fn client(&self) -> &Client { + self.client.as_ref().expect("must build client first") + } + pub fn indexer(&self) -> &Indexer { + self.indexer.as_ref().expect("indexer is not set up") + } + pub fn address(&self) -> AccountId { + self.address.clone().expect("an address is needed") + } + pub fn keypair(&self) -> Pair { + self.keypair.clone().expect("a keypair is needed") + } + pub fn idty_index(&self) -> u32 { + self.idty_index.expect("must fetch idty index first") + } + // --- methods --- + pub fn format_balance(&self, amount: Balance) -> String { + let base: u32 = 10; + format!( + "{} {}", + (amount as f32) / (base.pow(self.token_decimals) as f32), + self.token_symbol + ) + } + // --- mutators --- + /// force an address if needed + pub fn build_address(mut self) -> Self { + self.address = Some( + get_keys( + self.args.secret_format, + &self.args.address, + &self.args.secret, + NeededKeys::Public, + ) + .expect("needed") + .0 + .expect("needed"), + ); + self + } + /// force a keypair if needed + pub fn build_keypair(mut self) -> Self { + let (address, keypair) = get_keys( + self.args.secret_format, + &self.args.address, + &self.args.secret, + NeededKeys::Secret, + ) + .expect("needed"); + self.address = address; + self.keypair = keypair; + self + } + /// build a client from url + // TODO get client from a pre-defined list + pub async fn build_client(mut self) -> Self { + self.client = Some(Client::from_url(&self.args.url).await.expect("needed")); + self + } + /// build an indexer if not disabled + // TODO check that indexer matches client + pub fn build_indexer(mut self) -> Result<Self, anyhow::Error> { + self.indexer = if self.args.no_indexer { + None + } else { + Some(Indexer { + gql_client: reqwest::Client::builder() + .user_agent("gcli/0.1.0") + .build()?, + gql_url: self.args.indexer.clone(), + }) + }; + Ok(self) + } + /// get issuer index + /// needs address and client first + pub async fn fetch_idty_index(mut self) -> Result<Self, anyhow::Error> { + self.idty_index = Some( + commands::identity::get_idty_index_by_account_id(self.client(), &self.address()) + .await? + .ok_or(anyhow::anyhow!("needs to be member to use this command"))?, + ); + Ok(self) + } + /// get genesis hash + pub async fn fetch_genesis_hash(mut self) -> Result<Self, anyhow::Error> { + self.genesis_hash = self + .client() + .storage() + .fetch(&runtime::storage().system().block_hash(0), None) + .await? + .unwrap(); + Ok(self) + } + /// get properties + pub async fn fetch_system_properties(mut self) -> Result<Self, anyhow::Error> { + let system_properties = self.client().rpc().system_properties().await?; + let system_properties = serde_json::from_value::<SystemProperties>( + serde_json::Value::Object(system_properties), + )?; + self.token_decimals = system_properties.token_decimals; + self.token_symbol = system_properties.token_symbol; + Ok(self) + } + // TODO prevent awaits in async methods, prefer register requests and execute them all at once with a join + // example below + // example!( + // use futures::join; + // let addr_idty_index = runtime::storage().identity().identity_index_of(&account_id); + // let addr_block_hash = runtime::storage().system().block_hash(0); + // // Multiple fetches can be done in parallel. + // let (idty_index, genesis_hash) = join!( + // api.storage().fetch(&addr_idty_index, None), + // api.storage().fetch(&addr_block_hash, None) + // ); + // ); +} diff --git a/src/indexer.rs b/src/indexer.rs index 0a48b0eb1ef9342fc5f73acec9ea6f186eb9e574..a10f6051bbd64c2feaf03a9f6c6bbd8226794c8a 100644 --- a/src/indexer.rs +++ b/src/indexer.rs @@ -16,16 +16,17 @@ pub struct IdentityNameByPubkey; )] pub struct IdentityPubkeyByName; -pub struct Indexer<'a> { +#[derive(Clone)] +pub struct Indexer { pub gql_client: reqwest::Client, - pub gql_url: &'a str, + pub gql_url: String, } -impl<'a> Indexer<'a> { +impl Indexer { pub async fn username_by_pubkey(&self, pubkey: &str) -> Result<Option<String>> { Ok(post_graphql::<IdentityNameByPubkey, _>( &self.gql_client, - self.gql_url, + &self.gql_url, identity_name_by_pubkey::Variables { pubkey: pubkey.to_string(), }, @@ -38,7 +39,7 @@ impl<'a> Indexer<'a> { pub async fn pubkey_by_username(&self, username: &str) -> Result<Option<String>> { Ok(post_graphql::<IdentityPubkeyByName, _>( &self.gql_client, - self.gql_url, + self.gql_url.clone(), identity_pubkey_by_name::Variables { name: username.to_string(), }, diff --git a/src/main.rs b/src/main.rs index 3f8ec7a72885e295886b96b4e7793e4f2de4ba5e..ed9bb2f81ca42887746b19f0b34589b87e899158 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,16 @@ mod cache; mod commands; +mod data; mod indexer; mod keys; use clap::Parser; use codec::Encode; +use data::*; +use indexer::*; use keys::*; use serde::Deserialize; -use sp_core::sr25519::Pair; -use sp_core::H256; +use sp_core::{sr25519::Pair, Pair as _, H256}; #[cfg(feature = "dev")] #[subxt::subxt( @@ -21,6 +23,7 @@ pub mod runtime { // use crate::gdev::runtime_types::sp_core::sr25519::Signature; } +// declare custom types pub type Client = subxt::OnlineClient<Runtime>; pub type AccountId = subxt::ext::sp_runtime::AccountId32; pub type TxInBlock = subxt::tx::TxInBlock<Runtime, Client>; @@ -28,12 +31,14 @@ pub type TxProgress = subxt::tx::TxProgress<Runtime, Client>; pub type Balance = u64; pub type AccountData = runtime::runtime_types::pallet_duniter_account::types::AccountData<Balance>; pub type AccountInfo = runtime::runtime_types::frame_system::AccountInfo<u32, AccountData>; +pub type Hash = sp_core::H256; +// declare runtime types pub enum Runtime {} impl subxt::config::Config for Runtime { type Index = u32; type BlockNumber = u32; - type Hash = sp_core::H256; + type Hash = Hash; type Hashing = subxt::ext::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Address = subxt::ext::sp_runtime::MultiAddress<Self::AccountId, u32>; @@ -45,30 +50,30 @@ impl subxt::config::Config for Runtime { type ExtrinsicParams = subxt::tx::BaseExtrinsicParams<Self, Tip>; } -#[derive(Copy, Clone, Debug, Default, Encode)] +// Tip for transaction fee +#[derive(Copy, Clone, Debug, Default, codec::Encode)] pub struct Tip { #[codec(compact)] tip: u64, } - impl Tip { pub fn new(amount: u64) -> Self { Tip { tip: amount } } } - impl From<u64> for Tip { fn from(n: u64) -> Self { Self::new(n) } } -#[derive(Clone, Parser, Debug, Default)] +// define command line arguments +#[derive(Clone, clap::Parser, Debug, Default)] #[clap(author, version, about, long_about = None)] pub struct Args { + /// Subcommands #[clap(subcommand)] pub subcommand: Subcommand, - /// Indexer URL #[clap(short, long, default_value = "http://localhost:8080/v1/graphql")] indexer: String, @@ -90,120 +95,6 @@ pub struct Args { url: String, } -/// Data of current command -/// can also include fetched information -#[derive(Default)] -pub struct Data { - pub args: Args, - pub client: Option<Client>, - pub address: Option<AccountId>, - pub keypair: Option<Pair>, - pub idty_index: Option<u32>, - pub token_decimals: u32, - pub token_symbol: String, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct SystemProperties { - token_decimals: u32, - token_symbol: String, -} - -// implement helper functions for Data -impl Data { - /// --- constructor --- - pub fn new(args: Args) -> Self { - Self { - args, - token_decimals: 0, - token_symbol: "tokens".into(), - ..Default::default() - } - } - // --- getters --- - // the "unwrap" should not fail if data is well prepared - pub fn client(&self) -> Client { - self.client.clone().unwrap() - } - pub fn address(&self) -> AccountId { - self.address.clone().unwrap() - } - pub fn keypair(&self) -> Pair { - self.keypair.clone().unwrap() - } - pub fn idty_index(&self) -> u32 { - self.idty_index.unwrap() - } - // --- methods --- - pub fn format_balance(&self, amount: Balance) -> String { - let base: u32 = 10; - format!( - "{} {}", - (amount as f32) / (base.pow(self.token_decimals) as f32), - self.token_symbol - ) - } - // --- mutators --- - /// force an address if needed - pub fn build_address(mut self) -> Self { - self.address = Some( - get_keys( - self.args.secret_format, - &self.args.address, - &self.args.secret, - NeededKeys::Public, - ) - .expect("needed") - .0 - .expect("needed"), - ); - self - } - /// force a keypair if needed - pub fn build_keypair(mut self) -> Self { - let (address, keypair) = get_keys( - self.args.secret_format, - &self.args.address, - &self.args.secret, - NeededKeys::Secret, - ) - .expect("needed"); - self.address = address; - self.keypair = keypair; - self - } - /// build a client from url - // TODO get client from a pre-defined list - pub async fn build_client(mut self) -> Self { - self.client = Some(Client::from_url(&self.args.url).await.expect("needed")); - self - } - /// get issuer index - /// needs address and client first - pub async fn fetch_idty_index(mut self) -> Result<Self, anyhow::Error> { - self.idty_index = Some( - commands::identity::get_idty_index_by_account_id( - self.client().clone(), - &self.address(), - ) - .await? - .ok_or(anyhow::anyhow!("needs to be member to use this command"))?, - ); - Ok(self) - } - /// get properties - pub async fn fetch_system_properties(mut self) -> Result<Self, anyhow::Error> { - let system_properties = self.client().clone().rpc().system_properties().await?; - let system_properties = serde_json::from_value::<SystemProperties>( - serde_json::Value::Object(system_properties), - )?; - self.token_decimals = system_properties.token_decimals; - self.token_symbol = system_properties.token_symbol; - Ok(self) - } -} - /// track progress of transaction on the network /// until it is in block with success or failure pub async fn track_progress(progress: TxProgress) -> anyhow::Result<()> { @@ -246,11 +137,22 @@ pub enum Subcommand { /// Fetch account balance #[default] GetBalance, + /// Show address corresponding to given arguments + ShowAddress, + /// Fetch identity + Identity { + #[clap(short = 'p', long = "pubkey")] + account_id: Option<AccountId>, + #[clap(short = 'i', long = "identity")] + identity_id: Option<u32>, + #[clap(short = 'u', long = "username")] + username: Option<String>, + }, /// Create and certify an identity /// /// Caller must be member, and the target account must exist. CreateIdentity { - target: sp_core::crypto::AccountId32, + target: AccountId, }, /// Confirm an identity /// @@ -258,24 +160,31 @@ pub enum Subcommand { ConfirmIdentity { name: String, }, + /// Generate a revocation document for the provided account + GenRevocDoc, + /// Revoke an identity immediately + RevokeIdentity, CreateOneshot { balance: u64, - dest: sp_core::crypto::AccountId32, + dest: AccountId, }, ConsumeOneshot { - dest: sp_core::crypto::AccountId32, + dest: AccountId, #[clap(long = "oneshot")] dest_oneshot: bool, }, ConsumeOneshotWithRemaining { balance: u64, - dest: sp_core::crypto::AccountId32, + dest: AccountId, #[clap(long = "one")] dest_oneshot: bool, - remaining_to: sp_core::crypto::AccountId32, + remaining_to: AccountId, #[clap(long = "rem-one")] remaining_to_oneshot: bool, }, + OneshotBalance { + account: AccountId, + }, /// List upcoming expirations that require an action Expire { /// Show certs that expire within less than this number of blocks @@ -285,22 +194,8 @@ pub enum Subcommand { #[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)] @@ -316,7 +211,7 @@ pub enum Subcommand { actual_repart: usize, }, SudoSetKey { - new_key: sp_core::crypto::AccountId32, + new_key: AccountId, }, /// Emit a smith certification SmithCert { @@ -339,7 +234,7 @@ pub enum Subcommand { /// Amount to transfer amount: u64, /// Destination address - dest: sp_core::crypto::AccountId32, + dest: AccountId, /// Prevent from going below account existential deposit #[clap(short = 'k', long = "keep-alive")] keep_alive: bool, @@ -350,12 +245,15 @@ pub enum Subcommand { /// Amount given to each destination address amount: u64, /// List of target addresses - dests: Vec<sp_core::crypto::AccountId32>, + dests: Vec<AccountId>, }, /// Rotate and set session keys UpdateKeys, - /// Revoke an identity - RevokeIdentity, + /// Get information about runtime + RuntimeInfo, + /// Indexer subcommands + #[clap(subcommand)] + Indexer(IndexerSubcommand), } #[tokio::main(flavor = "current_thread")] @@ -375,6 +273,10 @@ async fn main() -> Result<(), GcliError> { .await?; commands::account::get_balance(data).await? } + Subcommand::ShowAddress => { + data = data.build_address(); + println!("address is: {}", data.address()); + } Subcommand::CreateIdentity { target } => { data = data.build_client().await.build_keypair(); let progress = @@ -387,6 +289,18 @@ async fn main() -> Result<(), GcliError> { commands::identity::confirm_identity(data.keypair(), data.client(), name).await?; track_progress(progress).await? } + Subcommand::RevokeIdentity => { + data = data + .build_client() + .await + .build_keypair() + .fetch_idty_index() + .await? + .fetch_genesis_hash() + .await?; + let progress = commands::identity::revoke_identity(data).await?; + track_progress(progress).await? + } Subcommand::CreateOneshot { balance, dest } => { commands::oneshot::create_oneshot_account( get_keys( @@ -458,8 +372,9 @@ async fn main() -> Result<(), GcliError> { identity_id, ref username, } => { + data = data.build_client().await; commands::identity::get_identity( - Client::from_url(&args.url).await.unwrap(), + data.client(), account_id.clone(), identity_id, username.clone(), @@ -468,18 +383,15 @@ async fn main() -> Result<(), GcliError> { .await? } Subcommand::GenRevocDoc => { - commands::revocation::generate_revoc_doc( - &Client::from_url(&args.url).await.unwrap(), - &get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - ) - .await? + data = data + .build_client() + .await + .build_keypair() + .fetch_idty_index() + .await? + .fetch_genesis_hash() + .await?; + commands::revocation::print_revoc_sig(&data) } Subcommand::GoOffline => { commands::smith::go_offline( @@ -554,19 +466,8 @@ async fn main() -> Result<(), GcliError> { .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? + data = data.build_keypair().build_client().await; + commands::sudo::set_key(data.keypair(), data.client(), new_key).await? } Subcommand::SmithCert { to } => { data = data @@ -662,21 +563,8 @@ async fn main() -> Result<(), GcliError> { ) .await .unwrap(), - Subcommand::RevokeIdentity => { - let (address, pair) = get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )?; - - commands::identity::revoke_identity( - pair.unwrap(), - Client::from_url(&args.url).await.unwrap(), - address.unwrap(), - ) - .await? - } + Subcommand::RuntimeInfo => commands::runtime::runtime_info(data).await, + Subcommand::Indexer(subcommand) => indexer::handle_command(data, subcommand)?, } Ok(())