Skip to content
Snippets Groups Projects
utils.rs 3.98 KiB
Newer Older
use crate::*;

/// track progress of transaction on the network
/// until it is in block with success or failure
pub async fn track_progress(
	mut progress: TxProgress,
) -> Result<ExtrinsicEvents<Runtime>, subxt::Error> {
	loop {
		if let Some(status) = progress.next().await {
			match status? {
				TxStatus::Validated => {
					println!("transaction submitted to the network, waiting 6 seconds...");
				}
				TxStatus::InBestBlock(in_block) => break in_block,
				TxStatus::Invalid { message } => {
					println!("Invalid {message}");
				}
				_ => continue,
			}
		}
	}
	.wait_for_success()
	.await
}

/// generic extrinsic submitter
pub async fn submit_call_and_look_event<
	E: std::fmt::Debug + StaticEvent + DisplayEvent,
Hugo Trentesaux's avatar
Hugo Trentesaux committed
	TxPayload: Payload,
	data: &Data,
Hugo Trentesaux's avatar
Hugo Trentesaux committed
	payload: &TxPayload,
) -> Result<(), subxt::Error> {
	// submit call
	let progress = submit_call(data, payload).await?;
	// if no wait, return immediately
	if data.args.no_wait {
		return Ok(());
	}
	// collect events
	let events = track_progress(progress).await?;
	// print given event if there
	look_event::<E>(data, &events)
Hugo Trentesaux's avatar
Hugo Trentesaux committed
pub async fn submit_call<TxPayload: Payload>(
Hugo Trentesaux's avatar
Hugo Trentesaux committed
	payload: &TxPayload,
) -> Result<TxProgress, subxt::Error> {
	// get account nonce manually to be based on last block and not last finalized
	let nonce = data
		.legacy_rpc_methods() // see issue #32
		.await
		.system_account_next_index(&data.address())
		.await?;

	// sign and submit
		// sr25519 key pair
		KeyPair::Sr25519(keypair) => data.client().tx().create_signed_offline(
			payload,
			&PairSigner::<Runtime, sp_core::sr25519::Pair>::new(keypair),
			DefaultExtrinsicParamsBuilder::new().nonce(nonce).build(),
		KeyPair::Ed25519(keypair) => data.client().tx().create_signed_offline(
			payload,
			&PairSigner::<Runtime, sp_core::ed25519::Pair>::new(keypair),
			DefaultExtrinsicParamsBuilder::new().nonce(nonce).build(),
		),
/// look event
pub fn look_event<E: std::fmt::Debug + StaticEvent + DisplayEvent>(
	data: &Data,
	events: &ExtrinsicEvents<Runtime>,
) -> Result<(), subxt::Error> {
	if let Some(e) = events.find_first::<E>()? {
		println!("{}", e.display(data));
	} else {
		// print nothing, this could happen for
		// - new cert vs renew cert
		// - new smith cert and smith "promotion"
		// println!("(no event of type {})", std::any::type_name::<E>())
/// custom error type intended to provide more convenient error message to user
#[derive(Debug)]
pub enum GcliError {
	/// error coming from subxt
	Subxt(subxt::Error),
	/// error coming from duniter
	Duniter(String),
	/// error coming from indexer
	Indexer(String),
	/// error coming from database
	#[allow(dead_code)]
	DatabaseError(DbErr),
	/// logic error (illegal operation or security)
	Logic(String),
	/// input error
	Input(String),
	/// error coming from anyhow (to be removed)
	Anyhow(anyhow::Error),
	/// error coming from io
	IoError(std::io::Error),
}
impl std::fmt::Display for GcliError {
	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
		match self {
			// prettier runtime error
			GcliError::Subxt(subxt::Error::Runtime(e)) => {
				write!(f, "{e}")
			}
			// debug log for detailed error
			_ => write!(f, "{:?}", self),
		}
	}
}
impl std::error::Error for GcliError {}
impl From<subxt::Error> for GcliError {
	fn from(e: subxt::Error) -> GcliError {
		GcliError::Subxt(e)
	}
}
impl From<anyhow::Error> for GcliError {
	fn from(e: anyhow::Error) -> GcliError {
		GcliError::Anyhow(e)
	}
}
impl From<confy::ConfyError> for GcliError {
	fn from(e: confy::ConfyError) -> GcliError {
		GcliError::Anyhow(e.into())
	}
}
impl From<std::io::Error> for GcliError {
	fn from(error: std::io::Error) -> Self {
		GcliError::IoError(error)
	}
}
impl From<sea_orm::DbErr> for GcliError {
	fn from(error: sea_orm::DbErr) -> Self {
		GcliError::DatabaseError(error)
	}
}