Skip to content

Commit

Permalink
Add propose command.
Browse files Browse the repository at this point in the history
This command takes the same arguments as `send`, but instead of
executing a transaction, it simply creates and prints out the proposal
for the transaction without executing it.
  • Loading branch information
nuttycom committed Nov 16, 2023
1 parent f3449b6 commit 0973bfd
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 29 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/target
/zec_sqlite_wallet*
32 changes: 14 additions & 18 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,9 @@ zcash_client_backend = { version = "0.10", features = ["lightwalletd-tonic"] }
zcash_client_sqlite = { version = "0.8", features = ["unstable"] }
zcash_primitives = "0.13"
zcash_proofs = "0.13"

[patch.crates-io]
zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "236cd569ee4a824d98920d1a61b8cc2b90ceba1d" }
zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "236cd569ee4a824d98920d1a61b8cc2b90ceba1d" }
zcash_client_backend = { git = "https://github.com/zcash/librustzcash.git", rev = "236cd569ee4a824d98920d1a61b8cc2b90ceba1d" }
zcash_client_sqlite = { git = "https://github.com/zcash/librustzcash.git", rev = "236cd569ee4a824d98920d1a61b8cc2b90ceba1d" }
1 change: 1 addition & 0 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub(crate) mod balance;
pub(crate) mod init;
pub(crate) mod list_tx;
pub(crate) mod list_unspent;
pub(crate) mod propose;
pub(crate) mod reset;
pub(crate) mod send;
pub(crate) mod sync;
Expand Down
9 changes: 6 additions & 3 deletions src/commands/list_unspent.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use anyhow::anyhow;
use gumdrop::Options;

use zcash_client_backend::data_api::WalletRead;
use zcash_client_backend::data_api::{SaplingInputSource, WalletRead};
use zcash_client_sqlite::WalletDb;
use zcash_primitives::{
consensus::Parameters,
transaction::components::amount::{Amount, MAX_MONEY},
transaction::components::{
amount::{Amount, MAX_MONEY},
sapling::fees::InputView,
},
zip32::AccountId,
};

Expand Down Expand Up @@ -41,7 +44,7 @@ impl Command {
)?;

for note in notes {
println!("{}: {}", note.note_id, format_zec(note.note_value));
println!("{}: {}", note.note_id(), format_zec(note.value()));
}

Ok(())
Expand Down
110 changes: 110 additions & 0 deletions src/commands/propose.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use gumdrop::Options;

use zcash_client_backend::{
address::RecipientAddress,
data_api::wallet::{input_selection::GreedyInputSelector, propose_transfer},
fees::standard::SingleOutputChangeStrategy,
zip321::{Payment, TransactionRequest},
};
use zcash_client_sqlite::WalletDb;
use zcash_primitives::{
consensus::Parameters,
transaction::{components::amount::NonNegativeAmount, fees::StandardFeeRule},
zip32::AccountId,
};

use crate::{data::get_db_paths, error, MIN_CONFIRMATIONS};

#[derive(Clone, Copy, Debug)]
pub(crate) enum FeeRule {
Fixed,
Zip317,
}

impl Default for FeeRule {
fn default() -> Self {
FeeRule::Zip317
}
}

#[allow(deprecated)]
impl From<FeeRule> for StandardFeeRule {
fn from(rule: FeeRule) -> Self {
match rule {
FeeRule::Fixed => StandardFeeRule::PreZip313,
FeeRule::Zip317 => StandardFeeRule::Zip317,
}
}
}

pub(crate) fn parse_fee_rule(name: &str) -> Result<FeeRule, String> {
match name {
"fixed" => Ok(FeeRule::Fixed),
"zip317" => Ok(FeeRule::Zip317),
other => Err(format!("Fee rule {} not recognized.", other)),
}
}

// Options accepted for the `propose` command
#[derive(Debug, Options)]
pub(crate) struct Command {
#[options(
required,
help = "the recipient's Unified, Sapling or transparent address"
)]
address: String,

#[options(required, help = "the amount in zatoshis")]
value: u64,

#[options(
required,
help = "fee strategy: \"fixed\" or \"zip317\"",
parse(try_from_str = "parse_fee_rule")
)]
fee_rule: FeeRule,
}

impl Command {
pub(crate) async fn run(
self,
params: impl Parameters + Copy + 'static,
wallet_dir: Option<String>,
) -> Result<(), anyhow::Error> {
let account = AccountId::from(0);
let (_, db_data) = get_db_paths(wallet_dir.as_ref());
let mut db_data = WalletDb::for_path(db_data, params)?;

let input_selector = GreedyInputSelector::new(
SingleOutputChangeStrategy::new(self.fee_rule.into(), None),
Default::default(),
);

let request = TransactionRequest::new(vec![Payment {
recipient_address: RecipientAddress::decode(&params, &self.address)
.ok_or(error::Error::InvalidRecipient)?,
amount: NonNegativeAmount::from_u64(self.value)
.map_err(|_| error::Error::InvalidAmount)?,
memo: None,
label: None,
message: None,
other_params: vec![],
}])
.map_err(error::Error::from)?;

let proposal = propose_transfer(
&mut db_data,
&params,
account,
&input_selector,
request,
MIN_CONFIRMATIONS,
)
.map_err(error::Error::from)?;

// Display the proposal
println!("Proposal: {:#?}", proposal);

Ok(())
}
}
22 changes: 15 additions & 7 deletions src/commands/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,20 @@ use zcash_client_backend::{
wallet::{input_selection::GreedyInputSelector, spend},
WalletRead,
},
fees::zip317::SingleOutputChangeStrategy,
fees::standard::SingleOutputChangeStrategy,
keys::UnifiedSpendingKey,
proto::service,
wallet::OvkPolicy,
zip321::{Payment, TransactionRequest},
};
use zcash_client_sqlite::WalletDb;
use zcash_primitives::{
consensus::Parameters,
transaction::{components::Amount, fees::zip317::FeeRule},
zip32::AccountId,
consensus::Parameters, transaction::components::amount::NonNegativeAmount, zip32::AccountId,
};
use zcash_proofs::prover::LocalTxProver;

use crate::{
commands::propose::{parse_fee_rule, FeeRule},
data::{get_db_paths, get_wallet_seed},
error,
remote::connect_to_lightwalletd,
Expand All @@ -36,6 +35,13 @@ pub(crate) struct Command {

#[options(required, help = "the amount in zatoshis")]
value: u64,

#[options(
required,
help = "fee strategy: \"fixed\" or \"zip317\"",
parse(try_from_str = "parse_fee_rule")
)]
fee_rule: FeeRule,
}

impl Command {
Expand All @@ -59,14 +65,15 @@ impl Command {
let prover =
LocalTxProver::with_default_location().ok_or(error::Error::MissingParameters)?;
let input_selector = GreedyInputSelector::new(
SingleOutputChangeStrategy::new(FeeRule::standard()),
SingleOutputChangeStrategy::new(self.fee_rule.into(), None),
Default::default(),
);

let request = TransactionRequest::new(vec![Payment {
recipient_address: RecipientAddress::decode(&params, &self.address)
.ok_or(error::Error::InvalidRecipient)?,
amount: Amount::from_u64(self.value).map_err(|_| error::Error::InvalidAmount)?,
amount: NonNegativeAmount::from_u64(self.value)
.map_err(|_| error::Error::InvalidAmount)?,
memo: None,
label: None,
message: None,
Expand All @@ -77,7 +84,8 @@ impl Command {
let id_tx = spend(
&mut db_data,
&params,
prover,
&prover,
&prover,
&input_selector,
&usk,
request,
Expand Down
1 change: 0 additions & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ pub(crate) type WalletErrorT = WalletError<
commitment_tree::Error,
GreedyInputSelectorError<FeeError, ReceivedNoteId>,
FeeError,
ReceivedNoteId,
>;

#[derive(Debug)]
Expand Down
4 changes: 4 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ enum Command {
#[options(help = "list the unspent notes in the wallet")]
ListUnspent(commands::list_unspent::Command),

#[options(help = "propose a transfer of funds to the given address and display the proposal")]
Propose(commands::propose::Command),

#[options(help = "send funds to the given address")]
Send(commands::send::Command),
}
Expand Down Expand Up @@ -89,6 +92,7 @@ fn main() -> Result<(), anyhow::Error> {
Some(Command::Balance(command)) => command.run(params, opts.wallet_dir),
Some(Command::ListTx(command)) => command.run(opts.wallet_dir),
Some(Command::ListUnspent(command)) => command.run(params, opts.wallet_dir),
Some(Command::Propose(command)) => command.run(params, opts.wallet_dir).await,
Some(Command::Send(command)) => command.run(params, opts.wallet_dir).await,
_ => Ok(()),
}
Expand Down

0 comments on commit 0973bfd

Please sign in to comment.