Merge pull request #65 from Electric-Coin-Company/shield-funds
Add commands to shield funds
This commit is contained in:
commit
39b668a314
|
@ -11,6 +11,7 @@ pub(crate) mod pczt;
|
|||
pub(crate) mod propose;
|
||||
pub(crate) mod reset;
|
||||
pub(crate) mod send;
|
||||
pub(crate) mod shield;
|
||||
pub(crate) mod sync;
|
||||
pub(crate) mod upgrade;
|
||||
|
||||
|
|
|
@ -4,8 +4,9 @@ use gumdrop::Options;
|
|||
use iso_currency::Currency;
|
||||
use rust_decimal::{prelude::FromPrimitive, Decimal};
|
||||
use tracing::{info, warn};
|
||||
use uuid::Uuid;
|
||||
use zcash_client_backend::{data_api::WalletRead, tor};
|
||||
use zcash_client_sqlite::WalletDb;
|
||||
use zcash_client_sqlite::{AccountUuid, WalletDb};
|
||||
use zcash_protocol::value::{Zatoshis, COIN};
|
||||
|
||||
use crate::{
|
||||
|
@ -16,6 +17,13 @@ use crate::{
|
|||
// Options accepted for the `balance` command
|
||||
#[derive(Debug, Options)]
|
||||
pub(crate) struct Command {
|
||||
#[options(
|
||||
free,
|
||||
required,
|
||||
help = "the UUID of the account for which to get a balance"
|
||||
)]
|
||||
account_id: Uuid,
|
||||
|
||||
#[options(help = "Convert ZEC values into the given currency")]
|
||||
convert: Option<Currency>,
|
||||
}
|
||||
|
@ -26,10 +34,7 @@ impl Command {
|
|||
|
||||
let (_, db_data) = get_db_paths(wallet_dir.as_ref());
|
||||
let db_data = WalletDb::for_path(db_data, params)?;
|
||||
let account_id = *db_data
|
||||
.get_account_ids()?
|
||||
.first()
|
||||
.ok_or(anyhow!("Wallet has no accounts"))?;
|
||||
let account_id = AccountUuid::from_uuid(self.account_id);
|
||||
|
||||
let address = db_data
|
||||
.get_current_address(account_id)?
|
||||
|
|
|
@ -1,18 +1,26 @@
|
|||
use anyhow::anyhow;
|
||||
use gumdrop::Options;
|
||||
|
||||
use uuid::Uuid;
|
||||
use zcash_client_backend::{
|
||||
data_api::{InputSource, WalletRead},
|
||||
ShieldedProtocol,
|
||||
};
|
||||
use zcash_client_sqlite::WalletDb;
|
||||
use zcash_client_sqlite::{AccountUuid, WalletDb};
|
||||
use zcash_protocol::value::{Zatoshis, MAX_MONEY};
|
||||
|
||||
use crate::{config::get_wallet_network, data::get_db_paths, error, ui::format_zec};
|
||||
|
||||
// Options accepted for the `balance` command
|
||||
// Options accepted for the `list-unspent` command
|
||||
#[derive(Debug, Options)]
|
||||
pub(crate) struct Command {}
|
||||
pub(crate) struct Command {
|
||||
#[options(
|
||||
free,
|
||||
required,
|
||||
help = "the UUID of the account for which to list unspent funds"
|
||||
)]
|
||||
account_id: Uuid,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub(crate) fn run(self, wallet_dir: Option<String>) -> Result<(), anyhow::Error> {
|
||||
|
@ -20,10 +28,7 @@ impl Command {
|
|||
|
||||
let (_, db_data) = get_db_paths(wallet_dir);
|
||||
let db_data = WalletDb::for_path(db_data, params)?;
|
||||
let account = *db_data
|
||||
.get_account_ids()?
|
||||
.first()
|
||||
.ok_or(anyhow!("Wallet has no accounts"))?;
|
||||
let account_id = AccountUuid::from_uuid(self.account_id);
|
||||
|
||||
// Use the height of the maximum scanned block as the anchor height, to emulate a
|
||||
// zero-conf transaction in order to select every note in the wallet.
|
||||
|
@ -34,7 +39,7 @@ impl Command {
|
|||
.block_height();
|
||||
|
||||
let notes = db_data.select_spendable_notes(
|
||||
account,
|
||||
account_id,
|
||||
Zatoshis::const_from_u64(MAX_MONEY),
|
||||
&[ShieldedProtocol::Sapling, ShieldedProtocol::Orchard],
|
||||
anchor_height,
|
||||
|
|
|
@ -5,6 +5,7 @@ pub(crate) mod create;
|
|||
pub(crate) mod inspect;
|
||||
pub(crate) mod prove;
|
||||
pub(crate) mod send;
|
||||
pub(crate) mod shield;
|
||||
pub(crate) mod sign;
|
||||
|
||||
#[cfg(feature = "pczt-qr")]
|
||||
|
@ -14,6 +15,8 @@ pub(crate) mod qr;
|
|||
pub(crate) enum Command {
|
||||
#[options(help = "create a PCZT")]
|
||||
Create(create::Command),
|
||||
#[options(help = "create a shielding PCZT")]
|
||||
Shield(shield::Command),
|
||||
#[options(help = "inspect a PCZT")]
|
||||
Inspect(inspect::Command),
|
||||
#[options(help = "create proofs for a PCZT")]
|
||||
|
|
|
@ -5,19 +5,17 @@ use anyhow::anyhow;
|
|||
use gumdrop::Options;
|
||||
|
||||
use tokio::io::{stdout, AsyncWriteExt};
|
||||
use uuid::Uuid;
|
||||
use zcash_address::ZcashAddress;
|
||||
use zcash_client_backend::{
|
||||
data_api::{
|
||||
wallet::{
|
||||
create_pczt_from_proposal, input_selection::GreedyInputSelector, propose_transfer,
|
||||
},
|
||||
WalletRead,
|
||||
data_api::wallet::{
|
||||
create_pczt_from_proposal, input_selection::GreedyInputSelector, propose_transfer,
|
||||
},
|
||||
fees::{standard::MultiOutputChangeStrategy, DustOutputPolicy, SplitPolicy, StandardFeeRule},
|
||||
wallet::OvkPolicy,
|
||||
ShieldedProtocol,
|
||||
};
|
||||
use zcash_client_sqlite::WalletDb;
|
||||
use zcash_client_sqlite::{AccountUuid, WalletDb};
|
||||
use zcash_protocol::{
|
||||
memo::{Memo, MemoBytes},
|
||||
value::Zatoshis,
|
||||
|
@ -29,6 +27,9 @@ use crate::{config::WalletConfig, data::get_db_paths, error, MIN_CONFIRMATIONS};
|
|||
// Options accepted for the `pczt create` command
|
||||
#[derive(Debug, Options)]
|
||||
pub(crate) struct Command {
|
||||
#[options(free, required, help = "the UUID of the account to send funds from")]
|
||||
account_id: Uuid,
|
||||
|
||||
#[options(
|
||||
required,
|
||||
help = "the recipient's Unified, Sapling or transparent address"
|
||||
|
@ -61,10 +62,7 @@ impl Command {
|
|||
|
||||
let (_, db_data) = get_db_paths(wallet_dir.as_ref());
|
||||
let mut db_data = WalletDb::for_path(db_data, params)?;
|
||||
let account_id = *db_data
|
||||
.get_account_ids()?
|
||||
.first()
|
||||
.ok_or(anyhow!("Wallet has no accounts"))?;
|
||||
let account_id = AccountUuid::from_uuid(self.account_id);
|
||||
|
||||
// Create the PCZT.
|
||||
let change_strategy = MultiOutputChangeStrategy::new(
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
use std::num::NonZeroUsize;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use gumdrop::Options;
|
||||
|
||||
use tokio::io::{stdout, AsyncWriteExt};
|
||||
use uuid::Uuid;
|
||||
use zcash_client_backend::{
|
||||
data_api::{
|
||||
wallet::{
|
||||
create_pczt_from_proposal, input_selection::GreedyInputSelector, propose_shielding,
|
||||
},
|
||||
WalletRead,
|
||||
},
|
||||
fees::{standard::MultiOutputChangeStrategy, DustOutputPolicy, SplitPolicy, StandardFeeRule},
|
||||
wallet::OvkPolicy,
|
||||
ShieldedProtocol,
|
||||
};
|
||||
use zcash_client_sqlite::{AccountUuid, WalletDb};
|
||||
use zcash_protocol::value::Zatoshis;
|
||||
|
||||
use crate::{config::WalletConfig, data::get_db_paths, error};
|
||||
|
||||
// Options accepted for the `pczt shield` command
|
||||
#[derive(Debug, Options)]
|
||||
pub(crate) struct Command {
|
||||
#[options(free, required, help = "the UUID of the account to shield funds in")]
|
||||
account_id: Uuid,
|
||||
|
||||
#[options(
|
||||
help = "note management: the number of notes to maintain in the wallet",
|
||||
default = "4"
|
||||
)]
|
||||
target_note_count: usize,
|
||||
|
||||
#[options(
|
||||
help = "note management: the minimum allowed value for split change amounts",
|
||||
default = "10000000"
|
||||
)]
|
||||
min_split_output_value: u64,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub(crate) async fn run(self, wallet_dir: Option<String>) -> Result<(), anyhow::Error> {
|
||||
let config = WalletConfig::read(wallet_dir.as_ref())?;
|
||||
let params = config.network();
|
||||
|
||||
let (_, db_data) = get_db_paths(wallet_dir.as_ref());
|
||||
let mut db_data = WalletDb::for_path(db_data, params)?;
|
||||
let account_id = AccountUuid::from_uuid(self.account_id);
|
||||
|
||||
// Create the PCZT.
|
||||
let change_strategy = MultiOutputChangeStrategy::new(
|
||||
StandardFeeRule::Zip317,
|
||||
None,
|
||||
ShieldedProtocol::Orchard,
|
||||
DustOutputPolicy::default(),
|
||||
SplitPolicy::with_min_output_value(
|
||||
NonZeroUsize::new(self.target_note_count)
|
||||
.ok_or(anyhow!("target note count must be nonzero"))?,
|
||||
Zatoshis::from_u64(self.min_split_output_value)?,
|
||||
),
|
||||
);
|
||||
let input_selector = GreedyInputSelector::new();
|
||||
|
||||
// For this dev tool, shield all funds immediately.
|
||||
let max_height = match db_data.chain_height()? {
|
||||
Some(max_height) => max_height,
|
||||
// If we haven't scanned anything, there's nothing to do.
|
||||
None => return Ok(()),
|
||||
};
|
||||
let transparent_balances = db_data.get_transparent_balances(account_id, max_height)?;
|
||||
let from_addrs = transparent_balances.into_keys().collect::<Vec<_>>();
|
||||
|
||||
let proposal = propose_shielding(
|
||||
&mut db_data,
|
||||
¶ms,
|
||||
&input_selector,
|
||||
&change_strategy,
|
||||
Zatoshis::ZERO,
|
||||
&from_addrs,
|
||||
account_id,
|
||||
0,
|
||||
)
|
||||
.map_err(error::Error::Shield)?;
|
||||
|
||||
let pczt = create_pczt_from_proposal(
|
||||
&mut db_data,
|
||||
¶ms,
|
||||
account_id,
|
||||
OvkPolicy::Sender,
|
||||
&proposal,
|
||||
)
|
||||
.map_err(error::Error::Shield)?;
|
||||
|
||||
stdout().write_all(&pczt.serialize()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -3,16 +3,14 @@ use std::{num::NonZeroUsize, str::FromStr};
|
|||
use anyhow::anyhow;
|
||||
use gumdrop::Options;
|
||||
|
||||
use uuid::Uuid;
|
||||
use zcash_address::ZcashAddress;
|
||||
use zcash_client_backend::{
|
||||
data_api::{
|
||||
wallet::{input_selection::GreedyInputSelector, propose_transfer},
|
||||
WalletRead,
|
||||
},
|
||||
data_api::wallet::{input_selection::GreedyInputSelector, propose_transfer},
|
||||
fees::{zip317::MultiOutputChangeStrategy, DustOutputPolicy, SplitPolicy, StandardFeeRule},
|
||||
ShieldedProtocol,
|
||||
};
|
||||
use zcash_client_sqlite::WalletDb;
|
||||
use zcash_client_sqlite::{AccountUuid, WalletDb};
|
||||
use zcash_protocol::value::Zatoshis;
|
||||
use zip321::{Payment, TransactionRequest};
|
||||
|
||||
|
@ -20,6 +18,9 @@ use crate::{config::get_wallet_network, data::get_db_paths, error, MIN_CONFIRMAT
|
|||
// Options accepted for the `propose` command
|
||||
#[derive(Debug, Options)]
|
||||
pub(crate) struct Command {
|
||||
#[options(free, required, help = "the UUID of the account to send funds from")]
|
||||
account_id: Uuid,
|
||||
|
||||
#[options(
|
||||
required,
|
||||
help = "the recipient's Unified, Sapling or transparent address"
|
||||
|
@ -48,10 +49,7 @@ impl Command {
|
|||
|
||||
let (_, db_data) = get_db_paths(wallet_dir.as_ref());
|
||||
let mut db_data = WalletDb::for_path(db_data, params)?;
|
||||
let account = *db_data
|
||||
.get_account_ids()?
|
||||
.first()
|
||||
.ok_or_else(|| anyhow!("Wallet has no accounts."))?;
|
||||
let account_id = AccountUuid::from_uuid(self.account_id);
|
||||
|
||||
let change_strategy = MultiOutputChangeStrategy::new(
|
||||
StandardFeeRule::Zip317,
|
||||
|
@ -75,7 +73,7 @@ impl Command {
|
|||
let proposal = propose_transfer(
|
||||
&mut db_data,
|
||||
¶ms,
|
||||
account,
|
||||
account_id,
|
||||
&input_selector,
|
||||
&change_strategy,
|
||||
request,
|
||||
|
|
|
@ -5,6 +5,7 @@ use anyhow::anyhow;
|
|||
use gumdrop::Options;
|
||||
use secrecy::ExposeSecret;
|
||||
|
||||
use uuid::Uuid;
|
||||
use zcash_address::ZcashAddress;
|
||||
use zcash_client_backend::{
|
||||
data_api::{
|
||||
|
@ -19,7 +20,7 @@ use zcash_client_backend::{
|
|||
wallet::OvkPolicy,
|
||||
ShieldedProtocol,
|
||||
};
|
||||
use zcash_client_sqlite::WalletDb;
|
||||
use zcash_client_sqlite::{AccountUuid, WalletDb};
|
||||
use zcash_proofs::prover::LocalTxProver;
|
||||
use zcash_protocol::value::Zatoshis;
|
||||
use zip321::{Payment, TransactionRequest};
|
||||
|
@ -35,6 +36,9 @@ use crate::{
|
|||
// Options accepted for the `send` command
|
||||
#[derive(Debug, Options)]
|
||||
pub(crate) struct Command {
|
||||
#[options(free, required, help = "the UUID of the account to send funds from")]
|
||||
account_id: Uuid,
|
||||
|
||||
#[options(
|
||||
required,
|
||||
help = "age identity file to decrypt the mnemonic phrase with"
|
||||
|
@ -80,10 +84,7 @@ impl Command {
|
|||
|
||||
let (_, db_data) = get_db_paths(wallet_dir.as_ref());
|
||||
let mut db_data = WalletDb::for_path(db_data, params)?;
|
||||
let account_id = *db_data
|
||||
.get_account_ids()?
|
||||
.first()
|
||||
.ok_or(anyhow!("Wallet has no accounts"))?;
|
||||
let account_id = AccountUuid::from_uuid(self.account_id);
|
||||
let account = db_data
|
||||
.get_account(account_id)?
|
||||
.ok_or(anyhow!("Account missing: {:?}", account_id))?;
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
use std::num::NonZeroUsize;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use gumdrop::Options;
|
||||
use secrecy::ExposeSecret;
|
||||
|
||||
use uuid::Uuid;
|
||||
use zcash_client_backend::{
|
||||
data_api::{
|
||||
wallet::{
|
||||
create_proposed_transactions, input_selection::GreedyInputSelector, propose_shielding,
|
||||
},
|
||||
Account, WalletRead,
|
||||
},
|
||||
fees::{standard::MultiOutputChangeStrategy, DustOutputPolicy, SplitPolicy, StandardFeeRule},
|
||||
keys::UnifiedSpendingKey,
|
||||
proto::service,
|
||||
wallet::OvkPolicy,
|
||||
ShieldedProtocol,
|
||||
};
|
||||
use zcash_client_sqlite::{AccountUuid, WalletDb};
|
||||
use zcash_proofs::prover::LocalTxProver;
|
||||
use zcash_protocol::value::Zatoshis;
|
||||
|
||||
use crate::{
|
||||
config::WalletConfig,
|
||||
data::get_db_paths,
|
||||
error,
|
||||
remote::{tor_client, Servers},
|
||||
};
|
||||
|
||||
// Options accepted for the `shield` command
|
||||
#[derive(Debug, Options)]
|
||||
pub(crate) struct Command {
|
||||
#[options(free, required, help = "the UUID of the account to shield funds in")]
|
||||
account_id: Uuid,
|
||||
|
||||
#[options(
|
||||
required,
|
||||
help = "age identity file to decrypt the mnemonic phrase with"
|
||||
)]
|
||||
identity: String,
|
||||
|
||||
#[options(
|
||||
help = "the server to shield via (default is \"ecc\")",
|
||||
default = "ecc",
|
||||
parse(try_from_str = "Servers::parse")
|
||||
)]
|
||||
server: Servers,
|
||||
|
||||
#[options(help = "disable connections via TOR")]
|
||||
disable_tor: bool,
|
||||
|
||||
#[options(
|
||||
help = "note management: the number of notes to maintain in the wallet",
|
||||
default = "4"
|
||||
)]
|
||||
target_note_count: usize,
|
||||
|
||||
#[options(
|
||||
help = "note management: the minimum allowed value for split change amounts",
|
||||
default = "10000000"
|
||||
)]
|
||||
min_split_output_value: u64,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub(crate) async fn run(self, wallet_dir: Option<String>) -> Result<(), anyhow::Error> {
|
||||
let mut config = WalletConfig::read(wallet_dir.as_ref())?;
|
||||
let params = config.network();
|
||||
|
||||
let (_, db_data) = get_db_paths(wallet_dir.as_ref());
|
||||
let mut db_data = WalletDb::for_path(db_data, params)?;
|
||||
let account_id = AccountUuid::from_uuid(self.account_id);
|
||||
let account = db_data
|
||||
.get_account(account_id)?
|
||||
.ok_or(anyhow!("Account missing: {:?}", account_id))?;
|
||||
let derivation = account.source().key_derivation().ok_or(anyhow!(
|
||||
"Cannot spend from view-only accounts; did you mean to use `pczt shield` instead?"
|
||||
))?;
|
||||
|
||||
// Decrypt the mnemonic to access the seed.
|
||||
let identities = age::IdentityFile::from_file(self.identity)?.into_identities()?;
|
||||
config.decrypt(identities.iter().map(|i| i.as_ref() as _))?;
|
||||
|
||||
let usk = UnifiedSpendingKey::from_seed(
|
||||
¶ms,
|
||||
config
|
||||
.seed()
|
||||
.ok_or(anyhow!("Seed must be present to enable sending"))?
|
||||
.expose_secret(),
|
||||
derivation.account_index(),
|
||||
)
|
||||
.map_err(error::Error::from)?;
|
||||
|
||||
let server = self.server.pick(params)?;
|
||||
let mut client = if self.disable_tor {
|
||||
server.connect_direct().await?
|
||||
} else {
|
||||
server.connect(|| tor_client(wallet_dir.as_ref())).await?
|
||||
};
|
||||
|
||||
// Create the transaction.
|
||||
println!("Creating transaction...");
|
||||
let prover =
|
||||
LocalTxProver::with_default_location().ok_or(error::Error::MissingParameters)?;
|
||||
let change_strategy = MultiOutputChangeStrategy::new(
|
||||
StandardFeeRule::Zip317,
|
||||
None,
|
||||
ShieldedProtocol::Orchard,
|
||||
DustOutputPolicy::default(),
|
||||
SplitPolicy::with_min_output_value(
|
||||
NonZeroUsize::new(self.target_note_count)
|
||||
.ok_or(anyhow!("target note count must be nonzero"))?,
|
||||
Zatoshis::from_u64(self.min_split_output_value)?,
|
||||
),
|
||||
);
|
||||
let input_selector = GreedyInputSelector::new();
|
||||
|
||||
// For this dev tool, shield all funds immediately.
|
||||
let max_height = match db_data.chain_height()? {
|
||||
Some(max_height) => max_height,
|
||||
// If we haven't scanned anything, there's nothing to do.
|
||||
None => return Ok(()),
|
||||
};
|
||||
let transparent_balances = db_data.get_transparent_balances(account_id, max_height)?;
|
||||
let from_addrs = transparent_balances.into_keys().collect::<Vec<_>>();
|
||||
|
||||
let proposal = propose_shielding(
|
||||
&mut db_data,
|
||||
¶ms,
|
||||
&input_selector,
|
||||
&change_strategy,
|
||||
Zatoshis::ZERO,
|
||||
&from_addrs,
|
||||
account_id,
|
||||
0,
|
||||
)
|
||||
.map_err(error::Error::Shield)?;
|
||||
|
||||
let txids = create_proposed_transactions(
|
||||
&mut db_data,
|
||||
¶ms,
|
||||
&prover,
|
||||
&prover,
|
||||
&usk,
|
||||
OvkPolicy::Sender,
|
||||
&proposal,
|
||||
)
|
||||
.map_err(error::Error::Shield)?;
|
||||
|
||||
if txids.len() > 1 {
|
||||
return Err(anyhow!(
|
||||
"Multi-transaction proposals are not yet supported."
|
||||
));
|
||||
}
|
||||
|
||||
let txid = *txids.first();
|
||||
|
||||
// Send the transaction.
|
||||
println!("Sending transaction...");
|
||||
let (txid, raw_tx) = db_data
|
||||
.get_transaction(txid)?
|
||||
.map(|tx| {
|
||||
let mut raw_tx = service::RawTransaction::default();
|
||||
tx.write(&mut raw_tx.data).unwrap();
|
||||
(tx.txid(), raw_tx)
|
||||
})
|
||||
.ok_or(anyhow!("Transaction not found for id {:?}", txid))?;
|
||||
let response = client.send_transaction(raw_tx).await?.into_inner();
|
||||
|
||||
if response.error_code != 0 {
|
||||
Err(error::Error::SendFailed {
|
||||
code: response.error_code,
|
||||
reason: response.error_message,
|
||||
}
|
||||
.into())
|
||||
} else {
|
||||
println!("{}", txid);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
12
src/error.rs
12
src/error.rs
|
@ -1,3 +1,4 @@
|
|||
use std::convert::Infallible;
|
||||
use std::fmt;
|
||||
|
||||
use zcash_client_backend::{
|
||||
|
@ -22,6 +23,15 @@ pub(crate) type WalletErrorT = WalletError<
|
|||
ReceivedNoteId,
|
||||
>;
|
||||
|
||||
pub(crate) type ShieldErrorT = WalletError<
|
||||
SqliteClientError,
|
||||
commitment_tree::Error,
|
||||
GreedyInputSelectorError,
|
||||
zip317::FeeError,
|
||||
zip317::FeeError,
|
||||
Infallible,
|
||||
>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Cache(FsBlockDbError),
|
||||
|
@ -32,6 +42,7 @@ pub enum Error {
|
|||
InvalidTreeState,
|
||||
MissingParameters,
|
||||
SendFailed { code: i32, reason: String },
|
||||
Shield(ShieldErrorT),
|
||||
Wallet(WalletErrorT),
|
||||
Zip321(Zip321Error),
|
||||
}
|
||||
|
@ -47,6 +58,7 @@ impl fmt::Display for Error {
|
|||
Error::InvalidTreeState => write!(f, "Invalid TreeState received from server"),
|
||||
Error::MissingParameters => write!(f, "Missing proving parameters"),
|
||||
Error::SendFailed { code, reason } => write!(f, "Send failed: ({}) {}", code, reason),
|
||||
Error::Shield(e) => e.fmt(f),
|
||||
Error::Wallet(e) => e.fmt(f),
|
||||
Error::Zip321(e) => write!(f, "{:?}", e),
|
||||
}
|
||||
|
|
|
@ -73,6 +73,9 @@ enum Command {
|
|||
#[options(help = "list the unspent notes in the wallet")]
|
||||
ListUnspent(commands::list_unspent::Command),
|
||||
|
||||
#[options(help = "shield transparent funds received by the wallet")]
|
||||
Shield(commands::shield::Command),
|
||||
|
||||
#[options(help = "propose a transfer of funds to the given address and display the proposal")]
|
||||
Propose(commands::propose::Command),
|
||||
|
||||
|
@ -165,10 +168,12 @@ fn main() -> Result<(), anyhow::Error> {
|
|||
Some(Command::ListAddresses(command)) => command.run(opts.wallet_dir),
|
||||
Some(Command::ListTx(command)) => command.run(opts.wallet_dir),
|
||||
Some(Command::ListUnspent(command)) => command.run(opts.wallet_dir),
|
||||
Some(Command::Shield(command)) => command.run(opts.wallet_dir).await,
|
||||
Some(Command::Propose(command)) => command.run(opts.wallet_dir).await,
|
||||
Some(Command::Send(command)) => command.run(opts.wallet_dir).await,
|
||||
Some(Command::Pczt(command)) => match command {
|
||||
commands::pczt::Command::Create(command) => command.run(opts.wallet_dir).await,
|
||||
commands::pczt::Command::Shield(command) => command.run(opts.wallet_dir).await,
|
||||
commands::pczt::Command::Inspect(command) => command.run().await,
|
||||
commands::pczt::Command::Prove(command) => command.run(opts.wallet_dir).await,
|
||||
commands::pczt::Command::Sign(command) => command.run(opts.wallet_dir).await,
|
||||
|
|
Loading…
Reference in New Issue