From fc368d887536b525beaa3d4685053c2f738ff130 Mon Sep 17 00:00:00 2001 From: Willem Olding Date: Mon, 30 Sep 2024 11:25:00 -0400 Subject: [PATCH 1/9] fix fmt and clippy --- src/lib.rs | 2 -- src/wallet.rs | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b17b3d0..7781cbf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,11 +8,9 @@ pub mod bindgen; #[cfg(feature = "wasm")] pub use bindgen::wallet::WebWallet; - pub mod error; pub mod init; - pub mod wallet; pub use wallet::Wallet; diff --git a/src/wallet.rs b/src/wallet.rs index bb4f90c..71cc1cc 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -80,8 +80,8 @@ impl Clone for Wallet { Self { db: self.db.clone(), client: self.client.clone(), - network: self.network.clone(), - min_confirmations: self.min_confirmations.clone(), + network: self.network, + min_confirmations: self.min_confirmations, } } } From 88e65e4ed9a63b6e3146cddc373678263a7364c4 Mon Sep 17 00:00:00 2001 From: Willem Olding Date: Mon, 30 Sep 2024 12:23:33 -0400 Subject: [PATCH 2/9] remove account_index from the api --- Cargo.lock | 24 ++++++++++++------------ Cargo.toml | 14 +++++++------- src/bindgen/wallet.rs | 37 ++++++++++++++++++++++++------------- src/lib.rs | 4 ---- src/wallet.rs | 36 ++++++++++++++++-------------------- 5 files changed, 59 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8147d46..9d23467 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -806,7 +806,7 @@ checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" [[package]] name = "equihash" version = "0.2.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4#b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4" +source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" dependencies = [ "blake2b_simd", "byteorder", @@ -858,7 +858,7 @@ dependencies = [ [[package]] name = "f4jumble" version = "0.1.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4#b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4" +source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" dependencies = [ "blake2b_simd", ] @@ -3648,7 +3648,7 @@ dependencies = [ [[package]] name = "zcash_address" version = "0.5.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4#b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4" +source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" dependencies = [ "bech32", "bs58", @@ -3660,7 +3660,7 @@ dependencies = [ [[package]] name = "zcash_client_backend" version = "0.13.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4#b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4" +source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" dependencies = [ "async-trait", "base64", @@ -3706,7 +3706,7 @@ dependencies = [ [[package]] name = "zcash_client_memory" version = "0.1.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4#b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4" +source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" dependencies = [ "async-trait", "bs58", @@ -3741,7 +3741,7 @@ dependencies = [ [[package]] name = "zcash_client_sqlite" version = "0.11.2" -source = "git+https://github.com/ChainSafe/librustzcash?rev=b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4#b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4" +source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" dependencies = [ "bs58", "byteorder", @@ -3777,7 +3777,7 @@ dependencies = [ [[package]] name = "zcash_encoding" version = "0.2.1" -source = "git+https://github.com/ChainSafe/librustzcash?rev=b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4#b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4" +source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" dependencies = [ "byteorder", "nonempty", @@ -3786,7 +3786,7 @@ dependencies = [ [[package]] name = "zcash_keys" version = "0.3.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4#b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4" +source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" dependencies = [ "bech32", "bip32", @@ -3827,7 +3827,7 @@ dependencies = [ [[package]] name = "zcash_primitives" version = "0.17.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4#b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4" +source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" dependencies = [ "aes", "bip32", @@ -3865,7 +3865,7 @@ dependencies = [ [[package]] name = "zcash_proofs" version = "0.17.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4#b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4" +source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" dependencies = [ "bellman", "blake2b_simd", @@ -3885,7 +3885,7 @@ dependencies = [ [[package]] name = "zcash_protocol" version = "0.3.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4#b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4" +source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" dependencies = [ "document-features", "memuse", @@ -3954,7 +3954,7 @@ dependencies = [ [[package]] name = "zip321" version = "0.1.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4#b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4" +source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" dependencies = [ "base64", "nom", diff --git a/Cargo.toml b/Cargo.toml index 3881961..69da9c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,12 +61,12 @@ tokio_with_wasm = { version = "0.7.1", features = ["rt", "rt-multi-thread", "syn ## Zcash dependencies -zcash_keys = { git = "https://github.com/ChainSafe/librustzcash", rev = "b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4", features = ["transparent-inputs", "orchard", "sapling", "unstable"] } -zcash_client_backend = { git = "https://github.com/ChainSafe/librustzcash", rev = "b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4", default-features = false, features = ["sync", "lightwalletd-tonic", "wasm-bindgen", "orchard"] } -zcash_client_memory = { git = "https://github.com/ChainSafe/librustzcash", rev = "b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4", features = ["orchard"] } -zcash_primitives = { git = "https://github.com/ChainSafe/librustzcash", rev = "b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4" } -zcash_address = { git = "https://github.com/ChainSafe/librustzcash", rev = "b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4" } -zcash_proofs = { git = "https://github.com/ChainSafe/librustzcash", rev = "b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4", default-features = false, features = ["bundled-prover"] } +zcash_keys = { git = "https://github.com/ChainSafe/librustzcash", rev = "d1fa3e846c5e61de3f1df23dd9f4d5416915631a", features = ["transparent-inputs", "orchard", "sapling", "unstable"] } +zcash_client_backend = { git = "https://github.com/ChainSafe/librustzcash", rev = "d1fa3e846c5e61de3f1df23dd9f4d5416915631a", default-features = false, features = ["sync", "lightwalletd-tonic", "wasm-bindgen", "orchard"] } +zcash_client_memory = { git = "https://github.com/ChainSafe/librustzcash", rev = "d1fa3e846c5e61de3f1df23dd9f4d5416915631a", features = ["orchard"] } +zcash_primitives = { git = "https://github.com/ChainSafe/librustzcash", rev = "d1fa3e846c5e61de3f1df23dd9f4d5416915631a" } +zcash_address = { git = "https://github.com/ChainSafe/librustzcash", rev = "d1fa3e846c5e61de3f1df23dd9f4d5416915631a" } +zcash_proofs = { git = "https://github.com/ChainSafe/librustzcash", rev = "d1fa3e846c5e61de3f1df23dd9f4d5416915631a", default-features = false, features = ["bundled-prover"] } ## gRPC Web dependencies prost = { version = "0.12", default-features = false } @@ -77,7 +77,7 @@ tonic = { version = "0.12", default-features = false, features = [ # Used in Native tests tokio = { version = "1.0" } -zcash_client_sqlite = { git = "https://github.com/ChainSafe/librustzcash", rev = "b6d32dd9a57165fb1508e9c1c8ab1a3aba09c7f4", default-features = false, features = ["unstable", "orchard"], optional = true } +zcash_client_sqlite = { git = "https://github.com/ChainSafe/librustzcash", rev = "d1fa3e846c5e61de3f1df23dd9f4d5416915631a", default-features = false, features = ["unstable", "orchard"], optional = true } getrandom = { version = "0.2", features = ["js"] } thiserror = "1.0.63" diff --git a/src/bindgen/wallet.rs b/src/bindgen/wallet.rs index 0d0b1e7..927448d 100644 --- a/src/bindgen/wallet.rs +++ b/src/bindgen/wallet.rs @@ -1,4 +1,5 @@ use std::num::NonZeroU32; +use std::ops::Deref; use serde::{Deserialize, Serialize}; use wasm_bindgen::prelude::*; @@ -6,9 +7,10 @@ use wasm_bindgen::prelude::*; use tonic_web_wasm_client::Client; use crate::error::Error; -use crate::{BlockRange, MemoryWallet, Wallet, PRUNING_DEPTH}; +use crate::{BlockRange, Wallet, PRUNING_DEPTH}; use wasm_thread as thread; use zcash_address::ZcashAddress; +use zcash_client_backend::data_api::WalletRead; use zcash_client_backend::proto::service::{ compact_tx_streamer_client::CompactTxStreamerClient, ChainSpec, }; @@ -16,6 +18,10 @@ use zcash_client_memory::MemoryWalletDb; use zcash_keys::keys::UnifiedFullViewingKey; use zcash_primitives::consensus::{self, BlockHeight}; +pub type MemoryWallet = Wallet, T>; +pub type AccountId = + as WalletRead>::AccountId; + /// # A Zcash wallet /// /// A wallet is a set of accounts that can be synchronized together with the blockchain. @@ -87,30 +93,30 @@ impl WebWallet { /// /// # Arguments /// seed_phrase - mnemonic phrase to initialise the wallet - /// account_index - The HD derivation index to use. Can be any integer + /// account_hd_index - The HD derivation index to use. Can be any integer /// birthday_height - The block height at which the account was created, optionally None and the current height is used /// pub async fn create_account( &self, seed_phrase: &str, - account_index: u32, + account_hd_index: u32, birthday_height: Option, - ) -> Result { + ) -> Result { tracing::info!("Create account called"); self.inner - .create_account(seed_phrase, account_index, birthday_height) + .create_account(seed_phrase, account_hd_index, birthday_height) .await + .map(|id| *id) } - pub async fn import_ufvk( - &self, - key: &str, - birthday_height: Option, - ) -> Result { + pub async fn import_ufvk(&self, key: &str, birthday_height: Option) -> Result { let ufvk = UnifiedFullViewingKey::decode(&self.inner.network, key) .map_err(Error::KeyParseError)?; - self.inner.import_ufvk(&ufvk, birthday_height).await + self.inner + .import_ufvk(&ufvk, birthday_height) + .await + .map(|id| *id) } pub async fn suggest_scan_ranges(&self) -> Result, Error> { @@ -173,13 +179,18 @@ impl WebWallet { pub async fn transfer( &self, seed_phrase: &str, - from_account_index: usize, + from_account_id: u32, to_address: String, value: u64, ) -> Result<(), Error> { let to_address = ZcashAddress::try_from_encoded(&to_address)?; self.inner - .transfer(seed_phrase, from_account_index, to_address, value) + .transfer( + seed_phrase, + AccountId::from(from_account_id), + to_address, + value, + ) .await } diff --git a/src/lib.rs b/src/lib.rs index 7781cbf..eb7d33b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,8 +15,6 @@ pub mod wallet; pub use wallet::Wallet; use wasm_bindgen::prelude::*; -use zcash_client_memory::MemoryWalletDb; -use zcash_primitives::consensus; /// The maximum number of checkpoints to store in each shard-tree pub const PRUNING_DEPTH: usize = 100; @@ -30,5 +28,3 @@ pub fn init_thread_pool(_threads: usize) {} #[wasm_bindgen] pub struct BlockRange(pub u32, pub u32); - -pub type MemoryWallet = Wallet, T>; diff --git a/src/wallet.rs b/src/wallet.rs index 71cc1cc..cccdc0d 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -24,8 +24,8 @@ use zcash_client_backend::data_api::wallet::{ }; use zcash_client_backend::data_api::{scanning::ScanRange, WalletCommitmentTrees}; use zcash_client_backend::data_api::{ - AccountBirthday, AccountPurpose, InputSource, NullifierQuery, WalletRead, WalletSummary, - WalletWrite, + Account, AccountBirthday, AccountPurpose, InputSource, NullifierQuery, WalletRead, + WalletSummary, WalletWrite, }; use zcash_client_backend::fees::zip317::SingleOutputChangeStrategy; use zcash_client_backend::proposal::Proposal; @@ -143,17 +143,17 @@ where /// /// # Arguments /// seed_phrase - mnemonic phrase to initialise the wallet - /// account_index - The HD derivation index to use. Can be any integer + /// account_id - The HD derivation index to use. Can be any integer /// birthday_height - The block height at which the account was created, optionally None and the current height is used /// pub async fn create_account( &self, seed_phrase: &str, - account_index: u32, + account_hd_index: u32, birthday_height: Option, - ) -> Result { + ) -> Result { // decode the mnemonic and derive the first account - let usk = usk_from_seed_str(seed_phrase, account_index, &self.network)?; + let usk = usk_from_seed_str(seed_phrase, account_hd_index, &self.network)?; let ufvk = usk.to_unified_full_viewing_key(); tracing::info!("Key successfully decoded. Importing into wallet"); @@ -166,7 +166,7 @@ where &self, ufvk: &UnifiedFullViewingKey, birthday_height: Option, - ) -> Result { + ) -> Result { self.import_account_ufvk(ufvk, birthday_height, AccountPurpose::ViewOnly) .await } @@ -177,7 +177,7 @@ where ufvk: &UnifiedFullViewingKey, birthday_height: Option, purpose: AccountPurpose, - ) -> Result { + ) -> Result { tracing::info!("Importing account with Ufvk: {:?}", ufvk); let mut client = self.client.clone(); let birthday = match birthday_height { @@ -205,13 +205,12 @@ where AccountBirthday::from_treestate(treestate, None).map_err(|_| Error::BirthdayError)? }; - let _account = self + Ok(self .db .write() .await - .import_account_ufvk(ufvk, &birthday, purpose)?; - - Ok("0".to_string()) + .import_account_ufvk(ufvk, &birthday, purpose)? + .id()) } pub async fn suggest_scan_ranges(&self) -> Result, Error> { @@ -384,12 +383,10 @@ where /// async fn propose_transfer( &self, - account_index: usize, + account_id: AccountId, to_address: ZcashAddress, value: u64, ) -> Result, Error> { - let account_id = self.db.read().await.get_account_ids()?[account_index]; - let input_selector = GreedyInputSelector::new( SingleOutputChangeStrategy::new(FeeRule::standard(), None, ShieldedProtocol::Orchard), Default::default(), @@ -467,14 +464,14 @@ where pub async fn transfer( &self, seed_phrase: &str, - from_account_index: usize, + from_account_id: AccountId, to_address: ZcashAddress, value: u64, ) -> Result<(), Error> { let mut client = self.client.clone(); let usk = usk_from_seed_str(seed_phrase, 0, &self.network)?; let proposal = self - .propose_transfer(from_account_index, to_address, value) + .propose_transfer(from_account_id, to_address, value) .await?; // TODO: Add callback for approving the transaction here let txids = self.create_proposed_transactions(proposal, &usk).await?; @@ -512,7 +509,7 @@ where fn usk_from_seed_str( seed: &str, - account_index: u32, + account_id: u32, network: &consensus::Network, ) -> Result { let mnemonic = >::from_phrase(seed).map_err(|_| Error::InvalidSeedPhrase)?; @@ -522,7 +519,6 @@ fn usk_from_seed_str( seed.zeroize(); SecretVec::new(secret) }; - let usk = - UnifiedSpendingKey::from_seed(network, seed.expose_secret(), account_index.try_into()?)?; + let usk = UnifiedSpendingKey::from_seed(network, seed.expose_secret(), account_id.try_into()?)?; Ok(usk) } From a6ef53d63078fca8a40f70713e327b8626d4561a Mon Sep 17 00:00:00 2001 From: Willem Olding Date: Mon, 30 Sep 2024 12:42:50 -0400 Subject: [PATCH 3/9] update demo wallet with new api --- packages/demo-wallet/src/App/Actions.tsx | 9 +++++---- packages/demo-wallet/src/App/App.tsx | 10 +++++----- src/bindgen/wallet.rs | 1 - 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/demo-wallet/src/App/Actions.tsx b/packages/demo-wallet/src/App/Actions.tsx index 3cb6786..8d82e8b 100644 --- a/packages/demo-wallet/src/App/Actions.tsx +++ b/packages/demo-wallet/src/App/Actions.tsx @@ -1,7 +1,7 @@ import initWasm, { initThreadPool, WebWallet } from "@webzjs/webz-core"; import { State, Action } from "./App"; -import { MAINNET_LIGHTWALLETD_PROXY } from "./constants"; +import { MAINNET_LIGHTWALLETD_PROXY } from "./Constants"; export async function init(dispatch: React.Dispatch) { await initWasm(); @@ -13,8 +13,8 @@ export async function init(dispatch: React.Dispatch) { } export async function addNewAccount(state: State, dispatch: React.Dispatch, seedPhrase: string, birthdayHeight: number) { - await state.webWallet?.create_account(seedPhrase, 0, birthdayHeight); - dispatch({ type: "append-account-seed", payload: seedPhrase }); + let account_id = await state.webWallet?.create_account(seedPhrase, 0, birthdayHeight) || 0; + dispatch({ type: "add-account-seed", payload: [account_id, seedPhrase] }); await syncStateWithWallet(state, dispatch); } @@ -60,6 +60,7 @@ export async function triggerTransfer( throw new Error("No active account"); } - await state.webWallet?.transfer(state.accountSeeds[state.activeAccount], state.activeAccount, toAddress, amount); + let activeAccountSeedPhrase = state.accountSeeds.get(state.activeAccount) || ""; + await state.webWallet?.transfer(activeAccountSeedPhrase, state.activeAccount, toAddress, amount); await syncStateWithWallet(state, dispatch); } diff --git a/packages/demo-wallet/src/App/App.tsx b/packages/demo-wallet/src/App/App.tsx index d650a94..16ae026 100644 --- a/packages/demo-wallet/src/App/App.tsx +++ b/packages/demo-wallet/src/App/App.tsx @@ -23,19 +23,19 @@ export type State = { activeAccount?: number; summary?: WalletSummary; chainHeight?: bigint; - accountSeeds: string[]; + accountSeeds: Map; }; const initialState: State = { activeAccount: undefined, summary: undefined, chainHeight: undefined, - accountSeeds: [], + accountSeeds: new Map(), }; export type Action = | { type: "set-active-account"; payload: number } - | { type: "append-account-seed"; payload: string } + | { type: "add-account-seed"; payload: [number, string] } | { type: "set-web-wallet"; payload: WebWallet } | { type: "set-summary"; payload: WalletSummary } | { type: "set-chain-height"; payload: bigint }; @@ -45,8 +45,8 @@ const reducer = (state: State, action: Action): State => { case "set-active-account": { return { ...state, activeAccount: action.payload }; } - case "append-account-seed": { - return { ...state, accountSeeds: [...state.accountSeeds, action.payload] }; + case "add-account-seed": { + return { ...state, accountSeeds: state.accountSeeds.set(action.payload[0], action.payload[1]) }; } case "set-web-wallet": { return { ...state, webWallet: action.payload }; diff --git a/src/bindgen/wallet.rs b/src/bindgen/wallet.rs index 927448d..f974f97 100644 --- a/src/bindgen/wallet.rs +++ b/src/bindgen/wallet.rs @@ -1,5 +1,4 @@ use std::num::NonZeroU32; -use std::ops::Deref; use serde::{Deserialize, Serialize}; use wasm_bindgen::prelude::*; From 443ad173dd770eafff632ae9ad03f6c002e4f310 Mon Sep 17 00:00:00 2001 From: Willem Olding Date: Mon, 30 Sep 2024 13:39:00 -0400 Subject: [PATCH 4/9] remove the legacy sync algo --- Cargo.toml | 1 - justfile | 10 +-- src/bindgen/wallet.rs | 23 +----- src/wallet.rs | 137 +--------------------------------- tests/message-board-sync.rs | 18 +---- tests/simple-sync-and-send.rs | 16 +--- 6 files changed, 17 insertions(+), 188 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3881961..ac92dd2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,6 @@ native = ["tonic/channel", "tonic/gzip", "tonic/tls-webpki-roots", "tokio/macros sqlite-db = ["dep:zcash_client_sqlite"] console_error_panic_hook = ["dep:console_error_panic_hook"] no-bundler = ["wasm-bindgen-rayon?/no-bundler", "wasm_thread/no-bundler"] -sync2 = [] [dependencies] ## Web dependencies diff --git a/justfile b/justfile index 1c62999..46ea915 100644 --- a/justfile +++ b/justfile @@ -2,26 +2,26 @@ default: just --list build *features: - wasm-pack build --no-opt -t web --scope webzjs --release --out-dir ./packages/webz-core --no-default-features --features="wasm wasm-parallel sync2 {{features}}" -Z build-std="panic_abort,std" + wasm-pack build --no-opt -t web --scope webzjs --release --out-dir ./packages/webz-core --no-default-features --features="wasm wasm-parallel {{features}}" -Z build-std="panic_abort,std" # All Wasm Tests test-web *features: WASM_BINDGEN_TEST_TIMEOUT=99999 wasm-pack test --release --firefox --no-default-features --features "wasm no-bundler {{features}}" -Z build-std="panic_abort,std" -# sync message board in the web: addigional args: sync2 +# sync message board in the web: addigional args: test-message-board-web *features: WASM_BINDGEN_TEST_TIMEOUT=99999 wasm-pack test --release --chrome --no-default-features --features "wasm no-bundler {{features}}" -Z build-std="panic_abort,std" --test message-board-sync -# simple example in the web: additional args: sync2 +# simple example in the web: additional args: test-simple-web *features: WASM_BINDGEN_TEST_TIMEOUT=99999 wasm-pack test --release --chrome --no-default-features --features "wasm no-bundler {{features}}" -Z build-std="panic_abort,std" --test simple-sync-and-send -# simple example: additional args: sync2, sqlite-db +# simple example: additional args:, sqlite-db example-simple *features: RUST_LOG="info,zcash_client_backend::sync=debug" cargo run -r --example simple-sync --features "native {{features}}" -# sync the message board: additional args: sync2, sqlite-db +# sync the message board: additional args:, sqlite-db example-message-board *features: RUST_LOG=info,zcash_client_backend::sync=debug cargo run -r --example message-board-sync --features "native {{features}}" diff --git a/src/bindgen/wallet.rs b/src/bindgen/wallet.rs index 0d0b1e7..400175b 100644 --- a/src/bindgen/wallet.rs +++ b/src/bindgen/wallet.rs @@ -117,31 +117,14 @@ impl WebWallet { self.inner.suggest_scan_ranges().await } - /// Synchronize the wallet with the blockchain up to the tip - /// The passed callback will be called for every batch of blocks processed with the current progress - pub async fn sync(&self, callback: &js_sys::Function) -> Result<(), Error> { - let callback = move |scanned_to: BlockHeight, tip: BlockHeight| { - let this = JsValue::null(); - let _ = callback.call2( - &this, - &JsValue::from(Into::::into(scanned_to)), - &JsValue::from(Into::::into(tip)), - ); - }; - - self.inner.sync(callback).await?; - - Ok(()) - } - /// Synchronize the wallet with the blockchain up to the tip using zcash_client_backend's algo - pub async fn sync2(&self) -> Result<(), Error> { + pub async fn sync(&self) -> Result<(), Error> { assert!(!thread::is_web_worker_thread()); let db = self.inner.clone(); let sync_handler = thread::Builder::new() - .name("sync2".to_string()) + .name("sync".to_string()) .spawn_async(|| async { assert!(thread::is_web_worker_thread()); tracing::debug!( @@ -150,7 +133,7 @@ impl WebWallet { ); let db = db; - db.sync2().await.unwrap_throw(); + db.sync().await.unwrap_throw(); }) .unwrap_throw() .join_async(); diff --git a/src/wallet.rs b/src/wallet.rs index 71cc1cc..63d385f 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -1,7 +1,6 @@ use std::num::NonZeroU32; use bip0039::{English, Mnemonic}; -use futures_util::{StreamExt, TryStreamExt}; use nonempty::NonEmpty; use secrecy::{ExposeSecret, SecretVec, Zeroize}; use tonic::{ @@ -22,23 +21,21 @@ use zcash_address::ZcashAddress; use zcash_client_backend::data_api::wallet::{ create_proposed_transactions, input_selection::GreedyInputSelector, propose_transfer, }; -use zcash_client_backend::data_api::{scanning::ScanRange, WalletCommitmentTrees}; +use zcash_client_backend::data_api::WalletCommitmentTrees; use zcash_client_backend::data_api::{ - AccountBirthday, AccountPurpose, InputSource, NullifierQuery, WalletRead, WalletSummary, - WalletWrite, + AccountBirthday, AccountPurpose, InputSource, WalletRead, WalletSummary, WalletWrite, }; use zcash_client_backend::fees::zip317::SingleOutputChangeStrategy; use zcash_client_backend::proposal::Proposal; use zcash_client_backend::proto::service::{ self, compact_tx_streamer_client::CompactTxStreamerClient, }; -use zcash_client_backend::scanning::{scan_block, Nullifiers, ScanningKeys}; use zcash_client_backend::wallet::OvkPolicy; use zcash_client_backend::zip321::{Payment, TransactionRequest}; use zcash_client_backend::ShieldedProtocol; use zcash_client_memory::{MemBlockCache, MemoryWalletDb}; use zcash_keys::keys::{UnifiedFullViewingKey, UnifiedSpendingKey}; -use zcash_primitives::consensus::{self, BlockHeight, Network}; +use zcash_primitives::consensus::{self, Network}; use zcash_primitives::transaction::components::amount::NonNegativeAmount; use zcash_primitives::transaction::fees::zip317::FeeRule; use zcash_primitives::transaction::TxId; @@ -228,7 +225,7 @@ where })?) } - pub async fn sync2(&self) -> Result<(), Error> { + pub async fn sync(&self) -> Result<(), Error> { let mut client = self.client.clone(); // TODO: This should be held in the Wallet struct so we can download in parallel let db_cache = MemBlockCache::new(); @@ -245,113 +242,6 @@ where .map_err(Into::into) } - /// Synchronize the wallet with the blockchain up to the tip - /// The passed callback will be called for every batch of blocks processed with the current progress - pub async fn sync(&self, callback: impl Fn(BlockHeight, BlockHeight)) -> Result<(), Error> { - let tip = self.update_chain_tip().await?; - - tracing::info!("Retrieving suggested scan ranges from wallet"); - let scan_ranges = self.db.read().await.suggest_scan_ranges()?; - tracing::info!("Suggested scan ranges: {:?}", scan_ranges); - - // TODO: Ensure wallet's view of the chain tip as of the previous wallet session is valid. - // See https://github.com/Electric-Coin-Company/zec-sqlite-cli/blob/8c2e49f6d3067ec6cc85248488915278c3cb1c5a/src/commands/sync.rs#L157 - - // Download and process all blocks in the requested ranges - // Split each range into BATCH_SIZE chunks to avoid requesting too many blocks at once - for scan_range in scan_ranges.into_iter().flat_map(|r| { - // Limit the number of blocks we download and scan at any one time. - (0..).scan(r, |acc, _| { - if acc.is_empty() { - None - } else if let Some((cur, next)) = acc.split_at(acc.block_range().start + BATCH_SIZE) - { - *acc = next; - Some(cur) - } else { - let cur = acc.clone(); - let end = acc.block_range().end; - *acc = ScanRange::from_parts(end..end, acc.priority()); - Some(cur) - } - }) - }) { - self.fetch_and_scan_range( - scan_range.block_range().start.into(), - scan_range.block_range().end.into(), - ) - .await?; - callback(scan_range.block_range().end, tip); - } - - Ok(()) - } - - /// Download and process all blocks in the given range - async fn fetch_and_scan_range(&self, start: u32, end: u32) -> Result<(), Error> { - let mut client = self.client.clone(); - // get the chainstate prior to the range - let tree_state = client - .get_tree_state(service::BlockId { - height: (start - 1).into(), - ..Default::default() - }) - .await?; - let chainstate = tree_state.into_inner().to_chain_state()?; - - // Get the scanning keys from the DB - let account_ufvks = self.db.read().await.get_unified_full_viewing_keys()?; - let scanning_keys = ScanningKeys::from_account_ufvks(account_ufvks); - - // Get the nullifiers for the unspent notes we are tracking - let nullifiers = Nullifiers::new( - self.db - .read() - .await - .get_sapling_nullifiers(NullifierQuery::Unspent)?, - self.db - .read() - .await - .get_orchard_nullifiers(NullifierQuery::Unspent)?, - ); - - let range = service::BlockRange { - start: Some(service::BlockId { - height: start.into(), - ..Default::default() - }), - end: Some(service::BlockId { - height: (end - 1).into(), - ..Default::default() - }), - }; - - tracing::info!("Scanning block range: {:?} to {:?}", start, end); - - let scanned_blocks = client - .get_block_range(range) - .await? - .into_inner() - .map(|compact_block| { - scan_block( - &self.network, - compact_block.unwrap(), - &scanning_keys, - &nullifiers, - None, - ) - }) - .try_collect() - .await?; - - self.db - .write() - .await - .put_blocks(&chainstate, scanned_blocks)?; - - Ok(()) - } - pub async fn get_wallet_summary(&self) -> Result>, Error> { Ok(self .db @@ -360,25 +250,6 @@ where .get_wallet_summary(self.min_confirmations.into())?) } - pub(crate) async fn update_chain_tip(&self) -> Result { - tracing::info!("Retrieving chain tip from lightwalletd"); - - let tip_height = self - .client - .clone() - .get_latest_block(service::ChainSpec::default()) - .await? - .get_ref() - .height - .try_into() - .unwrap(); - - tracing::info!("Latest block height is {}", tip_height); - self.db.write().await.update_chain_tip(tip_height)?; - - Ok(tip_height) - } - /// /// Create a transaction proposal to send funds from the wallet to a given address /// diff --git a/tests/message-board-sync.rs b/tests/message-board-sync.rs index 829bb7a..8163e54 100644 --- a/tests/message-board-sync.rs +++ b/tests/message-board-sync.rs @@ -39,21 +39,9 @@ async fn test_message_board() { let id = w.import_ufvk(&ufvk_str, Some(2477329)).await.unwrap(); tracing::info!("Created account with id: {}", id); - #[cfg(not(feature = "sync2"))] - { - tracing::info!("Syncing wallet with our sync impl"); - w.sync(&js_sys::Function::new_with_args( - "scanned_to, tip", - "console.log('Scanned: ', scanned_to, '/', tip)", - )) - .await - .unwrap(); - } - #[cfg(feature = "sync2")] - { - tracing::info!("Syncing wallet with sync2"); - w.sync2().await.unwrap(); - } + tracing::info!("Syncing wallet with our sync impl"); + w.sync().await.unwrap(); + tracing::info!("Syncing complete :)"); let summary = w.get_wallet_summary().await.unwrap(); diff --git a/tests/simple-sync-and-send.rs b/tests/simple-sync-and-send.rs index 68b48c7..b5f2e1f 100644 --- a/tests/simple-sync-and-send.rs +++ b/tests/simple-sync-and-send.rs @@ -33,20 +33,8 @@ async fn test_get_and_scan_range() { let w_clone = w.clone(); let w = w_clone; - #[cfg(not(feature = "sync2"))] - { - w.sync(&js_sys::Function::new_with_args( - "scanned_to, tip", - "console.log('Scanned: ', scanned_to, '/', tip)", - )) - .await - .unwrap(); - } - #[cfg(feature = "sync2")] - { - tracing::info!("Syncing wallet with sync2"); - w.sync2().await.unwrap(); - } + w.sync().await.unwrap(); + tracing::info!("Syncing complete :)"); let summary = w.get_wallet_summary().await.unwrap(); From 442ab3e4ab898f41cdcbe8c186619e36f61dda0e Mon Sep 17 00:00:00 2001 From: Willem Olding Date: Mon, 30 Sep 2024 14:01:53 -0400 Subject: [PATCH 5/9] add new fn to wallet to just send an existing transaction --- src/error.rs | 2 ++ src/wallet.rs | 72 +++++++++++++++++++++++++-------------------------- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/src/error.rs b/src/error.rs index 5dfb8c3..b097f3e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -59,6 +59,8 @@ pub enum Error { SqliteError(#[from] zcash_client_sqlite::error::SqliteClientError), #[error("Invalid seed phrase")] InvalidSeedPhrase, + #[error("Failed when creating transaction")] + FailedToCreateTransaction, } impl From for JsValue { diff --git a/src/wallet.rs b/src/wallet.rs index 71cc1cc..e4c0dfc 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -451,27 +451,52 @@ where OvkPolicy::Sender, &proposal, ) - .unwrap(); + .map_err(|_| Error::FailedToCreateTransaction)?; Ok(transactions) } + pub async fn send_authorized_transactions( + &mut self, + txids: &NonEmpty, + ) -> Result<(), Error> { + for txid in txids.iter() { + let (txid, raw_tx) = self + .db + .read() + .await + .get_transaction(*txid)? + .map(|tx| { + let mut raw_tx = service::RawTransaction::default(); + tx.write(&mut raw_tx.data).unwrap(); + (tx.txid(), raw_tx) + }) + .unwrap(); + + let response = self.client.send_transaction(raw_tx).await?.into_inner(); + + if response.error_code != 0 { + return Err(Error::SendFailed { + code: response.error_code, + reason: response.error_message, + }); + } else { + tracing::info!("Transaction {} send successfully :)", txid); + } + } + Ok(()) + } + /// - /// Create a transaction proposal to send funds from the wallet to a given address and if approved will sign it and send the proposed transaction(s) to the network - /// - /// First a proposal is created by selecting inputs and outputs to cover the requested amount. This proposal is then sent to the approval callback. - /// This allows wallet developers to display a confirmation dialog to the user before continuing. - /// - /// # Arguments + /// A helper function that creates a proposal, creates a transation from the proposal and then submits it /// pub async fn transfer( - &self, + &mut self, seed_phrase: &str, from_account_index: usize, to_address: ZcashAddress, value: u64, ) -> Result<(), Error> { - let mut client = self.client.clone(); let usk = usk_from_seed_str(seed_phrase, 0, &self.network)?; let proposal = self .propose_transfer(from_account_index, to_address, value) @@ -480,33 +505,8 @@ where let txids = self.create_proposed_transactions(proposal, &usk).await?; // send the transactions to the network!! - tracing::info!("Sending transaction..."); - let txid = *txids.first(); - let (txid, raw_tx) = self - .db - .read() - .await - .get_transaction(txid)? - .map(|tx| { - let mut raw_tx = service::RawTransaction::default(); - tx.write(&mut raw_tx.data).unwrap(); - (tx.txid(), raw_tx) - }) - .unwrap(); - - // tracing::info!("Transaction hex: 0x{}", hex::encode(&raw_tx.data)); - - let response = client.send_transaction(raw_tx).await?.into_inner(); - - if response.error_code != 0 { - Err(Error::SendFailed { - code: response.error_code, - reason: response.error_message, - }) - } else { - tracing::info!("Transaction {} send successfully :)", txid); - Ok(()) - } + tracing::info!("Sending transactions"); + self.send_authorized_transactions(&txids).await } } From bacb41a9067e08ed8988ff52b1e3bd76941dd4a5 Mon Sep 17 00:00:00 2001 From: Willem Olding Date: Mon, 30 Sep 2024 16:17:28 -0400 Subject: [PATCH 6/9] draft propose_transfer that returns serialized proposal --- Cargo.lock | 36 ++++++++++++++++++++++----------- Cargo.toml | 14 ++++++------- src/bindgen/wallet.rs | 47 ++++++++++++++++++++++++++++++++++++++++++- src/wallet.rs | 11 +++++----- 4 files changed, 83 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9d23467..759f765 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -806,7 +806,7 @@ checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" [[package]] name = "equihash" version = "0.2.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" +source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" dependencies = [ "blake2b_simd", "byteorder", @@ -858,7 +858,7 @@ dependencies = [ [[package]] name = "f4jumble" version = "0.1.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" +source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" dependencies = [ "blake2b_simd", ] @@ -1680,6 +1680,9 @@ name = "nonempty" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7" +dependencies = [ + "serde", +] [[package]] name = "nu-ansi-term" @@ -3648,11 +3651,13 @@ dependencies = [ [[package]] name = "zcash_address" version = "0.5.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" +source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" dependencies = [ "bech32", "bs58", "f4jumble", + "serde", + "serde_with", "zcash_encoding", "zcash_protocol", ] @@ -3660,7 +3665,7 @@ dependencies = [ [[package]] name = "zcash_client_backend" version = "0.13.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" +source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" dependencies = [ "async-trait", "base64", @@ -3686,6 +3691,8 @@ dependencies = [ "rayon", "sapling-crypto", "secrecy", + "serde", + "serde_with", "shardtree", "subtle", "time", @@ -3706,7 +3713,7 @@ dependencies = [ [[package]] name = "zcash_client_memory" version = "0.1.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" +source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" dependencies = [ "async-trait", "bs58", @@ -3741,7 +3748,7 @@ dependencies = [ [[package]] name = "zcash_client_sqlite" version = "0.11.2" -source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" +source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" dependencies = [ "bs58", "byteorder", @@ -3777,7 +3784,7 @@ dependencies = [ [[package]] name = "zcash_encoding" version = "0.2.1" -source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" +source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" dependencies = [ "byteorder", "nonempty", @@ -3786,7 +3793,7 @@ dependencies = [ [[package]] name = "zcash_keys" version = "0.3.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" +source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" dependencies = [ "bech32", "bip32", @@ -3827,7 +3834,7 @@ dependencies = [ [[package]] name = "zcash_primitives" version = "0.17.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" +source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" dependencies = [ "aes", "bip32", @@ -3851,6 +3858,7 @@ dependencies = [ "ripemd", "sapling-crypto", "secp256k1", + "serde", "sha2", "subtle", "tracing", @@ -3865,7 +3873,7 @@ dependencies = [ [[package]] name = "zcash_proofs" version = "0.17.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" +source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" dependencies = [ "bellman", "blake2b_simd", @@ -3885,10 +3893,12 @@ dependencies = [ [[package]] name = "zcash_protocol" version = "0.3.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" +source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" dependencies = [ "document-features", "memuse", + "serde", + "serde_with", ] [[package]] @@ -3954,11 +3964,13 @@ dependencies = [ [[package]] name = "zip321" version = "0.1.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=d1fa3e846c5e61de3f1df23dd9f4d5416915631a#d1fa3e846c5e61de3f1df23dd9f4d5416915631a" +source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" dependencies = [ "base64", "nom", "percent-encoding", + "serde", + "serde_with", "zcash_address", "zcash_protocol", ] diff --git a/Cargo.toml b/Cargo.toml index 69da9c9..a94006d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,12 +61,12 @@ tokio_with_wasm = { version = "0.7.1", features = ["rt", "rt-multi-thread", "syn ## Zcash dependencies -zcash_keys = { git = "https://github.com/ChainSafe/librustzcash", rev = "d1fa3e846c5e61de3f1df23dd9f4d5416915631a", features = ["transparent-inputs", "orchard", "sapling", "unstable"] } -zcash_client_backend = { git = "https://github.com/ChainSafe/librustzcash", rev = "d1fa3e846c5e61de3f1df23dd9f4d5416915631a", default-features = false, features = ["sync", "lightwalletd-tonic", "wasm-bindgen", "orchard"] } -zcash_client_memory = { git = "https://github.com/ChainSafe/librustzcash", rev = "d1fa3e846c5e61de3f1df23dd9f4d5416915631a", features = ["orchard"] } -zcash_primitives = { git = "https://github.com/ChainSafe/librustzcash", rev = "d1fa3e846c5e61de3f1df23dd9f4d5416915631a" } -zcash_address = { git = "https://github.com/ChainSafe/librustzcash", rev = "d1fa3e846c5e61de3f1df23dd9f4d5416915631a" } -zcash_proofs = { git = "https://github.com/ChainSafe/librustzcash", rev = "d1fa3e846c5e61de3f1df23dd9f4d5416915631a", default-features = false, features = ["bundled-prover"] } +zcash_keys = { git = "https://github.com/ChainSafe/librustzcash", rev = "efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0", features = ["transparent-inputs", "orchard", "sapling", "unstable"] } +zcash_client_backend = { git = "https://github.com/ChainSafe/librustzcash", rev = "efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0", default-features = false, features = ["sync", "lightwalletd-tonic", "wasm-bindgen", "orchard"] } +zcash_client_memory = { git = "https://github.com/ChainSafe/librustzcash", rev = "efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0", features = ["orchard"] } +zcash_primitives = { git = "https://github.com/ChainSafe/librustzcash", rev = "efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" } +zcash_address = { git = "https://github.com/ChainSafe/librustzcash", rev = "efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" } +zcash_proofs = { git = "https://github.com/ChainSafe/librustzcash", rev = "efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0", default-features = false, features = ["bundled-prover"] } ## gRPC Web dependencies prost = { version = "0.12", default-features = false } @@ -77,7 +77,7 @@ tonic = { version = "0.12", default-features = false, features = [ # Used in Native tests tokio = { version = "1.0" } -zcash_client_sqlite = { git = "https://github.com/ChainSafe/librustzcash", rev = "d1fa3e846c5e61de3f1df23dd9f4d5416915631a", default-features = false, features = ["unstable", "orchard"], optional = true } +zcash_client_sqlite = { git = "https://github.com/ChainSafe/librustzcash", rev = "efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0", default-features = false, features = ["unstable", "orchard"], optional = true } getrandom = { version = "0.2", features = ["js"] } thiserror = "1.0.63" diff --git a/src/bindgen/wallet.rs b/src/bindgen/wallet.rs index f974f97..eeff254 100644 --- a/src/bindgen/wallet.rs +++ b/src/bindgen/wallet.rs @@ -9,17 +9,22 @@ use crate::error::Error; use crate::{BlockRange, Wallet, PRUNING_DEPTH}; use wasm_thread as thread; use zcash_address::ZcashAddress; -use zcash_client_backend::data_api::WalletRead; +use zcash_client_backend::data_api::{WalletRead, InputSource}; +use zcash_client_backend::proposal::Proposal; use zcash_client_backend::proto::service::{ compact_tx_streamer_client::CompactTxStreamerClient, ChainSpec, }; use zcash_client_memory::MemoryWalletDb; use zcash_keys::keys::UnifiedFullViewingKey; use zcash_primitives::consensus::{self, BlockHeight}; +use zcash_primitives::transaction::fees::zip317::FeeRule; +use zcash_primitives::transaction::TxId; + pub type MemoryWallet = Wallet, T>; pub type AccountId = as WalletRead>::AccountId; +pub type NoteRef = as InputSource>::NoteRef; /// # A Zcash wallet /// @@ -193,6 +198,46 @@ impl WebWallet { .await } + /// + /// Create a transaction proposal to send funds from the wallet to a given address. + /// + pub async fn propose_transfer( + &self, + account_id: u32, + to_address: String, + value: u64, + ) -> Result { + let to_address = ZcashAddress::try_from_encoded(&to_address)?; + let proposal = self.inner.propose_transfer(AccountId::from(account_id), to_address, value).await?; + Ok(serde_wasm_bindgen::to_value(&proposal).unwrap()) + } + + /// + /// Perform the proving and signing required to create one or more transaction from the proposal. Created transactions are stored in the wallet database. + /// + /// Note: At the moment this requires a USK but ideally we want to be able to hand the signing off to a separate service + /// e.g. browser plugin, hardware wallet, etc. Will need to look into refactoring librustzcash create_proposed_transactions to allow for this + /// + // pub async fn create_proposed_transactions( + // &self, + // proposal: Proposal, + // usk: &UnifiedSpendingKey, + // ) -> Result, Error> { + // self.inner + // .create_proposed_transactions(proposal, usk) + // .await + // } + + /// + /// Send a list of transactions to the network via the lightwalletd instance this wallet is connected to + /// + // pub async fn send_authorized_transactions( + // &self, + // txids: &[TxId], + // ) -> Result<(), Error> { + // self.inner.send_authorized_transactions(txids).await + // } + /// Forwards a call to lightwalletd to retrieve the height of the latest block in the chain pub async fn get_latest_block(&self) -> Result { self.client() diff --git a/src/wallet.rs b/src/wallet.rs index b69f153..aaffa46 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -381,7 +381,7 @@ where /// /// Create a transaction proposal to send funds from the wallet to a given address /// - async fn propose_transfer( + pub async fn propose_transfer( &self, account_id: AccountId, to_address: ZcashAddress, @@ -426,7 +426,7 @@ where /// Note: At the moment this requires a USK but ideally we want to be able to hand the signing off to a separate service /// e.g. browser plugin, hardware wallet, etc. Will need to look into refactoring librustzcash create_proposed_transactions to allow for this /// - pub(crate) async fn create_proposed_transactions( + pub async fn create_proposed_transactions( &self, proposal: Proposal, usk: &UnifiedSpendingKey, @@ -454,9 +454,10 @@ where } pub async fn send_authorized_transactions( - &mut self, + &self, txids: &NonEmpty, ) -> Result<(), Error> { + let mut client = self.client.clone(); for txid in txids.iter() { let (txid, raw_tx) = self .db @@ -470,7 +471,7 @@ where }) .unwrap(); - let response = self.client.send_transaction(raw_tx).await?.into_inner(); + let response = client.send_transaction(raw_tx).await?.into_inner(); if response.error_code != 0 { return Err(Error::SendFailed { @@ -488,7 +489,7 @@ where /// A helper function that creates a proposal, creates a transation from the proposal and then submits it /// pub async fn transfer( - &mut self, + &self, seed_phrase: &str, from_account_id: AccountId, to_address: ZcashAddress, From 874d78d3705d23fa1362185769fe57ba7d282460 Mon Sep 17 00:00:00 2001 From: Willem Olding Date: Tue, 1 Oct 2024 14:28:22 -0400 Subject: [PATCH 7/9] restructured send process --- Cargo.lock | 24 ++--- Cargo.toml | 14 +-- packages/demo-wallet/src/App/Actions.tsx | 10 ++- .../src/App/components/ImportAccount.tsx | 1 + src/bindgen/mod.rs | 1 + src/bindgen/proposal.rs | 32 +++++++ src/bindgen/wallet.rs | 89 +++++++------------ src/wallet.rs | 7 +- 8 files changed, 97 insertions(+), 81 deletions(-) create mode 100644 src/bindgen/proposal.rs diff --git a/Cargo.lock b/Cargo.lock index 759f765..3429cde 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -806,7 +806,7 @@ checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" [[package]] name = "equihash" version = "0.2.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=9673cc2859e8a2528d1efd3c74795363f87ddf8f#9673cc2859e8a2528d1efd3c74795363f87ddf8f" dependencies = [ "blake2b_simd", "byteorder", @@ -858,7 +858,7 @@ dependencies = [ [[package]] name = "f4jumble" version = "0.1.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=9673cc2859e8a2528d1efd3c74795363f87ddf8f#9673cc2859e8a2528d1efd3c74795363f87ddf8f" dependencies = [ "blake2b_simd", ] @@ -3651,7 +3651,7 @@ dependencies = [ [[package]] name = "zcash_address" version = "0.5.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=9673cc2859e8a2528d1efd3c74795363f87ddf8f#9673cc2859e8a2528d1efd3c74795363f87ddf8f" dependencies = [ "bech32", "bs58", @@ -3665,7 +3665,7 @@ dependencies = [ [[package]] name = "zcash_client_backend" version = "0.13.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=9673cc2859e8a2528d1efd3c74795363f87ddf8f#9673cc2859e8a2528d1efd3c74795363f87ddf8f" dependencies = [ "async-trait", "base64", @@ -3713,7 +3713,7 @@ dependencies = [ [[package]] name = "zcash_client_memory" version = "0.1.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=9673cc2859e8a2528d1efd3c74795363f87ddf8f#9673cc2859e8a2528d1efd3c74795363f87ddf8f" dependencies = [ "async-trait", "bs58", @@ -3748,7 +3748,7 @@ dependencies = [ [[package]] name = "zcash_client_sqlite" version = "0.11.2" -source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=9673cc2859e8a2528d1efd3c74795363f87ddf8f#9673cc2859e8a2528d1efd3c74795363f87ddf8f" dependencies = [ "bs58", "byteorder", @@ -3784,7 +3784,7 @@ dependencies = [ [[package]] name = "zcash_encoding" version = "0.2.1" -source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=9673cc2859e8a2528d1efd3c74795363f87ddf8f#9673cc2859e8a2528d1efd3c74795363f87ddf8f" dependencies = [ "byteorder", "nonempty", @@ -3793,7 +3793,7 @@ dependencies = [ [[package]] name = "zcash_keys" version = "0.3.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=9673cc2859e8a2528d1efd3c74795363f87ddf8f#9673cc2859e8a2528d1efd3c74795363f87ddf8f" dependencies = [ "bech32", "bip32", @@ -3834,7 +3834,7 @@ dependencies = [ [[package]] name = "zcash_primitives" version = "0.17.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=9673cc2859e8a2528d1efd3c74795363f87ddf8f#9673cc2859e8a2528d1efd3c74795363f87ddf8f" dependencies = [ "aes", "bip32", @@ -3873,7 +3873,7 @@ dependencies = [ [[package]] name = "zcash_proofs" version = "0.17.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=9673cc2859e8a2528d1efd3c74795363f87ddf8f#9673cc2859e8a2528d1efd3c74795363f87ddf8f" dependencies = [ "bellman", "blake2b_simd", @@ -3893,7 +3893,7 @@ dependencies = [ [[package]] name = "zcash_protocol" version = "0.3.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=9673cc2859e8a2528d1efd3c74795363f87ddf8f#9673cc2859e8a2528d1efd3c74795363f87ddf8f" dependencies = [ "document-features", "memuse", @@ -3964,7 +3964,7 @@ dependencies = [ [[package]] name = "zip321" version = "0.1.0" -source = "git+https://github.com/ChainSafe/librustzcash?rev=efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0#efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=9673cc2859e8a2528d1efd3c74795363f87ddf8f#9673cc2859e8a2528d1efd3c74795363f87ddf8f" dependencies = [ "base64", "nom", diff --git a/Cargo.toml b/Cargo.toml index a94006d..5af0dd7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,12 +61,12 @@ tokio_with_wasm = { version = "0.7.1", features = ["rt", "rt-multi-thread", "syn ## Zcash dependencies -zcash_keys = { git = "https://github.com/ChainSafe/librustzcash", rev = "efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0", features = ["transparent-inputs", "orchard", "sapling", "unstable"] } -zcash_client_backend = { git = "https://github.com/ChainSafe/librustzcash", rev = "efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0", default-features = false, features = ["sync", "lightwalletd-tonic", "wasm-bindgen", "orchard"] } -zcash_client_memory = { git = "https://github.com/ChainSafe/librustzcash", rev = "efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0", features = ["orchard"] } -zcash_primitives = { git = "https://github.com/ChainSafe/librustzcash", rev = "efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" } -zcash_address = { git = "https://github.com/ChainSafe/librustzcash", rev = "efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0" } -zcash_proofs = { git = "https://github.com/ChainSafe/librustzcash", rev = "efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0", default-features = false, features = ["bundled-prover"] } +zcash_keys = { git = "https://github.com/ChainSafe/librustzcash", rev = "9673cc2859e8a2528d1efd3c74795363f87ddf8f", features = ["transparent-inputs", "orchard", "sapling", "unstable"] } +zcash_client_backend = { git = "https://github.com/ChainSafe/librustzcash", rev = "9673cc2859e8a2528d1efd3c74795363f87ddf8f", default-features = false, features = ["sync", "lightwalletd-tonic", "wasm-bindgen", "orchard"] } +zcash_client_memory = { git = "https://github.com/ChainSafe/librustzcash", rev = "9673cc2859e8a2528d1efd3c74795363f87ddf8f", features = ["orchard"] } +zcash_primitives = { git = "https://github.com/ChainSafe/librustzcash", rev = "9673cc2859e8a2528d1efd3c74795363f87ddf8f" } +zcash_address = { git = "https://github.com/ChainSafe/librustzcash", rev = "9673cc2859e8a2528d1efd3c74795363f87ddf8f" } +zcash_proofs = { git = "https://github.com/ChainSafe/librustzcash", rev = "9673cc2859e8a2528d1efd3c74795363f87ddf8f", default-features = false, features = ["bundled-prover"] } ## gRPC Web dependencies prost = { version = "0.12", default-features = false } @@ -77,7 +77,7 @@ tonic = { version = "0.12", default-features = false, features = [ # Used in Native tests tokio = { version = "1.0" } -zcash_client_sqlite = { git = "https://github.com/ChainSafe/librustzcash", rev = "efbaeec65dbf3b5126454fcb7a8f9be83cb9a9e0", default-features = false, features = ["unstable", "orchard"], optional = true } +zcash_client_sqlite = { git = "https://github.com/ChainSafe/librustzcash", rev = "9673cc2859e8a2528d1efd3c74795363f87ddf8f", default-features = false, features = ["unstable", "orchard"], optional = true } getrandom = { version = "0.2", features = ["js"] } thiserror = "1.0.63" diff --git a/packages/demo-wallet/src/App/Actions.tsx b/packages/demo-wallet/src/App/Actions.tsx index 8d82e8b..afc0c74 100644 --- a/packages/demo-wallet/src/App/Actions.tsx +++ b/packages/demo-wallet/src/App/Actions.tsx @@ -61,6 +61,12 @@ export async function triggerTransfer( } let activeAccountSeedPhrase = state.accountSeeds.get(state.activeAccount) || ""; - await state.webWallet?.transfer(activeAccountSeedPhrase, state.activeAccount, toAddress, amount); - await syncStateWithWallet(state, dispatch); + + let proposal = await state.webWallet?.propose_transfer(state.activeAccount, toAddress, amount); + console.log(JSON.stringify(proposal.describe(), null, 2)); + + let txids = await state.webWallet.create_proposed_transactions(proposal, activeAccountSeedPhrase); + console.log(JSON.stringify(txids, null, 2)); + + await state.webWallet.send_authorized_transactions(txids); } diff --git a/packages/demo-wallet/src/App/components/ImportAccount.tsx b/packages/demo-wallet/src/App/components/ImportAccount.tsx index 8588efc..aec337c 100644 --- a/packages/demo-wallet/src/App/components/ImportAccount.tsx +++ b/packages/demo-wallet/src/App/components/ImportAccount.tsx @@ -18,6 +18,7 @@ export function ImportAccount() { await addNewAccount(state, dispatch, seedPhrase, birthdayHeight); toast.success("Account imported successfully", { position: "top-center", + autoClose: 2000, }); setBirthdayHeight(0); setSeedPhrase(""); diff --git a/src/bindgen/mod.rs b/src/bindgen/mod.rs index 2fff25c..8aa035b 100644 --- a/src/bindgen/mod.rs +++ b/src/bindgen/mod.rs @@ -1 +1,2 @@ +pub mod proposal; pub mod wallet; diff --git a/src/bindgen/proposal.rs b/src/bindgen/proposal.rs new file mode 100644 index 0000000..8ae6a57 --- /dev/null +++ b/src/bindgen/proposal.rs @@ -0,0 +1,32 @@ +use wasm_bindgen::prelude::*; + +use super::wallet::NoteRef; +use zcash_primitives::transaction::fees::zip317::FeeRule; + +/// A handler to an immutable proposal. This can be passed to `create_proposed_transactions` to prove/authorize the transactions +/// before they are sent to the network. +/// +/// The proposal can be reviewed by calling `describe` which will return a JSON object with the details of the proposal. +#[wasm_bindgen] +pub struct Proposal { + inner: zcash_client_backend::proposal::Proposal, +} + +impl From> for Proposal { + fn from(inner: zcash_client_backend::proposal::Proposal) -> Self { + Self { inner } + } +} + +impl From for zcash_client_backend::proposal::Proposal { + fn from(proposal: Proposal) -> Self { + proposal.inner + } +} + +#[wasm_bindgen] +impl Proposal { + pub fn describe(&self) -> JsValue { + serde_wasm_bindgen::to_value(&self.inner).unwrap() + } +} diff --git a/src/bindgen/wallet.rs b/src/bindgen/wallet.rs index eeff254..0750884 100644 --- a/src/bindgen/wallet.rs +++ b/src/bindgen/wallet.rs @@ -1,26 +1,25 @@ use std::num::NonZeroU32; +use nonempty::NonEmpty; use serde::{Deserialize, Serialize}; use wasm_bindgen::prelude::*; use tonic_web_wasm_client::Client; use crate::error::Error; -use crate::{BlockRange, Wallet, PRUNING_DEPTH}; +use crate::wallet::usk_from_seed_str; +use crate::{bindgen::proposal::Proposal, BlockRange, Wallet, PRUNING_DEPTH}; use wasm_thread as thread; use zcash_address::ZcashAddress; -use zcash_client_backend::data_api::{WalletRead, InputSource}; -use zcash_client_backend::proposal::Proposal; +use zcash_client_backend::data_api::{InputSource, WalletRead}; use zcash_client_backend::proto::service::{ compact_tx_streamer_client::CompactTxStreamerClient, ChainSpec, }; use zcash_client_memory::MemoryWalletDb; use zcash_keys::keys::UnifiedFullViewingKey; use zcash_primitives::consensus::{self, BlockHeight}; -use zcash_primitives::transaction::fees::zip317::FeeRule; use zcash_primitives::transaction::TxId; - pub type MemoryWallet = Wallet, T>; pub type AccountId = as WalletRead>::AccountId; @@ -173,70 +172,50 @@ impl WebWallet { } /// - /// Create a transaction proposal to send funds from the wallet to a given address and if approved will sign it and send the proposed transaction(s) to the network - /// - /// First a proposal is created by selecting inputs and outputs to cover the requested amount. This proposal is then sent to the approval callback. - /// This allows wallet developers to display a confirmation dialog to the user before continuing. - /// - /// # Arguments + /// Create a transaction proposal to send funds from the wallet to a given address. /// - pub async fn transfer( + pub async fn propose_transfer( &self, - seed_phrase: &str, - from_account_id: u32, + account_id: u32, to_address: String, value: u64, - ) -> Result<(), Error> { + ) -> Result { let to_address = ZcashAddress::try_from_encoded(&to_address)?; - self.inner - .transfer( - seed_phrase, - AccountId::from(from_account_id), - to_address, - value, - ) - .await + let proposal = self + .inner + .propose_transfer(AccountId::from(account_id), to_address, value) + .await?; + Ok(proposal.into()) } /// - /// Create a transaction proposal to send funds from the wallet to a given address. + /// Perform the proving and signing required to create one or more transaction from the proposal. + /// Created transactions are stored in the wallet database and a list of the IDs is returned /// - pub async fn propose_transfer( + pub async fn create_proposed_transactions( &self, - account_id: u32, - to_address: String, - value: u64, + proposal: Proposal, + seed_phrase: &str, ) -> Result { - let to_address = ZcashAddress::try_from_encoded(&to_address)?; - let proposal = self.inner.propose_transfer(AccountId::from(account_id), to_address, value).await?; - Ok(serde_wasm_bindgen::to_value(&proposal).unwrap()) + let usk = usk_from_seed_str(seed_phrase, 0, &self.inner.network)?; + let txids = self + .inner + .create_proposed_transactions(proposal.into(), &usk) + .await?; + Ok(serde_wasm_bindgen::to_value(&txids).unwrap()) } - - /// - /// Perform the proving and signing required to create one or more transaction from the proposal. Created transactions are stored in the wallet database. - /// - /// Note: At the moment this requires a USK but ideally we want to be able to hand the signing off to a separate service - /// e.g. browser plugin, hardware wallet, etc. Will need to look into refactoring librustzcash create_proposed_transactions to allow for this + /// - // pub async fn create_proposed_transactions( - // &self, - // proposal: Proposal, - // usk: &UnifiedSpendingKey, - // ) -> Result, Error> { - // self.inner - // .create_proposed_transactions(proposal, usk) - // .await - // } - - /// /// Send a list of transactions to the network via the lightwalletd instance this wallet is connected to - /// - // pub async fn send_authorized_transactions( - // &self, - // txids: &[TxId], - // ) -> Result<(), Error> { - // self.inner.send_authorized_transactions(txids).await - // } + /// + pub async fn send_authorized_transactions(&self, txids: JsValue) -> Result<(), Error> { + let txids: NonEmpty = serde_wasm_bindgen::from_value(txids).unwrap(); + self.inner.send_authorized_transactions(&txids).await + } + + /////////////////////////////////////////////////////////////////////////////////////// + // lightwalletd gRPC methods + /////////////////////////////////////////////////////////////////////////////////////// /// Forwards a call to lightwalletd to retrieve the height of the latest block in the chain pub async fn get_latest_block(&self) -> Result { diff --git a/src/wallet.rs b/src/wallet.rs index aaffa46..548dde6 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -453,10 +453,7 @@ where Ok(transactions) } - pub async fn send_authorized_transactions( - &self, - txids: &NonEmpty, - ) -> Result<(), Error> { + pub async fn send_authorized_transactions(&self, txids: &NonEmpty) -> Result<(), Error> { let mut client = self.client.clone(); for txid in txids.iter() { let (txid, raw_tx) = self @@ -508,7 +505,7 @@ where } } -fn usk_from_seed_str( +pub(crate) fn usk_from_seed_str( seed: &str, account_id: u32, network: &consensus::Network, From 38aa204601c5bd87ccef533eeae7b10d938c25c5 Mon Sep 17 00:00:00 2001 From: Willem Olding Date: Tue, 1 Oct 2024 14:28:55 -0400 Subject: [PATCH 8/9] fmt --- src/bindgen/proposal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bindgen/proposal.rs b/src/bindgen/proposal.rs index 8ae6a57..db6bdae 100644 --- a/src/bindgen/proposal.rs +++ b/src/bindgen/proposal.rs @@ -5,7 +5,7 @@ use zcash_primitives::transaction::fees::zip317::FeeRule; /// A handler to an immutable proposal. This can be passed to `create_proposed_transactions` to prove/authorize the transactions /// before they are sent to the network. -/// +/// /// The proposal can be reviewed by calling `describe` which will return a JSON object with the details of the proposal. #[wasm_bindgen] pub struct Proposal { From 6a1dee7f90f81f50369ec0dba4ad5913ab6a41b8 Mon Sep 17 00:00:00 2001 From: Eric Tu Date: Tue, 1 Oct 2024 16:03:41 -0400 Subject: [PATCH 9/9] clippy --- src/bindgen/wallet.rs | 2 +- src/wallet.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bindgen/wallet.rs b/src/bindgen/wallet.rs index 38e6398..3917963 100644 --- a/src/bindgen/wallet.rs +++ b/src/bindgen/wallet.rs @@ -17,7 +17,7 @@ use zcash_client_backend::proto::service::{ }; use zcash_client_memory::MemoryWalletDb; use zcash_keys::keys::UnifiedFullViewingKey; -use zcash_primitives::consensus::{self, BlockHeight}; +use zcash_primitives::consensus; use zcash_primitives::transaction::TxId; pub type MemoryWallet = Wallet, T>; diff --git a/src/wallet.rs b/src/wallet.rs index 920160f..22bb521 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -23,8 +23,7 @@ use zcash_client_backend::data_api::wallet::{ }; use zcash_client_backend::data_api::WalletCommitmentTrees; use zcash_client_backend::data_api::{ - Account, AccountBirthday, AccountPurpose, InputSource, NullifierQuery, WalletRead, - WalletSummary, WalletWrite, + Account, AccountBirthday, AccountPurpose, InputSource, WalletRead, WalletSummary, WalletWrite, }; use zcash_client_backend::fees::zip317::SingleOutputChangeStrategy; use zcash_client_backend::proposal::Proposal;