diff --git a/res/indexer-queries.graphql b/res/indexer-queries.graphql
index b02516a8d9c45a4a2caa35a61fe1d38c120f5e15..304a8eeb30949d7dffda7a972c37348d88b883fa 100644
--- a/res/indexer-queries.graphql
+++ b/res/indexer-queries.graphql
@@ -4,6 +4,13 @@ query IdentityNameByIndex($index: Int!) {
   }
 }
 
+query NamesByIndexes($indexes: [Int!]!) {
+  identities(where: {index_in: $indexes}) {
+    index
+    name
+  }
+}
+
 query IdentityInfo($index: Int!) {
   identities(where: { index_eq: $index }) {
     name
diff --git a/src/cache.rs b/src/cache.rs
deleted file mode 100644
index 94316b5a36f8e425427967ef2f1ce91f6854a135..0000000000000000000000000000000000000000
--- a/src/cache.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-use crate::{indexer::*, *};
-
-use std::collections::{hash_map, HashMap};
-
-pub struct IdentityCache {
-	client: Client,
-	identities: HashMap<IdtyId, String>,
-	indexer: Option<Indexer>,
-}
-
-impl IdentityCache {
-	pub fn new(client: Client, indexer: Option<Indexer>) -> Self {
-		Self {
-			client,
-			identities: HashMap::new(),
-			indexer,
-		}
-	}
-
-	pub async fn fetch_identity(
-		&mut self,
-		identity_id: IdtyId,
-		parent_hash: sp_core::H256,
-	) -> anyhow::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()
-						.at(parent_hash)
-						.fetch(&runtime::storage().identity().identities(identity_id))
-						.await?
-						.ok_or_else(|| anyhow!("Identity {} not found", identity_id))?
-						.owner_key
-						.to_string();
-					format!(
-						"“ {} ”",
-						if let Some(indexer) = &self.indexer {
-							if let Some(username) = indexer.username_by_pubkey(&pubkey).await {
-								username
-							} else {
-								pubkey
-							}
-						} else {
-							pubkey
-						}
-					)
-				})
-				.clone(),
-		})
-	}
-}
diff --git a/src/commands/expire.rs b/src/commands/expire.rs
index d8f7bf0ed9d4b8f6822b4cd6fbef434003f5a976..f70ff42b15bdc4cf1dc37ae1e52d62002a4e9c2b 100644
--- a/src/commands/expire.rs
+++ b/src/commands/expire.rs
@@ -1,5 +1,4 @@
-use crate::*;
-
+use crate::{indexer::*, *};
 use futures::join;
 use std::collections::BTreeMap;
 
@@ -27,7 +26,7 @@ pub async fn monitor_expirations(data: &Data, blocks: u32, _sessions: u32) -> an
 
 	let end_block = current_block + blocks;
 
-	let mut identity_cache = cache::IdentityCache::new(client.clone(), indexer);
+	let mut identity_cache = IdentityCache::new(client.clone(), indexer);
 
 	// Certifications
 	let mut basic_certs_iter = client
@@ -51,12 +50,12 @@ pub async fn monitor_expirations(data: &Data, blocks: u32, _sessions: u32) -> an
 				println!(
 					"  {} ({}) -> {} ({})",
 					identity_cache
-						.fetch_identity(issuer_id, parent_hash)
+						.fetch_identity(issuer_id,)
 						.await
 						.unwrap_or_else(|_| "?".into()),
 					issuer_id,
 					identity_cache
-						.fetch_identity(receiver_id, parent_hash)
+						.fetch_identity(receiver_id,)
 						.await
 						.unwrap_or_else(|_| "?".into()),
 					receiver_id,
@@ -68,7 +67,8 @@ pub async fn monitor_expirations(data: &Data, blocks: u32, _sessions: u32) -> an
 	// Memberships
 	let mut basic_membership_iter = client
 		.storage()
-		.at(parent_hash)
+		.at_latest()
+		.await?
 		.iter(runtime::storage().membership().memberships_expire_on_iter())
 		.await?;
 	let mut basic_memberships = BTreeMap::new();
@@ -90,7 +90,7 @@ pub async fn monitor_expirations(data: &Data, blocks: u32, _sessions: u32) -> an
 				println!(
 					"  {} ({})",
 					identity_cache
-						.fetch_identity(identity_id, parent_hash)
+						.fetch_identity(identity_id)
 						.await
 						.unwrap_or_else(|_| "?".into()),
 					identity_id,
@@ -101,3 +101,53 @@ pub async fn monitor_expirations(data: &Data, blocks: u32, _sessions: u32) -> an
 
 	Ok(())
 }
+
+use std::collections::{hash_map, HashMap};
+
+pub struct IdentityCache {
+	client: Client,
+	identities: HashMap<IdtyId, String>,
+	indexer: Option<Indexer>,
+}
+
+impl IdentityCache {
+	pub fn new(client: Client, indexer: Option<Indexer>) -> Self {
+		Self {
+			client,
+			identities: HashMap::new(),
+			indexer,
+		}
+	}
+
+	pub async fn fetch_identity(&mut self, identity_id: IdtyId) -> anyhow::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()
+						.at_latest()
+						.await?
+						.fetch(&runtime::storage().identity().identities(identity_id))
+						.await?
+						.ok_or_else(|| anyhow!("Identity {} not found", identity_id))?
+						.owner_key
+						.to_string();
+					format!(
+						"“ {} ”",
+						if let Some(indexer) = &self.indexer {
+							if let Some(username) = indexer.username_by_pubkey(&pubkey).await {
+								username
+							} else {
+								pubkey
+							}
+						} else {
+							pubkey
+						}
+					)
+				})
+				.clone(),
+		})
+	}
+}
diff --git a/src/commands/identity.rs b/src/commands/identity.rs
index 448c87b38858800d7e935be1916e440857f70591..052f91689e3cd76ce4b5af1aa866e2afe5411e64 100644
--- a/src/commands/identity.rs
+++ b/src/commands/identity.rs
@@ -275,7 +275,7 @@ pub async fn get_identity(
 	let pseudo = pseudo.unwrap_or(if let Some(indexer) = &indexer {
 		indexer
 			.username_by_index(index)
-			.await?
+			.await
 			.ok_or_else(|| anyhow!("indexer does not have username for this index {index}"))?
 	} else {
 		"<no indexer>".to_string()
diff --git a/src/commands/smith.rs b/src/commands/smith.rs
index ad2d1cd512a00d0706f68a19ac52f2193fcf1546..034948b617a3e4924863fa4f6d9736095801e485 100644
--- a/src/commands/smith.rs
+++ b/src/commands/smith.rs
@@ -3,6 +3,7 @@ use crate::*;
 use commands::identity::try_get_idty_index_by_name;
 #[cfg(feature = "gdev")]
 use runtime::runtime_types::gdev_runtime::opaque::SessionKeys as RuntimeSessionKeys;
+use std::collections::HashMap;
 use std::ops::Deref;
 
 type SessionKeys = [u8; 128];
@@ -68,7 +69,7 @@ pub enum Subcommand {
 
 /// handle smith commands
 pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliError> {
-	let mut data = data.build_client().await?;
+	let mut data = data.build_client().await?.build_indexer().await?;
 	match command {
 		Subcommand::GoOnline => {
 			go_online(&data).await?;
@@ -191,40 +192,18 @@ pub async fn go_offline(data: &Data) -> Result<(), subxt::Error> {
 /// get online authorities
 pub async fn online(data: &Data) -> Result<(), anyhow::Error> {
 	let client = data.client();
-	let indexer = data.indexer.clone();
 
-	let parent_hash = client
-		.clone()
+	let online_authorities = client
 		.storage()
 		.at_latest()
 		.await?
-		.fetch(&runtime::storage().system().parent_hash())
-		.await?
-		.unwrap();
-
-	let mut identity_cache = cache::IdentityCache::new(client.clone(), indexer);
-
-	let online_authorities = client
-		.storage()
-		.at(parent_hash)
 		.fetch(&runtime::storage().authority_members().online_authorities())
 		.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()
-		.at(parent_hash)
+		.at_latest()
+		.await?
 		.fetch(
 			&runtime::storage()
 				.authority_members()
@@ -232,21 +211,10 @@ pub async fn online(data: &Data) -> Result<(), anyhow::Error> {
 		)
 		.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()
-		.at(parent_hash)
+		.at_latest()
+		.await?
 		.fetch(
 			&runtime::storage()
 				.authority_members()
@@ -255,15 +223,59 @@ pub async fn online(data: &Data) -> Result<(), anyhow::Error> {
 		.await?
 		.unwrap_or_default();
 
-	println!("Outgoing:");
-	for identity_id in outgoing_authorities {
+	if let Some(indexer) = &data.indexer {
+		let mut names = HashMap::<IdtyId, String>::new();
+		indexer
+			.names_by_indexes(&online_authorities)
+			.await
+			.into_iter()
+			.for_each(|e| {
+				names.insert(e.0, e.1);
+			});
+		println!("Online:");
+		println!(
+			"{}",
+			online_authorities
+				.iter()
+				.map(|i| &names
+					.get(i)
+					.expect("panic! found authorities whith no name")[..])
+				.collect::<Vec<&str>>()
+				.join(", ")
+		);
+
+		println!("Incoming:");
 		println!(
-			"  {}",
-			identity_cache
-				.fetch_identity(identity_id, parent_hash)
-				.await
-				.unwrap_or_else(|_| format!("{identity_id}"))
+			"{}",
+			incoming_authorities
+				.iter()
+				.map(|i| &names
+					.get(i)
+					.expect("panic! found authorities whith no name")[..])
+				.collect::<Vec<&str>>()
+				.join(", ")
 		);
+
+		println!("Outgoing:");
+		println!(
+			"{}",
+			outgoing_authorities
+				.iter()
+				.map(|i| &names
+					.get(i)
+					.expect("panic! found authorities whith no name")[..])
+				.collect::<Vec<&str>>()
+				.join(", ")
+		);
+	} else {
+		println!("Online:");
+		println!("{online_authorities:?}");
+
+		println!("Incoming:");
+		println!("{incoming_authorities:?}");
+
+		println!("Outgoing:");
+		println!("{outgoing_authorities:?}");
 	}
 
 	Ok(())
diff --git a/src/indexer.rs b/src/indexer.rs
index 495a99a97797052232ab6cb6e5813ccfb546ce7d..f940b30969db2f3fb1d17d7545d5e20737dafd5c 100644
--- a/src/indexer.rs
+++ b/src/indexer.rs
@@ -1,67 +1,13 @@
+mod queries;
+
 use crate::*;
 use comfy_table::*;
 use comfy_table::{ContentArrangement, Table};
-use graphql_client::{reqwest::post_graphql, GraphQLQuery};
-use identity_info::*;
+use graphql_client::reqwest::post_graphql;
+use graphql_client::GraphQLQuery;
+use queries::*;
 use sp_core::Bytes;
 
-// type used in parameters query
-// #[allow(non_camel_case_types)]
-// type jsonb = serde_json::Value;
-
-// index → identity
-#[derive(GraphQLQuery)]
-#[graphql(
-	schema_path = "res/indexer-schema.json",
-	query_path = "res/indexer-queries.graphql"
-)]
-pub struct IdentityNameByIndex;
-
-// index → identity info
-#[derive(GraphQLQuery)]
-#[graphql(
-	schema_path = "res/indexer-schema.json",
-	query_path = "res/indexer-queries.graphql"
-)]
-pub struct IdentityInfo;
-
-// pubkey → identity
-#[derive(GraphQLQuery)]
-#[graphql(
-	schema_path = "res/indexer-schema.json",
-	query_path = "res/indexer-queries.graphql"
-)]
-pub struct IdentityNameByPubkey;
-
-// pubkey → wasidentity
-#[derive(GraphQLQuery)]
-#[graphql(
-	schema_path = "res/indexer-schema.json",
-	query_path = "res/indexer-queries.graphql"
-)]
-pub struct WasIdentityNameByPubkey;
-
-#[derive(GraphQLQuery)]
-#[graphql(
-	schema_path = "res/indexer-schema.json",
-	query_path = "res/indexer-queries.graphql"
-)]
-pub struct LatestBlock;
-
-#[derive(GraphQLQuery)]
-#[graphql(
-	schema_path = "res/indexer-schema.json",
-	query_path = "res/indexer-queries.graphql"
-)]
-pub struct BlockByNumber;
-
-#[derive(GraphQLQuery, Debug)]
-#[graphql(
-	schema_path = "res/indexer-schema.json",
-	query_path = "res/indexer-queries.graphql"
-)]
-pub struct GenesisHash;
-
 #[derive(Clone, Debug)]
 pub struct Indexer {
 	pub gql_client: reqwest::Client,
@@ -69,80 +15,79 @@ pub struct Indexer {
 }
 
 impl Indexer {
+	/// graphql query without error management
+	async fn query<T: GraphQLQuery>(
+		&self,
+		var: <T as GraphQLQuery>::Variables,
+	) -> <T as GraphQLQuery>::ResponseData {
+		post_graphql::<T, _>(&self.gql_client, &self.gql_url, var)
+			.await
+			.expect("indexer connexion error")
+			.data
+			.expect("indexer error")
+	}
+
 	/// index → name
-	pub async fn username_by_index(&self, index: u32) -> anyhow::Result<Option<String>> {
-		Ok(post_graphql::<IdentityNameByIndex, _>(
-			&self.gql_client,
-			&self.gql_url,
-			identity_name_by_index::Variables {
-				index: index.into(),
-			},
-		)
-		.await?
-		.data
-		.and_then(move |mut data| data.identities.pop().map(|idty| idty.name)))
+	pub async fn username_by_index(&self, index: u32) -> Option<String> {
+		self.query::<IdentityNameByIndex>(identity_name_by_index::Variables {
+			index: index.into(),
+		})
+		.await
+		.identities
+		.pop()
+		.map(|idty| idty.name)
+	}
+
+	/// index → name (multiple)
+	pub async fn names_by_indexes(&self, indexes: &[IdtyId]) -> Vec<(IdtyId, String)> {
+		self.query::<NamesByIndexes>(names_by_indexes::Variables {
+			indexes: indexes.iter().map(|i| *i as i64).collect(),
+		})
+		.await
+		.identities
+		.into_iter()
+		.map(|idty| (idty.index as IdtyId, idty.name))
+		.collect()
 	}
 
 	/// pubkey → name
 	pub async fn username_by_pubkey(&self, pubkey: &str) -> Option<String> {
-		post_graphql::<IdentityNameByPubkey, _>(
-			&self.gql_client,
-			&self.gql_url,
-			identity_name_by_pubkey::Variables {
-				pubkey: pubkey.to_string(),
-			},
-		)
+		self.query::<IdentityNameByPubkey>(identity_name_by_pubkey::Variables {
+			pubkey: pubkey.to_string(),
+		})
 		.await
-		.expect("indexer connexion error")
-		.data
-		.and_then(move |mut data| data.identities.pop().map(|idty| idty.name))
+		.identities
+		.pop()
+		.map(|idty| idty.name)
 	}
 
 	/// pubkey → was name
 	pub async fn wasname_by_pubkey(&self, pubkey: &str) -> Option<String> {
-		post_graphql::<WasIdentityNameByPubkey, _>(
-			&self.gql_client,
-			&self.gql_url,
-			was_identity_name_by_pubkey::Variables {
-				pubkey: pubkey.to_string(),
-			},
-		)
-		.await
-		.expect("indexer connexion error")
-		.data
-		.and_then(move |data| {
-			data.account_by_id
-				.and_then(|mut acc| acc.was_identity.pop())
-				.map(|idty| idty.identity.name)
+		self.query::<WasIdentityNameByPubkey>(was_identity_name_by_pubkey::Variables {
+			pubkey: pubkey.to_string(),
 		})
+		.await
+		.account_by_id
+		.and_then(|mut acc| acc.was_identity.pop())
+		.map(|idty| idty.identity.name)
 	}
 
 	/// index → info
-	pub async fn identity_info(&self, index: u32) -> Option<IdentityInfoIdentities> {
-		post_graphql::<IdentityInfo, _>(
-			&self.gql_client,
-			&self.gql_url,
-			identity_info::Variables {
-				index: index.into(),
-			},
-		)
+	pub async fn identity_info(&self, index: u32) -> Option<identity_info::IdentityInfoIdentities> {
+		self.query::<IdentityInfo>(identity_info::Variables {
+			index: index.into(),
+		})
 		.await
-		.expect("indexer connexion error")
-		.data
-		.and_then(move |mut data| data.identities.pop())
+		.identities
+		.pop()
 	}
 
 	/// fetch latest block
 	pub async fn fetch_latest_block(&self) -> Option<latest_block::LatestBlockBlocks> {
-		post_graphql::<LatestBlock, _>(
-			&self.gql_client,
-			self.gql_url.clone(),
-			latest_block::Variables {},
-		)
-		.await
-		.expect("indexer connexion error")
-		.data
-		.and_then(move |mut data| data.blocks.pop())
+		self.query::<LatestBlock>(latest_block::Variables {})
+			.await
+			.blocks
+			.pop()
 	}
 
 	/// fetch block by number
@@ -150,21 +95,16 @@ impl Indexer {
 		&self,
 		number: BlockNumber,
 	) -> Option<block_by_number::BlockByNumberBlocks> {
-		post_graphql::<BlockByNumber, _>(
-			&self.gql_client,
-			self.gql_url.clone(),
-			block_by_number::Variables {
-				number: number.into(),
-			},
-		)
+		self.query::<BlockByNumber>(block_by_number::Variables {
+			number: number.into(),
+		})
 		.await
-		.expect("indexer connexion error")
-		.data
-		.and_then(move |mut data| data.blocks.pop())
+		.blocks
+		.pop()
 	}
 
 	/// fetch genesis hash
-	// since this is always called before any other indexer request, check errors
+	// since this is always called before any other indexer request, check errors in a more detailed way
 	pub async fn fetch_genesis_hash(&self) -> Result<Hash, GcliError> {
 		// try to connect to indexer
 		let response = post_graphql::<GenesisHash, _>(
diff --git a/src/indexer/queries.rs b/src/indexer/queries.rs
new file mode 100644
index 0000000000000000000000000000000000000000..29b657286492dc5c12cc77e7722ecab8adb1c80c
--- /dev/null
+++ b/src/indexer/queries.rs
@@ -0,0 +1,58 @@
+use graphql_client::GraphQLQuery;
+use sp_core::Bytes;
+
+#[derive(GraphQLQuery)]
+#[graphql(
+	schema_path = "res/indexer-schema.json",
+	query_path = "res/indexer-queries.graphql"
+)]
+pub struct IdentityNameByIndex;
+
+#[derive(GraphQLQuery)]
+#[graphql(
+	schema_path = "res/indexer-schema.json",
+	query_path = "res/indexer-queries.graphql"
+)]
+pub struct IdentityInfo;
+
+#[derive(GraphQLQuery)]
+#[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"
+)]
+pub struct WasIdentityNameByPubkey;
+
+#[derive(GraphQLQuery)]
+#[graphql(
+	schema_path = "res/indexer-schema.json",
+	query_path = "res/indexer-queries.graphql"
+)]
+pub struct LatestBlock;
+
+#[derive(GraphQLQuery)]
+#[graphql(
+	schema_path = "res/indexer-schema.json",
+	query_path = "res/indexer-queries.graphql"
+)]
+pub struct BlockByNumber;
+
+#[derive(GraphQLQuery, Debug)]
+#[graphql(
+	schema_path = "res/indexer-schema.json",
+	query_path = "res/indexer-queries.graphql"
+)]
+pub struct GenesisHash;
+
+#[derive(GraphQLQuery, Debug)]
+#[graphql(
+	schema_path = "res/indexer-schema.json",
+	query_path = "res/indexer-queries.graphql"
+)]
+pub struct NamesByIndexes;
diff --git a/src/main.rs b/src/main.rs
index 98458a9e5e55994720c5012ec81cb9bba7a70b39..f6571baaf2746611be5f40814d282f865b620956 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,3 @@
-mod cache;
 mod commands;
 mod conf;
 mod data;