use crate::wallet::send::SendProgress;
use super::LightClient;
impl LightClient {
pub async fn send_progress(&self) -> SendProgress {
self.wallet.lock().await.send_progress.clone()
}
}
pub mod send_with_proposal {
use std::convert::Infallible;
use nonempty::NonEmpty;
use zcash_client_backend::proposal::Proposal;
use zcash_client_backend::zip321::TransactionRequest;
use zcash_primitives::transaction::TxId;
use zcash_primitives::transaction::fees::zip317;
use crate::data::proposal::ZingoProposal;
use crate::lightclient::LightClient;
use crate::lightclient::error::{QuickSendError, QuickShieldError, SendError};
use crate::wallet::error::TransmissionError;
use crate::wallet::output::OutputRef;
impl LightClient {
async fn send(
&mut self,
proposal: &Proposal<zip317::FeeRule, OutputRef>,
) -> Result<NonEmpty<TxId>, SendError> {
let mut wallet = self.wallet.lock().await;
let calculated_txids = wallet
.calculate_transactions(proposal)
.await
.map_err(SendError::CalculateSendError)?;
self.latest_proposal = None;
Ok(wallet
.transmit_transactions(self.get_server_uri(), calculated_txids)
.await?)
}
async fn shield(
&mut self,
proposal: &Proposal<zip317::FeeRule, Infallible>,
) -> Result<NonEmpty<TxId>, SendError> {
let mut wallet = self.wallet.lock().await;
let calculated_txids = wallet
.calculate_transactions(proposal)
.await
.map_err(SendError::CalculateShieldError)?;
self.latest_proposal = None;
Ok(wallet
.transmit_transactions(self.get_server_uri(), calculated_txids)
.await?)
}
pub async fn resend(&self, txid: TxId) -> Result<(), TransmissionError> {
self.wallet
.lock()
.await
.transmit_transactions(self.get_server_uri(), NonEmpty::singleton(txid))
.await?;
Ok(())
}
pub async fn send_stored_proposal(&mut self) -> Result<NonEmpty<TxId>, SendError> {
if let Some(proposal) = self.latest_proposal.clone() {
match proposal {
ZingoProposal::Transfer(transfer_proposal) => {
self.send(&transfer_proposal).await
}
ZingoProposal::Shield(shield_proposal) => self.shield(&shield_proposal).await,
}
} else {
Err(SendError::NoStoredProposal)
}
}
pub async fn quick_send(
&mut self,
request: TransactionRequest,
) -> Result<NonEmpty<TxId>, QuickSendError> {
let proposal = self
.wallet
.lock()
.await
.create_send_proposal(request)
.await?;
Ok(self.send(&proposal).await?)
}
pub async fn quick_shield(&mut self) -> Result<NonEmpty<TxId>, QuickShieldError> {
let proposal = self.wallet.lock().await.create_shield_proposal().await?;
Ok(self.shield(&proposal).await?)
}
}
#[cfg(test)]
mod test {
use pepper_sync::sync::SyncConfig;
use crate::{
lightclient::sync::test::sync_example_wallet,
testutils::chain_generics::{
conduct_chain::ConductChain as _, live_chain::LiveChain, with_assertions,
},
wallet::{LightWallet, WalletBase, WalletSettings, disk::testing::examples},
};
#[tokio::test]
async fn complete_and_broadcast_unconnected_error() {
use crate::{
config::ZingoConfigBuilder, lightclient::LightClient,
mocks::proposal::ProposalBuilder,
};
use testvectors::seeds::ABANDON_ART_SEED;
let config = ZingoConfigBuilder::default().create();
let mut lc = LightClient::create_from_wallet(
LightWallet::new(
config.chain,
WalletBase::MnemonicPhrase(ABANDON_ART_SEED.to_string()),
1.into(),
WalletSettings {
sync_config: SyncConfig {
transparent_address_discovery:
pepper_sync::sync::TransparentAddressDiscovery::minimal(),
},
},
)
.unwrap(),
config,
true,
)
.unwrap();
let proposal = ProposalBuilder::default().build();
lc.send(&proposal).await.unwrap_err();
}
mod testnet {
use zcash_protocol::{PoolType, ShieldedProtocol};
use crate::testutils::lightclient::get_base_address;
use super::*;
#[ignore = "live testnet: testnet relies on NU6"]
#[tokio::test]
async fn glory_goddess_simple_send() {
let case = examples::NetworkSeedVersion::Testnet(
examples::TestnetSeedVersion::GloryGoddess,
);
let mut client = sync_example_wallet(case).await;
with_assertions::assure_propose_shield_bump_sync(
&mut LiveChain::setup().await,
&mut client,
true,
)
.await
.unwrap();
}
#[ignore = "live testnet: testnet relies on NU6"]
#[tokio::test]
async fn testnet_send_to_self_orchard() {
let case = examples::NetworkSeedVersion::Testnet(
examples::TestnetSeedVersion::ChimneyBetter(
examples::ChimneyBetterVersion::Latest,
),
);
let mut client = sync_example_wallet(case).await;
let client_addr =
get_base_address(&client, PoolType::Shielded(ShieldedProtocol::Orchard)).await;
with_assertions::propose_send_bump_sync_all_recipients(
&mut LiveChain::setup().await,
&mut client,
vec![(&client_addr, 10_000, None)],
vec![],
false,
)
.await
.unwrap();
}
#[ignore = "live testnet: testnet relies on NU6"]
#[tokio::test]
async fn testnet_shield() {
let case = examples::NetworkSeedVersion::Testnet(
examples::TestnetSeedVersion::ChimneyBetter(
examples::ChimneyBetterVersion::Latest,
),
);
let mut client = sync_example_wallet(case).await;
with_assertions::assure_propose_shield_bump_sync(
&mut LiveChain::setup().await,
&mut client,
true,
)
.await
.unwrap();
}
}
mod mainnet {
use zcash_protocol::{PoolType, ShieldedProtocol};
use crate::testutils::lightclient::get_base_address;
use super::*;
#[tokio::test]
#[ignore = "dont automatically run hot tests! this test spends actual zec!"]
async fn mainnet_send_to_self_orchard() {
let case = examples::NetworkSeedVersion::Mainnet(
examples::MainnetSeedVersion::HotelHumor(examples::HotelHumorVersion::Latest),
);
let mut client = sync_example_wallet(case).await;
let client_addr =
get_base_address(&client, PoolType::Shielded(ShieldedProtocol::Orchard)).await;
with_assertions::propose_send_bump_sync_all_recipients(
&mut LiveChain::setup().await,
&mut client,
vec![(&client_addr, 10_000, None)],
vec![],
false,
)
.await
.unwrap();
}
#[tokio::test]
#[ignore = "dont automatically run hot tests! this test spends actual zec!"]
async fn mainnet_send_to_self_sapling() {
let case = examples::NetworkSeedVersion::Mainnet(
examples::MainnetSeedVersion::HotelHumor(examples::HotelHumorVersion::Latest),
);
let mut client = sync_example_wallet(case).await;
let client_addr =
get_base_address(&client, PoolType::Shielded(ShieldedProtocol::Sapling)).await;
with_assertions::propose_send_bump_sync_all_recipients(
&mut LiveChain::setup().await,
&mut client,
vec![(&client_addr, 400_000, None)],
vec![],
false,
)
.await
.unwrap();
}
#[tokio::test]
#[ignore = "dont automatically run hot tests! this test spends actual zec!"]
async fn mainnet_send_to_self_transparent_and_then_shield() {
let case = examples::NetworkSeedVersion::Mainnet(
examples::MainnetSeedVersion::HotelHumor(examples::HotelHumorVersion::Latest),
);
let mut client = sync_example_wallet(case).await;
let client_addr = get_base_address(&client, PoolType::Transparent).await;
with_assertions::propose_send_bump_sync_all_recipients(
&mut LiveChain::setup().await,
&mut client,
vec![(&client_addr, 400_000, None)],
vec![],
false,
)
.await
.unwrap();
with_assertions::assure_propose_shield_bump_sync(
&mut LiveChain::setup().await,
&mut client,
false,
)
.await
.unwrap();
}
}
}
}