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(())