From b7376dc6bbd3311457ac0193cf03e8de5cbe428a Mon Sep 17 00:00:00 2001 From: Oscar Pepper Date: Wed, 10 Apr 2024 15:01:25 +0100 Subject: [PATCH 01/11] added propose and quicksend commmands behind zip317 feature --- zingolib/Cargo.toml | 1 + zingolib/src/commands.rs | 155 ++++++++++++++++++++++++++++++--- zingolib/src/commands/utils.rs | 5 +- 3 files changed, 149 insertions(+), 12 deletions(-) diff --git a/zingolib/Cargo.toml b/zingolib/Cargo.toml index f02582091..c765868bb 100644 --- a/zingolib/Cargo.toml +++ b/zingolib/Cargo.toml @@ -14,6 +14,7 @@ test-features = ["zingo-testvectors"] default = ["embed_params"] embed_params = [] darkside_tests = [] +zip317 = [] [dependencies] zingoconfig = { path = "../zingoconfig" } diff --git a/zingolib/src/commands.rs b/zingolib/src/commands.rs index 945f6ea64..191cdbbda 100644 --- a/zingolib/src/commands.rs +++ b/zingolib/src/commands.rs @@ -790,31 +790,91 @@ impl Command for DecryptMessageCommand { } } +#[cfg(feature = "zip317")] +struct ProposeCommand {} +#[cfg(feature = "zip317")] +impl Command for ProposeCommand { + fn help(&self) -> &'static str { + indoc! {r#" + Propose a transfer of ZEC to the given address(es) prior to sending. + The fee required to send this transaction will be added to the proposal and displayed to the user. + Usage: + propose
"" + OR + propose '[{"address":"
", "amount":, "memo":""}, ...]' + Example: + propose ztestsapling1x65nq4dgp0qfywgxcwk9n0fvm4fysmapgr2q00p85ju252h6l7mmxu2jg9cqqhtvzd69jwhgv8d 200000 "Hello from the command line" + send + + "#} + } + + fn short_help(&self) -> &'static str { + "Propose a transfer of ZEC to the given address(es) prior to sending." + } + + fn exec(&self, args: &[&str], lightclient: &LightClient) -> String { + let send_inputs = match utils::parse_send_args(args) { + Ok(args) => args, + Err(e) => { + return format!( + "Error: {}\nTry 'help send' for correct usage and examples.", + e + ) + } + }; + for send in &send_inputs { + let address = &send.0; + let memo = &send.2; + if memo.is_some() && is_transparent_address(address, &lightclient.config.chain) { + return format!( + "Error: {}\nTry 'help send' for correct usage and examples.", + CommandError::IncompatibleMemo, + ); + } + } + RT.block_on(async move { + match lightclient + .do_propose( + send_inputs + .iter() + .map(|(address, amount, memo)| (address.as_str(), *amount, memo.clone())) + .collect(), + ) + .await { + Ok(proposal) => { + object! { "fee" => proposal.steps().iter().fold(0, |acc, step| acc + u64::from(step.balance().fee_required()))} + } + Err(e) => { + object! { "error" => e } + } + } + .pretty(2) + }) + } +} + struct SendCommand {} impl Command for SendCommand { fn help(&self) -> &'static str { indoc! {r#" - Send ZEC to a given address(es) + Send ZEC to the given address(es). + The 10_000 zat fee required to send this transaction is additionally deducted from your balance. Usage: - send
"" - OR - send '[{"address":"
", "amount":, "memo":""}, ...]' - - NOTE: The fee required to send this transaction (currently ZEC 0.0001) is additionally deducted from your balance. + send
"" + OR + send '[{"address":"
", "amount":, "memo":""}, ...]' Example: - send ztestsapling1x65nq4dgp0qfywgxcwk9n0fvm4fysmapgr2q00p85ju252h6l7mmxu2jg9cqqhtvzd69jwhgv8d 200000 "Hello from the command line" + send ztestsapling1x65nq4dgp0qfywgxcwk9n0fvm4fysmapgr2q00p85ju252h6l7mmxu2jg9cqqhtvzd69jwhgv8d 200000 "Hello from the command line" "#} } fn short_help(&self) -> &'static str { - "Send ZEC to the given address" + "Send ZEC to the given address(es)." } fn exec(&self, args: &[&str], lightclient: &LightClient) -> String { - // Parse the args. There are two argument types. - // 1 - A set of 2(+1 optional) arguments for a single address send representing address, amount, memo? - // 2 - A single argument in the form of a JSON string that is '[{"address":"
", "value":, "memo":""}, ...]' let send_inputs = match utils::parse_send_args(args) { Ok(args) => args, Err(e) => { @@ -856,6 +916,74 @@ impl Command for SendCommand { } } +#[cfg(feature = "zip317")] +struct QuickSendCommand {} +#[cfg(feature = "zip317")] +impl Command for QuickSendCommand { + fn help(&self) -> &'static str { + indoc! {r#" + Send ZEC to the given address(es). Combines `Propose` and `Send` into a single command. + The fee required to send this transaction is additionally deducted from your balance. + Warning: + Transaction(s) will be sent without the user being aware of the fee amount. + Usage: + quicksend
"" + OR + quicksend '[{"address":"
", "amount":, "memo":""}, ...]' + Example: + quicksend ztestsapling1x65nq4dgp0qfywgxcwk9n0fvm4fysmapgr2q00p85ju252h6l7mmxu2jg9cqqhtvzd69jwhgv8d 200000 "Hello from the command line" + + "#} + } + + fn short_help(&self) -> &'static str { + "Send ZEC to the given address(es). Combines `Propose` and `Send` into a single command." + } + + fn exec(&self, args: &[&str], lightclient: &LightClient) -> String { + let send_inputs = match utils::parse_send_args(args) { + Ok(args) => args, + Err(e) => { + return format!( + "Error: {}\nTry 'help send' for correct usage and examples.", + e + ) + } + }; + for send in &send_inputs { + let address = &send.0; + let memo = &send.2; + if memo.is_some() && is_transparent_address(address, &lightclient.config.chain) { + return format!( + "Error: {}\nTry 'help send' for correct usage and examples.", + CommandError::IncompatibleMemo, + ); + } + } + RT.block_on(async move { + lightclient + .do_propose( + send_inputs + .iter() + .map(|(address, amount, memo)| (address.as_str(), *amount, memo.clone())) + .collect(), + ) + .await?; + match lightclient + .do_send_proposal().await + { + Ok(txids) => { + object! { "txids" => txids.iter().map(|txid| txid.to_string()).collect::>()} + } + Err(e) => { + object! { "error" => e } + } + } + .pretty(2) + }) + } +} + struct DeleteCommand {} impl Command for DeleteCommand { fn help(&self) -> &'static str { @@ -1434,6 +1562,11 @@ pub fn get_commands() -> HashMap<&'static str, Box> { { entries.push(("list", Box::new(TransactionsCommand {}))); } + #[cfg(feature = "zip317")] + { + entries.push(("propose", Box::new(ProposeCommand {}))); + entries.push(("quicksend", Box::new(QuickSendCommand {}))); + } entries.into_iter().collect() } diff --git a/zingolib/src/commands/utils.rs b/zingolib/src/commands/utils.rs index f4758b16c..3e86a801e 100644 --- a/zingolib/src/commands/utils.rs +++ b/zingolib/src/commands/utils.rs @@ -4,7 +4,10 @@ use crate::commands::error::CommandError; use crate::wallet; use zcash_primitives::memo::MemoBytes; -/// Send args accepts two different formats for its input +/// Parse the send arguments for `do_propose`. +/// The send arguments have two possible formats: +/// - 1 argument in the form of a JSON string for multiple sends. '[{"address":"
", "value":, "memo":""}, ...]' +/// - 2 (+1 optional) arguments for a single address send. &["
", , ""] pub(super) fn parse_send_args( args: &[&str], ) -> Result)>, CommandError> { From a461fe78116c63beef22f84773808a6be3f51503 Mon Sep 17 00:00:00 2001 From: Oscar Pepper Date: Wed, 10 Apr 2024 15:52:58 +0100 Subject: [PATCH 02/11] added unimplemented do_propose and do_send_proposal lightclient methods --- zingolib/src/commands.rs | 8 +++++--- zingolib/src/lightclient/send.rs | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/zingolib/src/commands.rs b/zingolib/src/commands.rs index 191cdbbda..c52d0802d 100644 --- a/zingolib/src/commands.rs +++ b/zingolib/src/commands.rs @@ -843,7 +843,7 @@ impl Command for ProposeCommand { ) .await { Ok(proposal) => { - object! { "fee" => proposal.steps().iter().fold(0, |acc, step| acc + u64::from(step.balance().fee_required()))} + object! { "fee" => proposal.steps().iter().fold(0, |acc, step| acc + u64::from(step.balance().fee_required())) } } Err(e) => { object! { "error" => e } @@ -961,14 +961,16 @@ impl Command for QuickSendCommand { } } RT.block_on(async move { - lightclient + if let Err(e) = lightclient .do_propose( send_inputs .iter() .map(|(address, amount, memo)| (address.as_str(), *amount, memo.clone())) .collect(), ) - .await?; + .await { + return e; + }; match lightclient .do_send_proposal().await { diff --git a/zingolib/src/lightclient/send.rs b/zingolib/src/lightclient/send.rs index bf91fadfd..3b63c2fa3 100644 --- a/zingolib/src/lightclient/send.rs +++ b/zingolib/src/lightclient/send.rs @@ -10,6 +10,9 @@ use zcash_proofs::prover::LocalTxProver; use super::{LightClient, LightWalletSendProgress}; use crate::wallet::Pool; +#[cfg(feature = "zip317")] +use {zcash_client_backend::proposal::Proposal, zcash_primitives::transaction::TxId}; + impl LightClient { async fn get_submission_height(&self) -> Result { Ok(BlockHeight::from_u32( @@ -53,6 +56,19 @@ impl LightClient { .collect() } + #[cfg(feature = "zip317")] + pub async fn do_propose( + &self, + _address_amount_memo_tuples: Vec<(&str, u64, Option)>, + ) -> Result, String> { + unimplemented!() + } + + #[cfg(feature = "zip317")] + pub async fn do_send_proposal(&self) -> Result, String> { + unimplemented!() + } + //TODO: Add migrate_sapling_to_orchard argument pub async fn do_send( &self, From 82a07a85d6e6c6ea3c47d1753f8e4ca7bdef2dd1 Mon Sep 17 00:00:00 2001 From: Oscar Pepper Date: Wed, 10 Apr 2024 16:03:58 +0100 Subject: [PATCH 03/11] updated changelog --- zingolib/CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/zingolib/CHANGELOG.md b/zingolib/CHANGELOG.md index 37a1d8834..12a78b240 100644 --- a/zingolib/CHANGELOG.md +++ b/zingolib/CHANGELOG.md @@ -23,14 +23,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `utils::txid_from_hex_encoded_str` fn - `test_framework` module - `test_framework::mocks` module +- `lightclient::send` + - `do_propose` behind zip317 feature + - `do_send_proposal` behind zip317 feature +- `commands` + - `ProposeCommand` struct and methods + - `QuickSendCommand` struct and methods ### Changed - load_client_config fn moves from zingolib to zingoconfig -- `wallet::keys`: - - `is_shielded_address` takes a `&ChainType` instead of a `&ZingoConfig` +- `wallet::keys::is_shielded_address` takes a `&ChainType` instead of a `&ZingoConfig` - zingolib/src/wallet/transaction_record_map.rs -> zingolib/src/wallet/transaction_records_by_id.rs - TransactionRecordMap -> TransactionRecordsById +- `commands` + - `get_commands` added propose and quicksend to entries behind zip317 feature + - `SendCommand::help` formatting ### Removed From 1e381a3012327bc075b60184199aa153c2ff4a79 Mon Sep 17 00:00:00 2001 From: Oscar Pepper Date: Wed, 10 Apr 2024 16:06:00 +0100 Subject: [PATCH 04/11] fixed mistake in changelog --- zingolib/CHANGELOG.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/zingolib/CHANGELOG.md b/zingolib/CHANGELOG.md index 12a78b240..9fa151ce4 100644 --- a/zingolib/CHANGELOG.md +++ b/zingolib/CHANGELOG.md @@ -24,11 +24,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `test_framework` module - `test_framework::mocks` module - `lightclient::send` - - `do_propose` behind zip317 feature - - `do_send_proposal` behind zip317 feature + - `do_propose` behind "zip317" feature + - `do_send_proposal` behind "zip317" feature - `commands` - - `ProposeCommand` struct and methods - - `QuickSendCommand` struct and methods + - `ProposeCommand` struct and methods behind "zip317" feature + - `QuickSendCommand` struct and methods behind "zip317" feature ### Changed @@ -37,7 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - zingolib/src/wallet/transaction_record_map.rs -> zingolib/src/wallet/transaction_records_by_id.rs - TransactionRecordMap -> TransactionRecordsById - `commands` - - `get_commands` added propose and quicksend to entries behind zip317 feature + - `get_commands` added propose and quicksend to entries behind "zip317" feature - `SendCommand::help` formatting ### Removed From a984aa768a8920de3ff27d067fe2b8d21e36e2a6 Mon Sep 17 00:00:00 2001 From: Oscar Pepper Date: Wed, 10 Apr 2024 16:09:33 +0100 Subject: [PATCH 05/11] fix whitespace --- zingolib/src/commands.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zingolib/src/commands.rs b/zingolib/src/commands.rs index c52d0802d..eb7b68d36 100644 --- a/zingolib/src/commands.rs +++ b/zingolib/src/commands.rs @@ -805,7 +805,7 @@ impl Command for ProposeCommand { Example: propose ztestsapling1x65nq4dgp0qfywgxcwk9n0fvm4fysmapgr2q00p85ju252h6l7mmxu2jg9cqqhtvzd69jwhgv8d 200000 "Hello from the command line" send - + "#} } @@ -844,7 +844,7 @@ impl Command for ProposeCommand { .await { Ok(proposal) => { object! { "fee" => proposal.steps().iter().fold(0, |acc, step| acc + u64::from(step.balance().fee_required())) } - } + } Err(e) => { object! { "error" => e } } From dfb290b07c3f2029a9176935fa29408a2eeb5222 Mon Sep 17 00:00:00 2001 From: Oscar Pepper Date: Thu, 11 Apr 2024 14:47:46 +0100 Subject: [PATCH 06/11] Helperised checking memo compatilibity --- zingolib/src/commands.rs | 51 ++++++++++++---------------------- zingolib/src/commands/utils.rs | 17 ++++++++++++ 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/zingolib/src/commands.rs b/zingolib/src/commands.rs index eb7b68d36..05d970b1a 100644 --- a/zingolib/src/commands.rs +++ b/zingolib/src/commands.rs @@ -1,4 +1,3 @@ -use crate::wallet::keys::is_transparent_address; use crate::wallet::{MemoDownloadOption, Pool}; use crate::{lightclient::LightClient, wallet}; use indoc::indoc; @@ -13,8 +12,6 @@ use zcash_client_backend::address::Address; use zcash_primitives::consensus::Parameters; use zcash_primitives::transaction::fees::zip317::MINIMUM_FEE; -use self::error::CommandError; - mod error; mod utils; @@ -823,16 +820,12 @@ impl Command for ProposeCommand { ) } }; - for send in &send_inputs { - let address = &send.0; - let memo = &send.2; - if memo.is_some() && is_transparent_address(address, &lightclient.config.chain) { - return format!( - "Error: {}\nTry 'help send' for correct usage and examples.", - CommandError::IncompatibleMemo, - ); - } - } + if let Err(e) = utils::check_memo_compatibility(&send_inputs, &lightclient.config().chain) { + return format!( + "Error: {}\nTry 'help send' for correct usage and examples.", + e, + ); + }; RT.block_on(async move { match lightclient .do_propose( @@ -884,16 +877,12 @@ impl Command for SendCommand { ) } }; - for send in &send_inputs { - let address = &send.0; - let memo = &send.2; - if memo.is_some() && is_transparent_address(address, &lightclient.config.chain) { - return format!( - "Error: {}\nTry 'help send' for correct usage and examples.", - CommandError::IncompatibleMemo, - ); - } - } + if let Err(e) = utils::check_memo_compatibility(&send_inputs, &lightclient.config().chain) { + return format!( + "Error: {}\nTry 'help send' for correct usage and examples.", + e, + ); + }; RT.block_on(async move { match lightclient .do_send( @@ -950,16 +939,12 @@ impl Command for QuickSendCommand { ) } }; - for send in &send_inputs { - let address = &send.0; - let memo = &send.2; - if memo.is_some() && is_transparent_address(address, &lightclient.config.chain) { - return format!( - "Error: {}\nTry 'help send' for correct usage and examples.", - CommandError::IncompatibleMemo, - ); - } - } + if let Err(e) = utils::check_memo_compatibility(&send_inputs, &lightclient.config().chain) { + return format!( + "Error: {}\nTry 'help send' for correct usage and examples.", + e, + ); + }; RT.block_on(async move { if let Err(e) = lightclient .do_propose( diff --git a/zingolib/src/commands/utils.rs b/zingolib/src/commands/utils.rs index 3e86a801e..0dbedc83e 100644 --- a/zingolib/src/commands/utils.rs +++ b/zingolib/src/commands/utils.rs @@ -3,6 +3,7 @@ use crate::commands::error::CommandError; use crate::wallet; use zcash_primitives::memo::MemoBytes; +use zingoconfig::ChainType; /// Parse the send arguments for `do_propose`. /// The send arguments have two possible formats: @@ -79,6 +80,22 @@ pub(super) fn parse_send_args( Ok(send_args) } +/// Checks send inputs do not contain memo's to transparent addresses. +pub(super) fn check_memo_compatibility( + send_inputs: &[(String, u64, Option)], + chain: &ChainType, +) -> Result<(), CommandError> { + for send in send_inputs { + let address = &send.0; + let memo = &send.2; + if memo.is_some() && wallet::keys::is_transparent_address(address, chain) { + return Err(CommandError::IncompatibleMemo); + } + } + + Ok(()) +} + #[cfg(test)] mod tests { use crate::wallet; From 11d9a57afefb787b2fda7fca0fb36db0b469b9ab Mon Sep 17 00:00:00 2001 From: Oscar Pepper Date: Tue, 16 Apr 2024 15:46:03 +0100 Subject: [PATCH 07/11] do_propose returns mock proposal and do_send_proposal returns a mock Vec --- zingolib/src/lightclient/send.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/zingolib/src/lightclient/send.rs b/zingolib/src/lightclient/send.rs index 3b63c2fa3..46f4bfeaf 100644 --- a/zingolib/src/lightclient/send.rs +++ b/zingolib/src/lightclient/send.rs @@ -3,12 +3,15 @@ use log::{debug, error}; use zcash_primitives::{ consensus::BlockHeight, memo::MemoBytes, - transaction::{components::amount::NonNegativeAmount, fees::zip317::MINIMUM_FEE}, + transaction::{ + components::amount::NonNegativeAmount, + fees::zip317::{FeeRule, MINIMUM_FEE}, + }, }; use zcash_proofs::prover::LocalTxProver; use super::{LightClient, LightWalletSendProgress}; -use crate::wallet::Pool; +use crate::wallet::{notes::NoteRecordIdentifier, Pool}; #[cfg(feature = "zip317")] use {zcash_client_backend::proposal::Proposal, zcash_primitives::transaction::TxId}; @@ -56,17 +59,21 @@ impl LightClient { .collect() } + /// Unstable function to expose the zip317 interface for development #[cfg(feature = "zip317")] pub async fn do_propose( &self, _address_amount_memo_tuples: Vec<(&str, u64, Option)>, - ) -> Result, String> { - unimplemented!() + ) -> Result, String> { + use crate::test_framework::mocks::ProposalBuilder; + + Ok(ProposalBuilder::default().build()) } + /// Unstable function to expose the zip317 interface for development #[cfg(feature = "zip317")] pub async fn do_send_proposal(&self) -> Result, String> { - unimplemented!() + Ok(vec![TxId::from_bytes([0u8; 32])]) } //TODO: Add migrate_sapling_to_orchard argument From 91cb23ec5bac0d60aa7f680fa9fb276d6b1b13a0 Mon Sep 17 00:00:00 2001 From: Oscar Pepper Date: Tue, 16 Apr 2024 17:32:03 +0100 Subject: [PATCH 08/11] fixed warnings --- zingolib/src/lightclient/send.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/zingolib/src/lightclient/send.rs b/zingolib/src/lightclient/send.rs index 46f4bfeaf..2e311ded5 100644 --- a/zingolib/src/lightclient/send.rs +++ b/zingolib/src/lightclient/send.rs @@ -3,15 +3,12 @@ use log::{debug, error}; use zcash_primitives::{ consensus::BlockHeight, memo::MemoBytes, - transaction::{ - components::amount::NonNegativeAmount, - fees::zip317::{FeeRule, MINIMUM_FEE}, - }, + transaction::{components::amount::NonNegativeAmount, fees::zip317::MINIMUM_FEE}, }; use zcash_proofs::prover::LocalTxProver; use super::{LightClient, LightWalletSendProgress}; -use crate::wallet::{notes::NoteRecordIdentifier, Pool}; +use crate::wallet::Pool; #[cfg(feature = "zip317")] use {zcash_client_backend::proposal::Proposal, zcash_primitives::transaction::TxId}; From be5e117bea3b090cd3564fa37c5c1ecdcdb65805 Mon Sep 17 00:00:00 2001 From: Oscar Pepper Date: Tue, 16 Apr 2024 18:26:15 +0100 Subject: [PATCH 09/11] fix dependencies --- zingolib/src/lightclient/send.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/zingolib/src/lightclient/send.rs b/zingolib/src/lightclient/send.rs index 2e311ded5..026bd431e 100644 --- a/zingolib/src/lightclient/send.rs +++ b/zingolib/src/lightclient/send.rs @@ -11,7 +11,11 @@ use super::{LightClient, LightWalletSendProgress}; use crate::wallet::Pool; #[cfg(feature = "zip317")] -use {zcash_client_backend::proposal::Proposal, zcash_primitives::transaction::TxId}; +use { + crate::wallet::notes::NoteRecordIdentifier, + zcash_client_backend::proposal::Proposal, + zcash_primitives::transaction::{fees::zip317::FeeRule, TxId}, +}; impl LightClient { async fn get_submission_height(&self) -> Result { From 37ce683bf61d2bc2c365b7b28544a5f3736c9245 Mon Sep 17 00:00:00 2001 From: Oscar Pepper Date: Wed, 17 Apr 2024 14:05:44 +0100 Subject: [PATCH 10/11] added unit test --- zingolib/src/commands/utils.rs | 53 +++++++++++++++++++++++++++----- zingolib/src/lightclient/send.rs | 4 ++- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/zingolib/src/commands/utils.rs b/zingolib/src/commands/utils.rs index 0dbedc83e..f5ea63c13 100644 --- a/zingolib/src/commands/utils.rs +++ b/zingolib/src/commands/utils.rs @@ -1,14 +1,14 @@ -//! Module containing utility functions for the commands interface +// Module containing utility functions for the commands interface use crate::commands::error::CommandError; use crate::wallet; use zcash_primitives::memo::MemoBytes; use zingoconfig::ChainType; -/// Parse the send arguments for `do_propose`. -/// The send arguments have two possible formats: -/// - 1 argument in the form of a JSON string for multiple sends. '[{"address":"
", "value":, "memo":""}, ...]' -/// - 2 (+1 optional) arguments for a single address send. &["
", , ""] +// Parse the send arguments for `do_propose`. +// The send arguments have two possible formats: +// - 1 argument in the form of a JSON string for multiple sends. '[{"address":"
", "value":, "memo":""}, ...]' +// - 2 (+1 optional) arguments for a single address send. &["
", , ""] pub(super) fn parse_send_args( args: &[&str], ) -> Result)>, CommandError> { @@ -80,7 +80,7 @@ pub(super) fn parse_send_args( Ok(send_args) } -/// Checks send inputs do not contain memo's to transparent addresses. +// Checks send inputs do not contain memo's to transparent addresses. pub(super) fn check_memo_compatibility( send_inputs: &[(String, u64, Option)], chain: &ChainType, @@ -98,7 +98,7 @@ pub(super) fn check_memo_compatibility( #[cfg(test)] mod tests { - use crate::wallet; + use crate::{commands::error::CommandError, wallet}; #[test] fn parse_send_args() { @@ -149,6 +149,7 @@ mod tests { mod fail_parse_send_args { mod json_array { use crate::commands::{error::CommandError, utils::parse_send_args}; + #[test] fn failed_json_parsing() { let args = [r#"testaddress{{"#]; @@ -285,4 +286,42 @@ mod tests { } } } + + #[test] + fn check_memo_compatibility() { + let value_str = "100000"; + let memo_str = "test memo"; + + // shielded address with memo + let address = "zregtestsapling1fmq2ufux3gm0v8qf7x585wj56le4wjfsqsj27zprjghntrerntggg507hxh2ydcdkn7sx8kya7p"; + let send_inputs = super::parse_send_args(&[address, value_str, memo_str]).unwrap(); + super::check_memo_compatibility( + &send_inputs, + &zingoconfig::ChainType::Regtest(zingoconfig::RegtestNetwork::all_upgrades_active()), + ) + .unwrap(); + + // transparent address without memo + let address = "tmBsTi2xWTjUdEXnuTceL7fecEQKeWaPDJd"; + let value_str = "100000"; + let send_inputs = super::parse_send_args(&[address, value_str]).unwrap(); + super::check_memo_compatibility( + &send_inputs, + &zingoconfig::ChainType::Regtest(zingoconfig::RegtestNetwork::all_upgrades_active()), + ) + .unwrap(); + + // transparent address with memo + let address = "tmBsTi2xWTjUdEXnuTceL7fecEQKeWaPDJd"; + let value_str = "100000"; + let memo_str = "test memo"; + let send_inputs = super::parse_send_args(&[address, value_str, memo_str]).unwrap(); + match super::check_memo_compatibility( + &send_inputs, + &zingoconfig::ChainType::Regtest(zingoconfig::RegtestNetwork::all_upgrades_active()), + ) { + Err(CommandError::IncompatibleMemo) => (), + _ => panic!(), + }; + } } diff --git a/zingolib/src/lightclient/send.rs b/zingolib/src/lightclient/send.rs index 026bd431e..1f3b41660 100644 --- a/zingolib/src/lightclient/send.rs +++ b/zingolib/src/lightclient/send.rs @@ -61,6 +61,7 @@ impl LightClient { } /// Unstable function to expose the zip317 interface for development + // TODO: add correct functionality and doc comments / tests #[cfg(feature = "zip317")] pub async fn do_propose( &self, @@ -72,12 +73,13 @@ impl LightClient { } /// Unstable function to expose the zip317 interface for development + // TODO: add correct functionality and doc comments / tests #[cfg(feature = "zip317")] pub async fn do_send_proposal(&self) -> Result, String> { Ok(vec![TxId::from_bytes([0u8; 32])]) } - //TODO: Add migrate_sapling_to_orchard argument + // TODO: Add migrate_sapling_to_orchard argument pub async fn do_send( &self, address_amount_memo_tuples: Vec<(&str, u64, Option)>, From dceea66dccb62f94d3e671e9e63fa8a20abcdd50 Mon Sep 17 00:00:00 2001 From: Oscar Pepper Date: Wed, 17 Apr 2024 14:07:56 +0100 Subject: [PATCH 11/11] updated changelog --- zingolib/CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zingolib/CHANGELOG.md b/zingolib/CHANGELOG.md index bb8bdbed9..acc00405d 100644 --- a/zingolib/CHANGELOG.md +++ b/zingolib/CHANGELOG.md @@ -21,10 +21,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - pub struct crate::wallet::notes::NoteRecordIdentifier - `utils` mod - `utils::txid_from_hex_encoded_str` fn -- `lightclient::send` +- `lightclient::LightClient`: - `do_propose` behind "zip317" feature - `do_send_proposal` behind "zip317" feature -- `commands` +- `commands`: - `ProposeCommand` struct and methods behind "zip317" feature - `QuickSendCommand` struct and methods behind "zip317" feature - `test_framework` mod @@ -35,7 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `wallet::keys::is_shielded_address` takes a `&ChainType` instead of a `&ZingoConfig` - zingolib/src/wallet/transaction_record_map.rs -> zingolib/src/wallet/transaction_records_by_id.rs - TransactionRecordMap -> TransactionRecordsById -- `commands` +- `commands`: - `get_commands` added propose and quicksend to entries behind "zip317" feature - `SendCommand::help` formatting