diff --git a/Cargo.toml b/Cargo.toml index 346eef8..11b48ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -120,7 +120,7 @@ apple_metal = ["metal", "objc", "block"] [dependencies.zcash_params] git = "https://github.com/hhanh00/zcash-params.git" -rev = "86bb1d12e0230c0bf40758fd7d57f3e4c104e36e" +rev = "9fabe6aa8b3ca7099dc39db16fe126129c7755b8" [dependencies.zcash_client_backend] git = "https://github.com/hhanh00/librustzcash.git" diff --git a/binding.h b/binding.h index 9c75707..f83465f 100644 --- a/binding.h +++ b/binding.h @@ -105,6 +105,13 @@ void rescan_from(uint32_t height); struct CResult_u64 get_taddr_balance(uint8_t coin, uint32_t id_account); +struct CResult_____c_char transfer_pools(uint8_t coin, + uint32_t account, + uint8_t from_pool, + uint8_t to_pool, + uint64_t amount, + uint32_t confirmations); + struct CResult_____c_char shield_taddr(uint8_t coin, uint32_t account, uint32_t confirmations); void scan_transparent_accounts(uint32_t gap_limit); @@ -116,7 +123,7 @@ struct CResult_____c_char prepare_multi_payment(uint8_t coin, struct CResult_____c_char transaction_report(uint8_t coin, char *plan); -struct CResult_____c_char sign(uint8_t coin, uint32_t account, char *tx, int64_t _port); +struct CResult_____c_char sign(uint8_t coin, uint32_t account, char *tx_plan, int64_t _port); struct CResult_____c_char sign_and_broadcast(uint8_t coin, uint32_t account, char *tx_plan); diff --git a/src/api/account.rs b/src/api/account.rs index 880bfbb..4663135 100644 --- a/src/api/account.rs +++ b/src/api/account.rs @@ -365,16 +365,14 @@ pub fn derive_keys( pub fn get_unified_address( coin: u8, id_account: u32, - t: bool, - s: bool, - o: bool, + address_type: u8, ) -> anyhow::Result { let c = CoinConfig::get(coin); let db = c.db()?; let tpe = UnifiedAddressType { - transparent: t, - sapling: s, - orchard: o, + transparent: address_type & 1 != 0, + sapling: address_type & 2 != 0, + orchard: address_type & 4 != 0, }; let address = crate::get_unified_address(c.chain.network(), &db, id_account, Some(tpe))?; // use ua settings Ok(address) @@ -390,11 +388,7 @@ fn get_sapling_address(coin: u8, id_account: u32) -> anyhow::Result { pub fn get_address(coin: u8, id_account: u32, address_type: u8) -> anyhow::Result { let c = CoinConfig::get(coin); let address = if c.chain.has_unified() { - let t = address_type & 1 != 0; - let s = address_type & 2 != 0; - let o = address_type & 4 != 0; - - get_unified_address(coin, id_account, t, s, o)? + get_unified_address(coin, id_account, address_type)? } else { get_sapling_address(coin, id_account)? }; diff --git a/src/api/dart_ffi.rs b/src/api/dart_ffi.rs index 3cd0bfc..7e31303 100644 --- a/src/api/dart_ffi.rs +++ b/src/api/dart_ffi.rs @@ -12,6 +12,7 @@ use std::path::Path; use std::sync::Mutex; use tokio::sync::Semaphore; use zcash_primitives::transaction::builder::Progress; +use crate::api::payment_v2::AmountOrMax; static mut POST_COBJ: Option = None; @@ -416,6 +417,24 @@ pub async unsafe extern "C" fn get_taddr_balance(coin: u8, id_account: u32) -> C to_cresult(res) } +#[tokio::main] +#[no_mangle] +pub async unsafe extern "C" fn transfer_pools( + coin: u8, + account: u32, + from_pool: u8, to_pool: u8, + amount: u64, + confirmations: u32, +) -> CResult<*mut c_char> { + let res = async move { + let tx_plan = crate::api::payment_v2::transfer_pools(coin, account, from_pool, to_pool, + AmountOrMax::Amount(amount), confirmations).await?; + let tx_plan = serde_json::to_string(&tx_plan)?; + Ok::<_, anyhow::Error>(tx_plan) + }; + to_cresult_str(res.await) +} + #[tokio::main] #[no_mangle] pub async unsafe extern "C" fn shield_taddr( diff --git a/src/api/payment_v2.rs b/src/api/payment_v2.rs index 341e4e4..5f6cd63 100644 --- a/src/api/payment_v2.rs +++ b/src/api/payment_v2.rs @@ -34,7 +34,7 @@ pub async fn build_tx_plan( let checkpoint_height = get_checkpoint_height(&db, last_height, confirmations)?; (fvk, checkpoint_height) }; - let change_address = get_unified_address(coin, account, true, true, true)?; + let change_address = get_unified_address(coin, account, 7)?; let context = TxBuilderContext::from_height(coin, checkpoint_height)?; let mut orders = vec![]; @@ -144,17 +144,36 @@ pub async fn build_max_tx( Err(TransactionBuilderError::TxTooComplex) } -/// Make a transaction that shields the transparent balance -pub async fn shield_taddr(coin: u8, account: u32, confirmations: u32) -> anyhow::Result { - let address = get_unified_address(coin, account, false, true, true)?; // get our own unified address +pub enum AmountOrMax { + Amount(u64), + Max +} + +pub async fn transfer_pools(coin: u8, account: u32, from_pool: u8, to_pool: u8, amount: AmountOrMax, + confirmations: u32) -> anyhow::Result { + let address = get_unified_address(coin, account, to_pool)?; // get our own unified address + let a = match amount { + AmountOrMax::Amount(a) => a, + AmountOrMax::Max => 0, + }; let recipient = RecipientMemo { address, - amount: 0, + amount: a, memo: Memo::from_str("Shield Transparent Balance")?, max_amount_per_note: 0, }; let last_height = get_latest_height().await?; - let tx_plan = build_max_tx(coin, account, last_height, &recipient, 2, confirmations).await?; + let tx_plan = match amount { + AmountOrMax::Amount(_) => build_tx_plan(coin, account, last_height, slice::from_ref(&recipient), + !from_pool, confirmations).await?, + AmountOrMax::Max => build_max_tx(coin, account, last_height, &recipient, !from_pool, confirmations).await?, + }; + Ok(tx_plan) +} + +/// Make a transaction that shields the transparent balance +pub async fn shield_taddr(coin: u8, account: u32, confirmations: u32) -> anyhow::Result { + let tx_plan = transfer_pools(coin, account, 1, 6, AmountOrMax::Max, confirmations).await?; let tx_id = sign_and_broadcast(coin, account, &tx_plan).await?; log::info!("TXID: {}", tx_id); Ok(tx_id) diff --git a/src/db.rs b/src/db.rs index 1c3077e..0fce7d7 100644 --- a/src/db.rs +++ b/src/db.rs @@ -633,14 +633,15 @@ impl DbAdapter { &self, account: u32, checkpoint_height: u32, + orchard: bool, ) -> anyhow::Result> { let mut notes = vec![]; let mut statement = self.connection.prepare( "SELECT id_note, diversifier, value, rcm, witness FROM received_notes r, sapling_witnesses w WHERE spent IS NULL AND account = ?2 AND rho IS NULL - AND (r.excluded IS NULL OR NOT r.excluded) AND w.height = ?1 + AND (r.excluded IS NULL OR NOT r.excluded) AND w.height = ?1 AND r.orchard = ?3 AND r.id_note = w.note")?; - let rows = statement.query_map(params![checkpoint_height, account], |row| { + let rows = statement.query_map(params![checkpoint_height, account, orchard], |row| { let id_note: u32 = row.get(0)?; let diversifier: Vec = row.get(1)?; let amount: i64 = row.get(2)?; diff --git a/src/note_selection/tests.rs b/src/note_selection/tests.rs index 79fac54..c85f678 100644 --- a/src/note_selection/tests.rs +++ b/src/note_selection/tests.rs @@ -728,7 +728,7 @@ fn test_tx_plan() { &Network::MainNetwork, "", 0, - &Hash::default(), + None, &utxos, &orders, &TransactionBuilderConfig { diff --git a/src/note_selection/utxo.rs b/src/note_selection/utxo.rs index d005700..bbe8865 100644 --- a/src/note_selection/utxo.rs +++ b/src/note_selection/utxo.rs @@ -16,7 +16,10 @@ pub async fn fetch_utxos( let db = coin.db.as_ref().unwrap(); let db = db.lock().unwrap(); if excluded_flags & 2 == 0 { - utxos.extend(db.get_unspent_received_notes(account, checkpoint_height)?); + utxos.extend(db.get_unspent_received_notes(account, checkpoint_height, false)?); + } + if excluded_flags & 4 == 0 { + utxos.extend(db.get_unspent_received_notes(account, checkpoint_height, true)?); } Ok(utxos) }