mod commands; mod conf; mod data; mod database; mod display; mod entities; mod indexer; mod inputs; mod keys; mod runtime_config; mod utils; use anyhow::anyhow; use clap::builder::OsStr; use clap::Parser; use codec::Encode; use colored::Colorize; use data::*; use display::DisplayEvent; use keys::*; use runtime_config::*; use serde::{Deserialize, Serialize}; use std::str::FromStr; use subxt::{ blocks::ExtrinsicEvents, config::DefaultExtrinsicParamsBuilder, events::StaticEvent, ext::sp_core::{sr25519, Pair as _}, tx::{DefaultPayload, PairSigner, Payload, TxStatus}, }; use utils::*; // alias pub type StaticPayload<Calldata> = DefaultPayload<Calldata>; /// 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, /// Overwrite indexer endpoint #[clap(short, long, conflicts_with_all=["no_indexer","network"])] indexer: Option<String>, /// Do not use indexer #[clap(long)] no_indexer: bool, /// Secret key or BIP39 mnemonic (only used when secret format is compatible) /// (eventually followed by derivation path) #[clap(short, long)] secret: Option<String>, /// Secret key format (seed, substrate, g1v1) #[clap(short = 'S', long)] secret_format: Option<SecretFormat>, /// SS58 Address #[clap(short, conflicts_with = "name")] address: Option<AccountId>, /// Name of an SS58 Address in the vault #[clap(short = 'v')] name: Option<String>, /// Overwrite duniter websocket RPC endpoint #[clap(short, long, conflicts_with = "network")] url: Option<String>, /// Target network (local, gdev, gtest...) #[clap(short, long)] network: Option<String>, /// prevent waiting for extrinsic completion #[clap(long)] no_wait: bool, /// Output format (human, json, ...) #[clap(short = 'o', long, default_value = OutputFormat::Human)] output_format: OutputFormat, } // TODO derive the fromstr implementation /// secret format #[derive(Clone, Copy, Debug, Eq, PartialEq, Default)] enum OutputFormat { /// Human #[default] Human, /// JSON Json, } impl FromStr for OutputFormat { type Err = std::io::Error; fn from_str(s: &str) -> std::io::Result<Self> { match s { "human" => Ok(OutputFormat::Human), "json" => Ok(OutputFormat::Json), _ => Err(std::io::Error::from(std::io::ErrorKind::InvalidInput)), } } } impl From<OutputFormat> for &'static str { fn from(val: OutputFormat) -> &'static str { match val { OutputFormat::Human => "human", OutputFormat::Json => "json", } } } impl From<OutputFormat> for OsStr { fn from(val: OutputFormat) -> OsStr { OsStr::from(Into::<&str>::into(val)) } } /// define subcommands #[derive(Clone, Debug, clap::Subcommand, Default)] pub enum Subcommand { /// Nothing #[default] #[clap(hide = true)] Nothing, /// Account (balance, transfer...) #[clap(subcommand)] Account(commands::account::Subcommand), /// Identity (get, create, confirm, revoke...) #[clap(subcommand)] Identity(commands::identity::Subcommand), /// Smith (certify, go-online, go-offline...) #[clap(subcommand)] Smith(commands::smith::Subcommand), /// Sudo (set key, sudo calls...) #[clap(hide = true)] #[clap(subcommand)] Sudo(commands::sudo::Subcommand), /// Tech (list members, proposals, vote...) #[clap(subcommand)] Tech(commands::collective::Subcommand), /// Universal Dividend (claim...) #[clap(subcommand)] Ud(commands::ud::Subcommand), /// Oneshot account (balance, create, consume...) #[clap(subcommand)] Oneshot(commands::oneshot::Subcommand), /// Blockchain (current block, runtime info...) #[clap(subcommand)] Blockchain(commands::blockchain::Subcommand), /// Indexer (check, latest block) #[clap(subcommand)] Indexer(indexer::Subcommand), /// Config (show, save...) #[clap(subcommand)] Config(conf::Subcommand), /// Key management (import, generate, list...) #[clap(subcommand)] Vault(commands::vault::Subcommand), /// Cesium #[clap(subcommand, hide = true)] Cesium(commands::cesium::Subcommand), /// Publish a new git tag with actual version #[clap(hide = true)] Publish, } /// main function #[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), GcliError> { // init logger env_logger::init(); // parse argument and initialize data let data = Data::new(Args::parse()).await?; // match subcommands let result = match data.args.subcommand.clone() { Subcommand::Nothing => Ok(()), Subcommand::Account(subcommand) => { commands::account::handle_command(data, subcommand).await } Subcommand::Identity(subcommand) => { commands::identity::handle_command(data, subcommand).await } Subcommand::Smith(subcommand) => commands::smith::handle_command(data, subcommand).await, Subcommand::Sudo(subcommand) => commands::sudo::handle_command(data, subcommand).await, Subcommand::Tech(subcommand) => { commands::collective::handle_command(data, subcommand).await } Subcommand::Ud(subcommand) => commands::ud::handle_command(data, subcommand).await, Subcommand::Oneshot(subcommand) => { commands::oneshot::handle_command(data, subcommand).await } Subcommand::Blockchain(subcommand) => { commands::blockchain::handle_command(data, subcommand).await } Subcommand::Indexer(subcommand) => indexer::handle_command(data, subcommand).await, Subcommand::Config(subcommand) => conf::handle_command(data, subcommand).await, Subcommand::Vault(subcommand) => commands::vault::handle_command(data, subcommand).await, Subcommand::Cesium(subcommand) => commands::cesium::handle_command(data, subcommand).await, Subcommand::Publish => commands::publish::handle_command().await, }; if let Err(ref e) = result { println!("{}", e.to_string().red()) } // still return result for detailed error message // println!(); // result Ok(()) }