Kaynağa Gözat

upgrade to clap 3.0 and move cli parser structs to cli dir

ghassmo 4 yıl önce
ebeveyn
işleme
92ed458518
9 değiştirilmiş dosya ile 351 ekleme ve 230 silme
  1. 57 6
      Cargo.lock
  2. 1 1
      Cargo.toml
  3. 9 16
      src/bin/cashierd.rs
  4. 10 23
      src/bin/darkfid.rs
  5. 95 148
      src/bin/drk.rs
  6. 7 12
      src/bin/gatewayd.rs
  7. 150 0
      src/cli/cli_parser.rs
  8. 3 0
      src/cli/mod.rs
  9. 19 24
      src/darkpulse/cli_option.rs

+ 57 - 6
Cargo.lock

@@ -890,11 +890,41 @@ dependencies = [
  "atty",
  "bitflags",
  "strsim 0.8.0",
- "textwrap",
+ "textwrap 0.11.0",
  "unicode-width",
  "vec_map",
 ]
 
+[[package]]
+name = "clap"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d17bf219fcd37199b9a29e00ba65dfb8cd5b2688b7297ec14ff829c40ac50ca9"
+dependencies = [
+ "atty",
+ "bitflags",
+ "clap_derive",
+ "indexmap",
+ "lazy_static",
+ "os_str_bytes",
+ "strsim 0.10.0",
+ "termcolor",
+ "textwrap 0.14.2",
+]
+
+[[package]]
+name = "clap_derive"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1b9752c030a14235a0bd5ef3ad60a1dcac8468c30921327fc8af36b20c790b9"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2 1.0.36",
+ "quote 1.0.14",
+ "syn 1.0.84",
+]
+
 [[package]]
 name = "cloudabi"
 version = "0.0.3"
@@ -1334,7 +1364,7 @@ dependencies = [
  "bs58",
  "bytes",
  "chrono",
- "clap",
+ "clap 3.0.0",
  "crossbeam-channel 0.5.1",
  "crypto_api_chachapoly",
  "dirs 4.0.0",
@@ -3071,6 +3101,15 @@ dependencies = [
  "vcpkg",
 ]
 
+[[package]]
+name = "os_str_bytes"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "ouroboros"
 version = "0.13.0"
@@ -4397,7 +4436,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b08f88740c713a8b44fc1391b202f7866539cffeec29cadd1a288e1e464990db"
 dependencies = [
  "chrono",
- "clap",
+ "clap 2.34.0",
  "rpassword",
  "solana-perf",
  "solana-remote-wallet",
@@ -4431,7 +4470,7 @@ dependencies = [
  "base64 0.13.0",
  "bincode",
  "bs58",
- "clap",
+ "clap 2.34.0",
  "indicatif",
  "jsonrpc-core",
  "log",
@@ -4488,7 +4527,7 @@ checksum = "6ecd178827887c60394ad7f0342a1e1e6e6114b9f066497326b5f855ea3718d4"
 dependencies = [
  "bincode",
  "byteorder",
- "clap",
+ "clap 2.34.0",
  "log",
  "serde",
  "serde_derive",
@@ -4577,7 +4616,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "92ae3b94d966346c0a5425f18350aaf17bc3e37252985f0f3f117e81cfd9d05f"
 dependencies = [
  "bincode",
- "clap",
+ "clap 2.34.0",
  "log",
  "nix",
  "rand 0.7.3",
@@ -5073,6 +5112,12 @@ version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
 
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
 [[package]]
 name = "subtle"
 version = "2.4.1"
@@ -5212,6 +5257,12 @@ dependencies = [
  "unicode-width",
 ]
 
+[[package]]
+name = "textwrap"
+version = "0.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
+
 [[package]]
 name = "thiserror"
 version = "1.0.30"

+ 1 - 1
Cargo.toml

@@ -60,7 +60,7 @@ smol = "1.2.5"
 
 # Utilities
 anyhow = "1.0.49"
-clap = "2.34.0"
+clap = { version = "3.0.0", features = ["derive"] }
 dirs = "4.0.0"
 failure = "0.1.8"
 lazy_static = "1.4.0"

+ 9 - 16
src/bin/cashierd.rs

@@ -3,7 +3,7 @@ use std::{path::PathBuf, str::FromStr};
 use async_executor::Executor;
 use async_std::sync::{Arc, Mutex};
 use async_trait::async_trait;
-use clap::clap_app;
+use clap::Parser;
 use easy_parallel::Parallel;
 use log::{debug, info, trace};
 use rand::rngs::OsRng;
@@ -13,7 +13,7 @@ use simplelog::{ColorChoice, LevelFilter, TermLogger, TerminalMode};
 use drk::{
     blockchain::{rocks::columns, Rocks, RocksColumn},
     circuit::{MintContract, SpendContract},
-    cli::{CashierdConfig, Config},
+    cli::{CashierdConfig, CliCashierd, Config},
     client::Client,
     crypto::{
         keypair::{PublicKey, SecretKey},
@@ -732,24 +732,17 @@ async fn start(
 
 #[async_std::main]
 async fn main() -> Result<()> {
-    let args = clap_app!(cashierd =>
-        (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
-        (@arg ADDRESS: -a --address "Get Cashier Public key")
-        (@arg verbose: -v --verbose "Increase verbosity")
-        (@arg trace: -t --trace "Show event trace")
-        (@arg refresh: -r --refresh "Refresh the wallet and slabstore")
-    )
-    .get_matches();
+    let args = CliCashierd::parse();
 
-    let config_path = if args.is_present("CONFIG") {
-        expand_path(args.value_of("CONFIG").unwrap())?
+    let config_path = if args.config.is_some() {
+        expand_path(&args.config.unwrap())?
     } else {
         join_config_path(&PathBuf::from("cashierd.toml"))?
     };
 
-    let loglevel = if args.is_present("verbose") {
+    let loglevel = if args.verbose {
         LevelFilter::Debug
-    } else if args.is_present("trace") {
+    } else if args.trace {
         LevelFilter::Trace
     } else {
         LevelFilter::Info
@@ -764,7 +757,7 @@ async fn main() -> Result<()> {
 
     let config: CashierdConfig = Config::<CashierdConfig>::load(config_path)?;
 
-    if args.is_present("refresh") {
+    if args.refresh {
         info!(target: "CASHIER DAEMON", "Refresh the wallet and the database");
         let client_wallet_path =
             format!("sqlite://{}", expand_path(&config.client_wallet_path)?.to_str().unwrap());
@@ -789,7 +782,7 @@ async fn main() -> Result<()> {
         return Ok(())
     }
 
-    let get_address_flag = args.is_present("ADDRESS");
+    let get_address_flag = args.address;
 
     let ex = Arc::new(Executor::new());
     let (signal, shutdown) = async_channel::unbounded::<()>();

+ 10 - 23
src/bin/darkfid.rs

@@ -3,7 +3,7 @@ use std::{collections::HashMap, path::PathBuf, str::FromStr};
 use async_executor::Executor;
 use async_std::sync::{Arc, Mutex};
 use async_trait::async_trait;
-use clap::clap_app;
+use clap::Parser;
 use easy_parallel::Parallel;
 use log::{debug, info};
 use num_bigint::BigUint;
@@ -14,7 +14,7 @@ use url::Url;
 use drk::{
     blockchain::{rocks::columns, Rocks, RocksColumn},
     circuit::{MintContract, SpendContract},
-    cli::{Config, DarkfidConfig},
+    cli::{CliDarkfid, Config, DarkfidConfig},
     client::Client,
     crypto::{keypair::PublicKey, proof::VerifyingKey},
     rpc::{
@@ -536,7 +536,7 @@ impl Darkfid {
 
 async fn start(
     executor: Arc<Executor<'_>>,
-    local_cashier: Option<&str>,
+    local_cashier: Option<String>,
     config: &DarkfidConfig,
 ) -> Result<()> {
     let wallet_path = format!("sqlite://{}", expand_path(&config.wallet_path)?.to_str().unwrap());
@@ -618,24 +618,17 @@ async fn start(
 
 #[async_std::main]
 async fn main() -> Result<()> {
-    let args = clap_app!(darkfid =>
-        (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
-        (@arg verbose: -v --verbose "Increase verbosity")
-        (@arg trace: -t --trace "Show event trace")
-        (@arg refresh: -r --refresh "Refresh the wallet and slabstore")
-        (@arg cashier: --cashier +takes_value "Local cashier public key")
-    )
-    .get_matches();
+    let args = CliDarkfid::parse();
 
-    let config_path = if args.is_present("CONFIG") {
-        expand_path(args.value_of("CONFIG").unwrap())?
+    let config_path = if args.config.is_some() {
+        expand_path(&args.config.unwrap())?
     } else {
         join_config_path(&PathBuf::from("darkfid.toml"))?
     };
 
-    let loglevel = if args.is_present("verbose") {
+    let loglevel = if args.verbose {
         LevelFilter::Debug
-    } else if args.is_present("trace") {
+    } else if args.trace {
         LevelFilter::Trace
     } else {
         LevelFilter::Info
@@ -650,7 +643,7 @@ async fn main() -> Result<()> {
 
     let config: DarkfidConfig = Config::<DarkfidConfig>::load(config_path)?;
 
-    if args.is_present("refresh") {
+    if args.refresh {
         info!(target: "DARKFI DAEMON", "Refresh the wallet and the database");
         let wallet_path =
             format!("sqlite://{}", expand_path(&config.wallet_path)?.to_str().unwrap());
@@ -668,12 +661,6 @@ async fn main() -> Result<()> {
         return Ok(())
     }
 
-    let mut local_cashier: Option<&str> = None;
-
-    if args.is_present("cashier") {
-        local_cashier = Some(args.value_of("cashier").unwrap())
-    }
-
     let ex = Arc::new(Executor::new());
     let (signal, shutdown) = async_channel::unbounded::<()>();
 
@@ -687,7 +674,7 @@ async fn main() -> Result<()> {
         // Run the main future on the current thread.
         .finish(|| {
             smol::future::block_on(async move {
-                start(ex2, local_cashier, &config).await?;
+                start(ex2, args.cashier, &config).await?;
                 drop(signal);
                 Ok::<(), drk::Error>(())
             })

+ 95 - 148
src/bin/drk.rs

@@ -2,14 +2,14 @@ use std::{path::PathBuf, str::FromStr};
 
 #[macro_use]
 extern crate prettytable;
-use clap::{clap_app, ArgMatches};
+use clap::Parser;
 use log::debug;
 use prettytable::{format, Table};
 use serde_json::{json, Value};
 use simplelog::{ColorChoice, LevelFilter, TermLogger, TerminalMode};
 
 use drk::{
-    cli::{Config, DrkConfig},
+    cli::{CliDrk, CliDrkSubCommands, Config, DrkConfig},
     rpc::{jsonrpc, jsonrpc::JsonResult},
     util::{join_config_path, path::expand_path, NetworkName},
     Error, Result,
@@ -156,126 +156,120 @@ impl Drk {
     }
 }
 
-async fn start(config: &DrkConfig, options: ArgMatches<'_>) -> Result<()> {
+async fn start(config: &DrkConfig, options: CliDrk) -> Result<()> {
     let client = Drk::new(config.darkfid_rpc_url.clone());
 
-    if options.is_present("hello") {
-        let reply = client.say_hello().await?;
-        println!("Server replied: {}", &reply.to_string());
-        return Ok(())
-    }
-
-    if let Some(matches) = options.subcommand_matches("wallet") {
-        if matches.is_present("create") {
-            let reply = client.create_wallet().await?;
-            if reply.as_bool().unwrap() {
-                println!("Wallet created successfully.")
-            } else {
-                println!("Server replied: {}", &reply.to_string());
-            }
+    match options.command {
+        Some(CliDrkSubCommands::Hello {}) => {
+            let reply = client.say_hello().await?;
+            println!("Server replied: {}", &reply.to_string());
             return Ok(())
         }
-
-        if matches.is_present("keygen") {
-            let reply = client.key_gen().await?;
-            if reply.as_bool().unwrap() {
-                println!("Key generation successful.")
-            } else {
-                println!("Server replied: {}", &reply.to_string());
-            }
-            return Ok(())
-        }
-
-        if matches.is_present("address") {
-            let reply = client.get_key().await?;
-            println!("Wallet address: {}", &reply.to_string());
+        Some(CliDrkSubCommands::Features {}) => {
+            let reply = client.features().await?;
+            println!("Features: {}", &reply.to_string());
             return Ok(())
         }
+        Some(CliDrkSubCommands::Wallet { create, keygen, address, balances }) => {
+            if create {
+                let reply = client.create_wallet().await?;
+                if reply.as_bool().unwrap() {
+                    println!("Wallet created successfully.")
+                } else {
+                    println!("Server replied: {}", &reply.to_string());
+                }
+                return Ok(())
+            }
 
-        if matches.is_present("balances") {
-            let reply = client.get_balances().await?;
+            if keygen {
+                let reply = client.key_gen().await?;
+                if reply.as_bool().unwrap() {
+                    println!("Key generation successful.")
+                } else {
+                    println!("Server replied: {}", &reply.to_string());
+                }
+                return Ok(())
+            }
 
-            if reply.as_object().is_some() && !reply.as_object().unwrap().is_empty() {
-                let mut table = Table::new();
-                table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
-                table.set_titles(row!["token", "amount", "network"]);
+            if address {
+                let reply = client.get_key().await?;
+                println!("Wallet address: {}", &reply.to_string());
+                return Ok(())
+            }
 
-                for (tkn, data) in reply.as_object().unwrap() {
-                    table.add_row(row![tkn, data[0].as_str().unwrap(), data[1].as_str().unwrap()]);
+            if balances {
+                let reply = client.get_balances().await?;
+
+                if reply.as_object().is_some() && !reply.as_object().unwrap().is_empty() {
+                    let mut table = Table::new();
+                    table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
+                    table.set_titles(row!["token", "amount", "network"]);
+
+                    for (tkn, data) in reply.as_object().unwrap() {
+                        table.add_row(row![
+                            tkn,
+                            data[0].as_str().unwrap(),
+                            data[1].as_str().unwrap()
+                        ]);
+                    }
+
+                    table.printstd();
+                } else {
+                    println!("Balances: {}", "0".to_string());
                 }
 
-                table.printstd();
-            } else {
-                println!("Balances: {}", "0".to_string());
+                return Ok(())
             }
-
-            return Ok(())
         }
-    }
-
-    if let Some(matches) = options.subcommand_matches("id") {
-        let token = matches.value_of("TOKEN").unwrap();
-        let network = matches.value_of("network").unwrap().to_lowercase();
-
-        client.check_network(&NetworkName::from_str(&network)?).await?;
+        Some(CliDrkSubCommands::Id { network, token }) => {
+            let network = network.to_lowercase();
+            client.check_network(&NetworkName::from_str(&network)?).await?;
 
-        let reply = client.get_token_id(&network, token).await?;
+            let reply = client.get_token_id(&network, &token).await?;
 
-        println!("Token ID: {}", &reply.to_string());
-        return Ok(())
-    }
-
-    if options.is_present("features") {
-        let reply = client.features().await?;
-        println!("Features: {}", &reply.to_string());
-        return Ok(())
-    }
-
-    if let Some(matches) = options.subcommand_matches("deposit") {
-        let network = matches.value_of("network").unwrap().to_lowercase();
-        let token_sym = matches.value_of("TOKENSYM").unwrap();
-
-        client.check_network(&NetworkName::from_str(&network)?).await?;
+            println!("Token ID: {}", &reply.to_string());
+            return Ok(())
+        }
+        Some(CliDrkSubCommands::Deposit { network, token_sym }) => {
+            let network = network.to_lowercase();
 
-        let reply = client.deposit(&network, token_sym).await?;
+            client.check_network(&NetworkName::from_str(&network)?).await?;
 
-        println!("Deposit your coins to the following address: {}", &reply.to_string());
+            let reply = client.deposit(&network, &token_sym).await?;
 
-        return Ok(())
-    }
+            println!("Deposit your coins to the following address: {}", &reply.to_string());
 
-    if let Some(matches) = options.subcommand_matches("withdraw") {
-        let network = matches.value_of("network").unwrap().to_lowercase();
-        let token_sym = matches.value_of("TOKENSYM").unwrap();
-        let address = matches.value_of("ADDRESS").unwrap();
-        let amount = matches.value_of("AMOUNT").unwrap();
+            return Ok(())
+        }
+        Some(CliDrkSubCommands::Transfer { network, token_sym, address, amount }) => {
+            let network = network.to_lowercase();
 
-        client.check_network(&NetworkName::from_str(&network)?).await?;
+            client.check_network(&NetworkName::from_str(&network)?).await?;
 
-        let reply = client.withdraw(&network, token_sym, address, amount).await?;
+            client.transfer(&network, &token_sym, &address, &amount.to_string()).await?;
 
-        println!("{}", &reply.to_string());
+            println!(
+                "{} {} Transfered successfully",
+                amount.to_string(),
+                token_sym.to_string().to_uppercase(),
+            );
 
-        return Ok(())
-    }
+            return Ok(())
+        }
 
-    if let Some(matches) = options.subcommand_matches("transfer") {
-        let network = matches.value_of("network").unwrap().to_lowercase();
-        let token_sym = matches.value_of("TOKENSYM").unwrap();
-        let address = matches.value_of("ADDRESS").unwrap();
-        let amount = matches.value_of("AMOUNT").unwrap();
+        Some(CliDrkSubCommands::Withdraw { network, token_sym, address, amount }) => {
+            let network = network.to_lowercase();
 
-        client.check_network(&NetworkName::from_str(&network)?).await?;
+            client.check_network(&NetworkName::from_str(&network)?).await?;
 
-        client.transfer(&network, token_sym, address, amount).await?;
+            let reply =
+                client.withdraw(&network, &token_sym, &address, &amount.to_string()).await?;
 
-        println!(
-            "{} {} Transfered successfully",
-            amount.to_string(),
-            token_sym.to_string().to_uppercase(),
-        );
+            println!("{}", &reply.to_string());
 
-        return Ok(())
+            return Ok(())
+        }
+        None => {}
     }
 
     println!("Please run 'drk help' to see usage.");
@@ -284,65 +278,17 @@ async fn start(config: &DrkConfig, options: ArgMatches<'_>) -> Result<()> {
 
 #[async_std::main]
 async fn main() -> Result<()> {
-    let args = clap_app!(drk =>
-    (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
-    (@arg verbose: -v --verbose "Increase verbosity")
-    (@arg trace: -t --trace "Show event trace")
-    (@subcommand hello =>
-     (about: "Say hello to the RPC")
-    )
-    (@subcommand wallet =>
-     (about: "Wallet operations")
-     (@arg create: --create "Initialize a new wallet")
-     (@arg keygen: --keygen "Generate wallet keypair")
-     (@arg address: --address "Get wallet address")
-     (@arg balances: --balances "Get wallet balances")
-    )
-    (@subcommand id =>
-     (about: "Get hexidecimal ID for token symbol")
-     (@arg network: +required +takes_value --network
-      "Which network to use (bitcoin/solana/...)")
-     (@arg TOKEN: +required
-      "Which token to query (btc/sol/usdc/...)")
-    )
-    (@subcommand features =>
-     (about: "Show what features the cashier supports")
-    )
-    (@subcommand deposit =>
-     (about: "Deposit clear tokens for Dark tokens")
-     (@arg network: +required +takes_value --network
-      "Which network to use (bitcoin/solana/...)")
-     (@arg TOKENSYM: +required
-      "Which token symbol to deposit (btc/sol/usdc...)")
-    )
-    (@subcommand transfer =>
-     (about: "Transfer Dark tokens to address")
-     (@arg network: +required +takes_value --network
-      "Which network to use (bitcoin/solana/...)")
-     (@arg TOKENSYM: +required "Desired token (btc/sol/usdc...)")
-     (@arg ADDRESS: +required "Recipient address")
-     (@arg AMOUNT: +required "Amount to send")
-    )
-    (@subcommand withdraw =>
-     (about: "Withdraw Dark tokens for clear tokens")
-     (@arg network: +required +takes_value --network
-      "Which network to use (bitcoin/solana/...)")
-     (@arg TOKENSYM: +required "Which token to receive (btc/sol/usdc...)")
-     (@arg ADDRESS: +required "Recipient address")
-     (@arg AMOUNT: +required "Amount to withdraw")
-    )
-    )
-    .get_matches();
-
-    let config_path = if args.is_present("CONFIG") {
-        expand_path(args.value_of("CONFIG").unwrap())?
+    let args = CliDrk::parse();
+
+    let config_path = if args.config.is_some() {
+        expand_path(&args.config.clone().unwrap())?
     } else {
         join_config_path(&PathBuf::from("drk.toml"))?
     };
 
-    let loglevel = if args.is_present("verbose") {
+    let loglevel = if args.verbose {
         LevelFilter::Debug
-    } else if args.is_present("trace") {
+    } else if args.trace {
         LevelFilter::Trace
     } else {
         LevelFilter::Info
@@ -354,6 +300,7 @@ async fn main() -> Result<()> {
         TerminalMode::Mixed,
         ColorChoice::Auto,
     )?;
+
     let config = Config::<DrkConfig>::load(config_path)?;
 
     start(&config, args).await

+ 7 - 12
src/bin/gatewayd.rs

@@ -1,14 +1,14 @@
 use std::{path::PathBuf, sync::Arc};
 
 use async_executor::Executor;
-use clap::clap_app;
+use clap::Parser;
 use easy_parallel::Parallel;
 use log::debug;
 use simplelog::{LevelFilter, SimpleLogger};
 
 use drk::{
     blockchain::{rocks::columns, Rocks, RocksColumn},
-    cli::{Config, GatewaydConfig},
+    cli::{CliGatewayd, Config, GatewaydConfig},
     service::GatewayService,
     util::{expand_path, join_config_path},
     Result,
@@ -29,22 +29,17 @@ async fn start(executor: Arc<Executor<'_>>, config: &GatewaydConfig) -> Result<(
 
 #[async_std::main]
 async fn main() -> Result<()> {
-    let args = clap_app!(gatewayd =>
-        (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
-        (@arg verbose: -v --verbose "Increase verbosity")
-        (@arg trace: -t --trace "Show event trace")
-    )
-    .get_matches();
+    let args = CliGatewayd::parse();
 
-    let config_path = if args.is_present("CONFIG") {
-        expand_path(args.value_of("CONFIG").unwrap())?
+    let config_path = if args.config.is_some() {
+        expand_path(&args.config.unwrap())?
     } else {
         join_config_path(&PathBuf::from("gatewayd.toml"))?
     };
 
-    let loglevel = if args.is_present("verbose") {
+    let loglevel = if args.verbose {
         LevelFilter::Debug
-    } else if args.is_present("trace") {
+    } else if args.trace {
         LevelFilter::Trace
     } else {
         LevelFilter::Info

+ 150 - 0
src/cli/cli_parser.rs

@@ -0,0 +1,150 @@
+use clap::{AppSettings, Parser, Subcommand};
+
+#[derive(Subcommand)]
+pub enum CliDrkSubCommands {
+    /// Say hello to the RPC
+    Hello {},
+    /// Show what features the cashier supports
+    Features {},
+    /// Wallet operations
+    Wallet {
+        /// Initialize a new wallet
+        #[clap(long)]
+        create: bool,
+        /// Generate wallet keypair
+        #[clap(long)]
+        keygen: bool,
+        /// Get wallet address
+        #[clap(long)]
+        address: bool,
+        /// Get wallet balances
+        #[clap(long)]
+        balances: bool,
+    },
+    /// Get hexidecimal ID for token symbol
+    Id {
+        /// Which network to use (bitcoin/solana/...)
+        #[clap(long)]
+        network: String,
+        /// Which token to query (btc/sol/usdc/...)
+        #[clap(parse(try_from_str))]
+        token: String,
+    },
+    /// Withdraw Dark tokens for clear tokens
+    Withdraw {
+        /// Which network to use (bitcoin/solana/...)
+        #[clap(long)]
+        network: String,
+        /// Which token to receive (btc/sol/usdc/...)
+        #[clap(parse(try_from_str))]
+        token_sym: String,
+        /// Recipient address
+        #[clap(parse(try_from_str))]
+        address: String,
+        /// Amount to withdraw
+        #[clap(parse(try_from_str))]
+        amount: u64,
+    },
+    /// Transfer Dark tokens to address
+    Transfer {
+        /// Which network to use (bitcoin/solana/...)
+        #[clap(long)]
+        network: String,
+        /// Which token to transfer (btc/sol/usdc/...)
+        #[clap(parse(try_from_str))]
+        token_sym: String,
+        /// Recipient address
+        #[clap(parse(try_from_str))]
+        address: String,
+        /// Amount to transfer
+        #[clap(parse(try_from_str))]
+        amount: u64,
+    },
+    /// Deposit clear tokens for Dark tokens
+    Deposit {
+        /// Which network to use (bitcoin/solana/...)
+        #[clap(long)]
+        network: String,
+        /// Which token to deposit (btc/sol/usdc/...)
+        #[clap(parse(try_from_str))]
+        token_sym: String,
+    },
+}
+
+/// Drk cli
+#[derive(Parser)]
+#[clap(name = "drk")]
+#[clap(author, version, about)]
+#[clap(global_setting(AppSettings::PropagateVersion))]
+#[clap(global_setting(AppSettings::UseLongFormatForHelpSubcommand))]
+#[clap(setting(AppSettings::SubcommandRequiredElseHelp))]
+pub struct CliDrk {
+    /// Sets a custom config file
+    #[clap(short, long)]
+    pub config: Option<String>,
+    /// Increase verbosity
+    #[clap(short, long)]
+    pub verbose: bool,
+    /// Show event trace
+    #[clap(short, long)]
+    pub trace: bool,
+    #[clap(subcommand)]
+    pub command: Option<CliDrkSubCommands>,
+}
+
+/// Gatewayd cli
+#[derive(Parser)]
+#[clap(name = "gatewayd")]
+pub struct CliGatewayd {
+    /// Sets a custom config file
+    #[clap(short, long)]
+    pub config: Option<String>,
+    /// Increase verbosity
+    #[clap(short, long)]
+    pub verbose: bool,
+    /// Show event trace
+    #[clap(short, long)]
+    pub trace: bool,
+}
+
+/// Darkfid cli
+#[derive(Parser)]
+#[clap(name = "darkfid")]
+pub struct CliDarkfid {
+    /// Sets a custom config file
+    #[clap(short, long)]
+    pub config: Option<String>,
+    /// Local cashier public key
+    #[clap(long)]
+    pub cashier: Option<String>,
+    /// Increase verbosity
+    #[clap(short, long)]
+    pub verbose: bool,
+    /// Show event trace
+    #[clap(short, long)]
+    pub trace: bool,
+    /// Refresh the wallet and slabstore
+    #[clap(short, long)]
+    pub refresh: bool,
+}
+
+/// Cashierd cli
+#[derive(Parser)]
+#[clap(name = "cashierd")]
+pub struct CliCashierd {
+    /// Sets a custom config file
+    #[clap(short, long)]
+    pub config: Option<String>,
+    /// Get Cashier Public key
+    #[clap(short, long)]
+    pub address: bool,
+    /// Increase verbosity
+    #[clap(short, long)]
+    pub verbose: bool,
+    /// Show event trace
+    #[clap(short, long)]
+    pub trace: bool,
+    /// Refresh the wallet and slabstore
+    #[clap(short, long)]
+    pub refresh: bool,
+}

+ 3 - 0
src/cli/mod.rs

@@ -1,2 +1,5 @@
 pub mod cli_config;
+pub mod cli_parser;
+
 pub use cli_config::{CashierdConfig, Config, DarkfidConfig, DrkConfig, GatewaydConfig};
+pub use cli_parser::{CliCashierd, CliDarkfid, CliDrk, CliDrkSubCommands, CliGatewayd};

+ 19 - 24
src/darkpulse/cli_option.rs

@@ -1,6 +1,6 @@
 use std::net::SocketAddr;
 
-use clap::{App, Arg, SubCommand};
+use clap::{App, Arg};
 
 use super::Channel;
 use crate::{net::Settings, Result};
@@ -21,71 +21,66 @@ impl CliOption {
             .author("Dark Renaissance Technologies")
             .about("An anonymous p2p chat application")
             .arg(
-                Arg::with_name("accept")
-                    .short("a")
+                Arg::new("accept")
+                    .short('a')
                     .value_name("ADDRESSES")
                     .help("accept address")
                     .long("accept")
                     .required(true),
             )
-            .arg(Arg::with_name("slots").value_name("SLOTS").long("slots").help("Connection slots"))
+            .arg(Arg::new("slots").value_name("SLOTS").long("slots").help("Connection slots"))
+            .arg(Arg::new("verbose").takes_value(false).long("verbose").help("increase verbosity"))
             .arg(
-                Arg::with_name("verbose")
-                    .takes_value(false)
-                    .long("verbose")
-                    .help("increase verbosity"),
-            )
-            .arg(
-                Arg::with_name("connects")
+                Arg::new("connects")
                     .value_name("MANUAL_CONNECTS")
-                    .multiple(true)
+                    .multiple_occurrences(true)
                     .takes_value(true)
-                    .short("c")
+                    .short('c')
                     .long("connects")
                     .help("Manual connections"),
             )
             .arg(
-                Arg::with_name("seed")
+                Arg::new("seed")
                     .value_name("ADDRESSES")
-                    .multiple(true)
+                    .multiple_occurrences(true)
                     .takes_value(true)
-                    .short("s")
+                    .short('s')
                     .long("seed")
                     .help("Connect to the seed node"),
             )
             .arg(
-                Arg::with_name("log")
+                Arg::new("log")
                     .value_name("LOG_PATH")
                     .takes_value(true)
                     .long("log")
                     .help("Log file path"),
             )
             .arg(
-                Arg::with_name("username")
+                Arg::new("username")
                     .value_name("USERNAME")
-                    .short("u")
+                    .short('u')
                     .long("username")
                     .help("node's username"),
             )
             .arg(
-                Arg::with_name("channel")
+                Arg::new("channel")
                     .value_name("CHANNEL")
-                    .short("h")
+                    .short('h')
                     .long("channel")
                     .help("switch to one of available channels"),
             )
             .subcommand(
-                SubCommand::with_name("newchannel")
+                App::new("newchannel")
                     .about("add new channel")
                     .arg(
-                        Arg::with_name("name")
+                        Arg::new("name")
                             .long("channelname")
                             .required(true)
                             .value_name("CHANNELNAME")
                             .help("name for the new channel"),
                     )
                     .arg(
-                        Arg::with_name("address")
+                        Arg::new("address")
                             .long("channeladdress")
                             .required(true)
                             .value_name("CHANNELADDRESS")