Skip to content
Snippets Groups Projects
Select Git revision
  • 4010a9e40db1b3beeebb06151fdf3c008496d4a3
  • master default protected
  • json-output
  • nostr
  • 48-error-base-58-requirement-is-violated
  • no-rename
  • hugo/tx-comments
  • poka/dev
  • hugo/dev
  • tuxmain/mail
  • 0.4.3-RC2
  • 0.4.3-RC1
  • 0.4.2
  • 0.4.1
  • 0.4.0
  • 0.3.0
  • 0.2.17
  • 0.2.16
  • 0.2.15
  • 0.2.14
  • 0.2.13
  • 0.2.12
  • 0.2.10
  • 0.2.9
  • 0.2.8
  • 0.2.7
  • 0.2.6
  • 0.2.5
  • 0.2.4
  • 0.2.3
30 results

utils.rs

Blame
  • utils.rs 3.98 KiB
    use crate::*;
    use sea_orm::DbErr;
    
    /// 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,
    	TxPayload: Payload,
    >(
    	data: &Data,
    	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)
    }
    
    /// submit call
    pub async fn submit_call<TxPayload: Payload>(
    	data: &Data,
    	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
    	match data.keypair().await {
    		// 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(),
    		),
    	}?
    	.submit_and_watch()
    	.await
    }
    
    /// 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>())
    	}
    	Ok(())
    }
    
    /// 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
    	#[allow(dead_code)]
    	Duniter(String),
    	/// error coming from indexer
    	#[allow(dead_code)]
    	Indexer(String),
    	/// error coming from database
    	#[allow(dead_code)]
    	DatabaseError(DbErr),
    	/// logic error (illegal operation or security)
    	#[allow(dead_code)]
    	Logic(String),
    	/// input error
    	#[allow(dead_code)]
    	Input(String),
    	/// error coming from anyhow (to be removed)
    	#[allow(dead_code)]
    	Anyhow(anyhow::Error),
    	/// error coming from io
    	#[allow(dead_code)]
    	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)
    	}
    }