Skip to content
Snippets Groups Projects
collective.rs 3.33 KiB
use crate::*;

use anyhow::Result;

/// define technical committee subcommands
#[derive(Clone, Default, Debug, clap::Parser)]
pub enum Subcommand {
	#[default]
	/// List members of the technical committee
	Members,
	/// List proposals to the technical committee
	Proposals,
	/// Vote a proposal to the technical committee
	Vote {
		/// Proposal hash
		hash: Hash,
		/// Proposal index
		index: u32,
		/// Vote (0=against, 1=for)
		vote: u8,
	},
}

/// handle technical committee commands
pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliError> {
	let mut data = data.build_client().await?.build_indexer().await?;
	match command {
		Subcommand::Members => {
			data = data.build_client().await?;
			commands::collective::technical_committee_members(&data).await?
		}
		Subcommand::Proposals => {
			data = data.build_client().await?;
			commands::collective::technical_committee_proposals(data.client()).await?
		}
		Subcommand::Vote { hash, index, vote } => {
			data = data.build_client().await?;
			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(
				&data, hash, //Hash::from_str(&hash).expect("Invalid hash formatting"),
				index, vote,
			)
			.await?;
		}
	};

	Ok(())
}

/// list technical committee members
pub async fn technical_committee_members(data: &Data) -> Result<()> {
	let client = data.client();
	let indexer = data.indexer.clone();

	let parent_hash = client
		.storage()
		.at_latest()
		.await?
		.fetch(&runtime::storage().system().parent_hash())
		.await?
		.unwrap();

	for account_id in client
		.storage()
		.at(parent_hash)
		.fetch(&runtime::storage().technical_committee().members())
		.await?
		.unwrap_or_default()
	{
		println!(
			"{}",
			if let Some(indexer) = &indexer {
				indexer
					.username_by_pubkey(&account_id.to_string())
					.await
					.ok()
					.flatten()
			} else {
				client
					.storage()
					.at(parent_hash)
					.fetch(&runtime::storage().identity().identity_index_of(&account_id))
					.await
					.ok()
					.flatten()
					.map(|identity_id| format!("{identity_id}"))
			}
			.unwrap_or_else(|| account_id.to_string(),)
		);
	}

	Ok(())
}

/// list technical committee proposals
// 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()
		.at_latest()
		.await?
		.fetch(&runtime::storage().system().parent_hash())
		.await?
		.unwrap();

	let mut proposals_iter = client
		.storage()
		.at(parent_hash)
		.iter(runtime::storage().technical_committee().proposal_of_iter())
		.await?;
	while let Some(Ok((proposal_hash, proposal))) = proposals_iter.next().await {
		println!("{}", hex::encode(&proposal_hash[32..64]));
		println!("{proposal:#?}");
		println!();
	}

	Ok(())
}

/// submit vote to technical committee
pub async fn technical_committee_vote(
	data: &Data,
	proposal_hash: Hash,
	proposal_index: u32,
	vote: bool,
) -> Result<(), subxt::Error> {
	submit_call_and_look_event::<
		runtime::technical_committee::events::Voted,
		Payload<runtime::technical_committee::calls::types::Vote>,
	>(
		data,
		&runtime::tx()
			.technical_committee()
			.vote(proposal_hash, proposal_index, vote),
	)
	.await
}