From fecd24a35a721c75be71da6e10a0d7b80bfa5346 Mon Sep 17 00:00:00 2001
From: tuxmain <tuxmain@zettascript.org>
Date: Thu, 1 Sep 2022 12:07:58 +0200
Subject: [PATCH] feat: optional secret

---
 README.md   | 10 ++++-----
 src/main.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 57 insertions(+), 13 deletions(-)

diff --git a/README.md b/README.md
index 8bf013f..640f0fd 100644
--- a/README.md
+++ b/README.md
@@ -4,14 +4,14 @@ CLI client for [Duniter-V2S](https://git.duniter.org/nodes/rust/duniter-v2s/).
 
 ## Usage
 
-Send 10 ÄžD from Alice to Ferdie:
-
-	cargo run -- --url ws://localhost:9944 --secret //Alice transfer 1000 5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL
-
 If using a different runtime, update the metadata for the client to compile:
 
 	subxt metadata -f bytes > res/metadata.scale
 
+Send 10 ÄžD from Alice to Ferdie:
+
+	cargo run -- --url ws://localhost:9944 --secret //Alice transfer 1000 5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL
+
 List certifications and session keys that will expire within one month:
 
-	cargo run -- --url wss://gdev.librelois.fr:443/ws --secret //Alice expire --blocks 432000
+	cargo run -- --url wss://gdev.librelois.fr:443/ws expire --blocks 432000
diff --git a/src/main.rs b/src/main.rs
index f7ca9b0..d5ca0e3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,10 +5,11 @@ use anyhow::{anyhow, Context, Result};
 use clap::Parser;
 use codec::Encode;
 use sp_core::{
-    crypto::{AccountId32, DeriveJunction, Pair as _},
+    crypto::{AccountId32, DeriveJunction, Pair as _, Ss58Codec},
     sr25519::Pair,
 };
 use std::collections::BTreeMap;
+use std::str::FromStr;
 use subxt::sp_runtime::MultiAddress;
 use subxt::{
     extrinsic::{BaseExtrinsicParams, BaseExtrinsicParamsBuilder},
@@ -54,7 +55,10 @@ struct Args {
     /// Secret key or BIP39 mnemonic
     /// (eventually followed by derivation path)
     #[clap(short, long)]
-    secret: String,
+    secret: Option<String>,
+    /// Address
+    #[clap(short, long)]
+    address: Option<String>,
     /// Websocket RPC endpoint
     #[clap(short, long, default_value = "ws://localhost:9944")]
     url: String,
@@ -118,8 +122,33 @@ async fn main() -> Result<()> {
 
     let args = Args::parse();
 
-    let pair = Pair::from_string(&args.secret, None)
-        .map_err(|_| anyhow!("Invalid secret {}", args.secret))?;
+    let (account_id, pair) = match (&args.address, &args.secret) {
+        (Some(address), Some(secret)) => {
+            let pair = Pair::from_string(secret, None)
+                .map_err(|_| anyhow!("Invalid secret {}", secret))?;
+            let address = sp_core::crypto::AccountId32::from_string(address)
+                .map_err(|_| anyhow!("Invalid address {}", address))?;
+            assert_eq!(
+                address,
+                pair.public().into(),
+                "Secret and address do not match."
+            );
+            (Some(pair.public().into()), Some(pair))
+        }
+        (None, Some(secret)) => {
+            let pair = Pair::from_string(secret, None)
+                .map_err(|_| anyhow!("Invalid secret {}", secret))?;
+            (Some(pair.public().into()), Some(pair))
+        }
+        (Some(address), None) => (
+            Some(
+                sp_core::crypto::AccountId32::from_str(address)
+                    .map_err(|_| anyhow!("Invalid address {}", address))?,
+            ),
+            None,
+        ),
+        (None, None) => (None, None),
+    };
 
     let client: Client = ClientBuilder::new()
         .set_url(&args.url)
@@ -132,12 +161,15 @@ async fn main() -> Result<()> {
         .user_agent("gcli/0.1.0")
         .build()?;
 
-    let account_id: sp_core::crypto::AccountId32 = pair.public().into();
-    let account = api.storage().system().account(&account_id, None).await?;
-    logs::info!("Account free balance: {}", account.data.free);
+    if let Some(account_id) = &account_id {
+        let account = api.storage().system().account(account_id, None).await?;
+        logs::info!("Account free balance: {}", account.data.free);
+    }
 
     match args.subcommand {
         Subcommand::CreateOneshot { balance, dest } => {
+            let pair = pair.expect("This subcommand needs a secret.");
+
             api.tx()
                 .oneshot_account()
                 .create_oneshot_account(dest.into(), balance)?
@@ -148,6 +180,8 @@ async fn main() -> Result<()> {
                 .await?;
         }
         Subcommand::ConsumeOneshot { dest, dest_oneshot } => {
+            let pair = pair.expect("This subcommand needs a secret.");
+
             let number = api.storage().system().number(None).await?;
             api.tx()
                 .oneshot_account()
@@ -176,6 +210,8 @@ async fn main() -> Result<()> {
             remaining_to,
             remaining_to_oneshot,
         } => {
+            let pair = pair.expect("This subcommand needs a secret.");
+
             let number = api.storage().system().number(None).await?;
             api.tx()
                 .oneshot_account()
@@ -354,7 +390,9 @@ async fn main() -> Result<()> {
                 }
             }
         }
-        Subcommand::GenRevocDoc => gen_revoc_doc(&api, &pair).await?,
+        Subcommand::GenRevocDoc => {
+            gen_revoc_doc(&api, &pair.expect("This subcommand needs a secret.")).await?
+        }
         Subcommand::OneshotBalance { account } => {
             logs::info!(
                 "{}",
@@ -369,6 +407,8 @@ async fn main() -> Result<()> {
             target,
             actual_repart,
         } => {
+            let pair = pair.expect("This subcommand needs a secret.");
+
             let mut pairs = Vec::new();
             for i in actual_repart.unwrap_or_default()..target {
                 let pair_i = pair
@@ -398,6 +438,8 @@ async fn main() -> Result<()> {
             }
         }
         Subcommand::SpamRoll { actual_repart } => {
+            let pair = pair.expect("This subcommand needs a secret.");
+
             let mut pairs =
                 Vec::<(PairSigner<DefaultConfig, Pair>, AccountId32)>::with_capacity(actual_repart);
             for i in 0..actual_repart {
@@ -448,6 +490,8 @@ async fn main() -> Result<()> {
             dest,
             keep_alive,
         } => {
+            let pair = pair.expect("This subcommand needs a secret.");
+
             if keep_alive {
                 api.tx()
                     .balances()
-- 
GitLab