From 61bd3405f173857f65f882429efe500f54cd3a52 Mon Sep 17 00:00:00 2001 From: librelois <c@elo.tf> Date: Thu, 25 Mar 2021 00:00:54 +0100 Subject: [PATCH] feat(pay): add ud units, pay to scrypt, and confirmation --- Cargo.lock | 39 +++++++++++------ Cargo.toml | 1 + src/commands.rs | 1 + src/commands/wallet.rs | 96 +++++++++++++++++++++++++++--------------- src/inputs.rs | 34 +++++++++++++++ src/main.rs | 6 ++- 6 files changed, 128 insertions(+), 49 deletions(-) create mode 100644 src/inputs.rs diff --git a/Cargo.lock b/Cargo.lock index 099be32..08e1a23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,6 +81,9 @@ name = "arrayvec" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +dependencies = [ + "serde", +] [[package]] name = "ascii" @@ -350,9 +353,9 @@ checksum = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d" [[package]] name = "dubp" -version = "0.49.0" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9617091ba0d0a0cc95392655b0b7136fee3b63101d64c0fd0a5c2741983f18" +checksum = "1669c61ccfe0d3fc7be8fe3175ebd401b9c879f638425f31e92777c73b32ea86" dependencies = [ "dubp-common", "dubp-documents", @@ -364,7 +367,7 @@ dependencies = [ [[package]] name = "dubp-client" version = "0.1.0" -source = "git+https://git.duniter.org/libs/dubp-rs-client-lib?branch=master#398b44b8b61e6cf631c1842ca44c9f3916c1c66f" +source = "git+https://git.duniter.org/libs/dubp-rs-client-lib?branch=master#a690f9b1bb029495c6aaf957c31d528dd282b49c" dependencies = [ "bincode", "dubp", @@ -380,9 +383,9 @@ dependencies = [ [[package]] name = "dubp-common" -version = "0.49.0" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da764b34a61ecb52fa90dc11f5a44d6bc9599b043d37592b5102b95d993fd677" +checksum = "515fb09166a50b4543a99c42359fc4afa5a4c7af118c6f9627575c2760f3fef8" dependencies = [ "dup-crypto", "serde", @@ -393,9 +396,9 @@ dependencies = [ [[package]] name = "dubp-documents" -version = "0.49.0" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8810039b6dd6a101109aebc9836ddec58366052803f824c56016889d9444f5cf" +checksum = "ccc9327c62778ee4fd060c0efbe32c6cfda5e317c4a2eb4ddee8293fbd278904" dependencies = [ "beef", "dubp-wallet", @@ -407,9 +410,9 @@ dependencies = [ [[package]] name = "dubp-documents-parser" -version = "0.49.0" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c791c77a3f9c670666dc41f861481cc80eb1ad193584727adfee792350fd3129" +checksum = "271ce4a6bebfdfdaefb0e51f57c9bb04976fce5fbe2744dd60c1dcf857c60c20" dependencies = [ "dubp-documents", "json-pest-parser", @@ -421,9 +424,9 @@ dependencies = [ [[package]] name = "dubp-wallet" -version = "0.49.0" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ef8e7c5334ddbc7899f83911026ebc324ba7fc7232c7ca5265e611490dbd282" +checksum = "f6e65a121fa6745038e903ed3d1eb6a97f9658c6c6e2bfbf7e9ffdaf34161d23" dependencies = [ "byteorder", "dubp-common", @@ -436,8 +439,9 @@ dependencies = [ [[package]] name = "duniter-bca-types" version = "0.1.0" -source = "git+https://git.duniter.org/nodes/typescript/duniter?branch=bca#fd6d221857461f75d059c5fc2afc24daab4d5545" +source = "git+https://git.duniter.org/nodes/typescript/duniter?branch=dev#591f334185151a200a7dbb06b32ff434a19b0885" dependencies = [ + "arrayvec", "bincode", "dubp", "serde", @@ -447,9 +451,9 @@ dependencies = [ [[package]] name = "dup-crypto" -version = "0.49.0" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0be04829b31b18bacf5317001366d807e5fbd02085ee6348508c1299b5bcaf6c" +checksum = "3032421000ca2cdd372bd72f4c548be7f1386d357abb0936291890064d3072e8" dependencies = [ "aes", "arrayvec", @@ -633,6 +637,7 @@ dependencies = [ "anyhow", "dubp-client", "mockall 0.8.3", + "read_input", "rpassword", "serde", "structopt", @@ -1269,6 +1274,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "read_input" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b57518cc6538a2eb7dce826e24fa51d0b7cf8e744ee10c7f56259cdec40050e5" + [[package]] name = "regex" version = "1.4.4" diff --git a/Cargo.toml b/Cargo.toml index 0a29130..84b3d75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ description = "A command line client written in Rust that use Duniter GVA API." anyhow = "1.0.32" dubp-client = { git = "https://git.duniter.org/libs/dubp-rs-client-lib", branch = "master", features = ["blocking"], default-features = false } #dubp-client= { path = "../dubp-rs-client-lib", features = ["blocking"], default-features = false } +read_input = "0.8.4" rpassword = "5.0.1" serde = { version = "1.0.105", features = ["derive"] } structopt = "0.3.18" diff --git a/src/commands.rs b/src/commands.rs index fae427f..a252528 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -21,6 +21,7 @@ pub mod wallet; use crate::*; +#[allow(clippy::large_enum_variant)] #[derive(StructOpt)] pub(crate) enum Command { /// Get account balance diff --git a/src/commands/wallet.rs b/src/commands/wallet.rs index a4c596c..7caaae2 100644 --- a/src/commands/wallet.rs +++ b/src/commands/wallet.rs @@ -23,7 +23,7 @@ use dubp_client::{ }, keys::{ ed25519::bip32::{KeyPair, PrivateDerivationPath}, - KeyPair as _, KeyPairEnum, PublicKey, + KeyPair as _, KeyPairEnum, }, mnemonic::{mnemonic_to_seed, Language, Mnemonic, MnemonicType}, utils::U31, @@ -31,6 +31,7 @@ use dubp_client::{ wallet::prelude::SourceAmount, }; +#[allow(clippy::large_enum_variant)] #[derive(StructOpt)] pub enum WalletCommand { /// Generate a wallet @@ -75,7 +76,7 @@ pub enum WalletCommand { Pay { account_index: u32, #[structopt(short, long)] - amount: u64, + amount: f64, #[structopt(short, long)] base: Option<u64>, #[structopt(short, long)] @@ -89,7 +90,13 @@ pub enum WalletCommand { #[structopt(long)] password_stdin: bool, #[structopt(short, long)] - recipient: String, + recipient: PkOrScript, + /// UD units + #[structopt(short, long)] + ud_units: bool, + /// Auto confirm (for non-interactive use) + #[structopt(short, long)] + yes: bool, }, } @@ -176,49 +183,70 @@ pub(crate) fn wallet<C: GvaClient, W: Write>( lang, password_stdin, recipient, + ud_units, + yes, } => { - let recipient = PublicKey::from_base58(&recipient)?; - + let recipient = recipient.0; let keypair = get_master_keypair(dewif, dewif_file, lang, password_stdin)?; + let (amount, amount_str) = if ud_units { + (Amount::Uds(amount), format!("{:.2} UDğ1", amount)) + } else { + ( + Amount::Cents(SourceAmount::new( + (amount * 100.0).round() as i64, + base.unwrap_or_default() as i64, + )), + format!("{:.2} Ğ1", amount), + ) + }; + match account_index % 3 { 0 => { let trasparent_keypair = keypair.derive(PrivateDerivationPath::transparent( U31::new(account_index)?, )?); - writeln!( - out, - "Sending {}.{} Ğ1 to {} from transparent account {} …", - amount / 100, - amount % 100, - recipient, - trasparent_keypair.public_key().to_base58() - )?; + let confirm = if yes { + true + } else { + let res = input() + .msg(format!( + "Send {} to {} from transparent account {}? [y/N]", + amount_str, + recipient.to_string(), + trasparent_keypair.public_key().to_base58() + )) + .default('N') + .get(); + res == 'y' || res == 'Y' + }; - let req_time = Instant::now(); - let payment_result = gva_client.simple_payment( - SourceAmount::new(amount as i64, base.unwrap_or_default() as i64), - &trasparent_keypair.generate_signator(), - recipient, - comment, - None, - )?; + if confirm { + let req_time = Instant::now(); + let payment_result = gva_client.simple_payment( + amount, + &trasparent_keypair.generate_signator(), + recipient, + comment, + None, + )?; - if let PaymentResult::Errors(errors) = payment_result { - writeln!(out, "All or part of the payment failed, errors: \n")?; - for error in errors { - writeln!(out, "- {:?}", error)?; + if let PaymentResult::Errors(errors) = payment_result { + writeln!(out, "All or part of the payment failed, errors: \n")?; + for error in errors { + writeln!(out, "- {:?}", error)?; + } + todo!() + } else { + let duration = req_time.elapsed(); + writeln!( + out, + "Payment succesfully processed in {}.{} ms.", + duration.as_millis(), + duration.subsec_micros() % 1_000 + )?; } - todo!() - } else { - writeln!(out, "Payment succesfully sent.")?; - let duration = req_time.elapsed(); - println!( - "Payment processed in {}.{} ms.", - duration.as_millis(), - duration.subsec_micros() % 1_000 - ); } Ok(()) diff --git a/src/inputs.rs b/src/inputs.rs new file mode 100644 index 0000000..e11f1bb --- /dev/null +++ b/src/inputs.rs @@ -0,0 +1,34 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +use crate::*; +use dubp_client::{ + crypto::keys::PublicKey as _, + documents_parser::{wallet_script_from_str, TextParseError}, +}; + +pub struct PkOrScript(pub(crate) WalletScriptV10); + +impl FromStr for PkOrScript { + type Err = TextParseError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + if let Ok(pubkey) = PublicKey::from_base58(s) { + Ok(Self(WalletScriptV10::single_sig(pubkey))) + } else { + Ok(Self(wallet_script_from_str(s)?)) + } + } +} diff --git a/src/main.rs b/src/main.rs index cebd558..dd82f88 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,8 +25,10 @@ )] mod commands; +mod inputs; use crate::commands::Command; +use crate::inputs::PkOrScript; use commands::{ balance::balance, current_ud::current_ud, idty::idty, members_count::members_count, wallet::wallet, @@ -35,8 +37,10 @@ use commands::{ use dubp_client::MockGvaClient; use dubp_client::{ crypto::keys::{ed25519::PublicKey, PublicKey as _}, - AccountBalance, GvaClient, Idty, NaiveGvaClient, PaymentResult, PubkeyOrScript, + wallet::prelude::*, + AccountBalance, Amount, GvaClient, Idty, NaiveGvaClient, PaymentResult, PubkeyOrScript, }; +use read_input::prelude::*; use std::{ env::var_os, fs::File, -- GitLab