From a429b92734c477d1e0533291c7c0f048a18ea736 Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Fri, 19 Dec 2025 18:53:26 +0200 Subject: [PATCH] fix: private native transfer unification --- wallet/src/cli/programs/mod.rs | 33 +++++++++++++ .../src/cli/programs/native_token_transfer.rs | 12 ++--- wallet/src/privacy_preserving_tx.rs | 17 +++++++ .../native_token_transfer/mod.rs | 46 ++++++++++++++++++- .../native_token_transfer/private.rs | 38 ++++++++++++++- 5 files changed, 135 insertions(+), 11 deletions(-) diff --git a/wallet/src/cli/programs/mod.rs b/wallet/src/cli/programs/mod.rs index 3ffb7bb..f97c27a 100644 --- a/wallet/src/cli/programs/mod.rs +++ b/wallet/src/cli/programs/mod.rs @@ -1,3 +1,36 @@ pub mod native_token_transfer; pub mod pinata; pub mod token; + +use anyhow::Result; +use clap::Args; +use nssa::AccountId; + +use crate::helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix}; + +#[derive(Debug, Args)] +struct ArgsSenderOwned { + /// from - valid 32 byte base58 string with privacy prefix + #[arg(long)] + from: String, +} + +impl ArgsSenderOwned { + pub fn parse_acc_and_privacy(self) -> Result<(AccountId, AccountPrivacyKind)> { + let (acc_id_raw, privacy) = parse_addr_with_privacy_prefix(&self.from)?; + Ok((acc_id_raw.parse()?, privacy)) + } +} + +#[derive(Debug, Args)] +struct ArgsReceiverVariableOwnership { + /// to - valid 32 byte base58 string with privacy prefix + #[arg(long)] + to: Option, + /// to_npk - valid 32 byte hex string + #[arg(long)] + to_npk: Option, + /// to_ipk - valid 33 byte hex string + #[arg(long)] + to_ipk: Option, +} diff --git a/wallet/src/cli/programs/native_token_transfer.rs b/wallet/src/cli/programs/native_token_transfer.rs index 7868a7c..793ba80 100644 --- a/wallet/src/cli/programs/native_token_transfer.rs +++ b/wallet/src/cli/programs/native_token_transfer.rs @@ -317,8 +317,8 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { let from: AccountId = from.parse().unwrap(); let to: AccountId = to.parse().unwrap(); - let (res, [secret_from, secret_to]) = NativeTokenTransfer(wallet_core) - .send_private_transfer_to_owned_account(from, to, amount) + let (res, acc_decode_data) = NativeTokenTransfer(wallet_core) + .send_private_transfer_to_owned_account_gen(from, to, amount) .await?; println!("Results of tx send are {res:#?}"); @@ -329,8 +329,6 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { .await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { - let acc_decode_data = vec![Decode(secret_from, from), Decode(secret_to, to)]; - wallet_core.decode_insert_privacy_preserving_transaction_results( tx, &acc_decode_data, @@ -361,8 +359,8 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { let to_ipk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec()); - let (res, [secret_from, _]) = NativeTokenTransfer(wallet_core) - .send_private_transfer_to_outer_account(from, to_npk, to_ipk, amount) + let (res, acc_decode_data) = NativeTokenTransfer(wallet_core) + .send_private_transfer_to_outer_account_gen(from, to_npk, to_ipk, amount) .await?; println!("Results of tx send are {res:#?}"); @@ -373,8 +371,6 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { .await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { - let acc_decode_data = vec![Decode(secret_from, from)]; - wallet_core.decode_insert_privacy_preserving_transaction_results( tx, &acc_decode_data, diff --git a/wallet/src/privacy_preserving_tx.rs b/wallet/src/privacy_preserving_tx.rs index 3bd0c4c..4805e0d 100644 --- a/wallet/src/privacy_preserving_tx.rs +++ b/wallet/src/privacy_preserving_tx.rs @@ -9,6 +9,7 @@ use nssa_core::{ use crate::WalletCore; +#[derive(Clone)] pub enum PrivacyPreservingAccount { Public(AccountId), PrivateOwned(AccountId), @@ -18,6 +19,22 @@ pub enum PrivacyPreservingAccount { }, } +impl PrivacyPreservingAccount { + pub fn account_id_decode_data(&self) -> Option { + match self { + &Self::PrivateOwned(acc_id) => Some(acc_id), + _ => None, + } + } + + pub fn is_private(&self) -> bool { + matches!( + &self, + &Self::PrivateOwned(_) | &Self::PrivateForeign { npk: _, ipk: _ } + ) + } +} + pub struct PrivateAccountKeys { pub npk: NullifierPublicKey, pub ssk: SharedSecretKey, diff --git a/wallet/src/program_facades/native_token_transfer/mod.rs b/wallet/src/program_facades/native_token_transfer/mod.rs index 693ef8d..03a41b6 100644 --- a/wallet/src/program_facades/native_token_transfer/mod.rs +++ b/wallet/src/program_facades/native_token_transfer/mod.rs @@ -1,8 +1,8 @@ -use common::error::ExecutionFailureKind; +use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse}; use nssa::{Account, program::Program}; use nssa_core::program::InstructionData; -use crate::WalletCore; +use crate::{AccDecodeData, PrivacyPreservingAccount, WalletCore}; pub mod deshielded; pub mod private; @@ -31,3 +31,45 @@ fn auth_transfer_preparation( (instruction_data, program, tx_pre_check) } + +impl NativeTokenTransfer<'_> { + pub async fn send_privacy_preserving_transfer_unified( + &self, + acc_vector: Vec, + method_data: u128, + ) -> Result<(SendTxResponse, Vec), ExecutionFailureKind> { + let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(method_data); + + self.0 + .send_privacy_preserving_tx_with_pre_check( + acc_vector.clone(), + &instruction_data, + &program, + tx_pre_check, + ) + .await + .map(|(resp, secrets)| { + let mut secrets_iter = secrets.into_iter(); + + ( + resp, + acc_vector + .into_iter() + .filter_map(|acc| { + if acc.is_private() { + let secret = secrets_iter.next().expect("expected next secret"); + + if let Some(acc_id) = acc.account_id_decode_data() { + Some(AccDecodeData::Decode(secret, acc_id)) + } else { + Some(AccDecodeData::Skip) + } + } else { + None + } + }) + .collect(), + ) + }) + } +} diff --git a/wallet/src/program_facades/native_token_transfer/private.rs b/wallet/src/program_facades/native_token_transfer/private.rs index 320027b..5caffa7 100644 --- a/wallet/src/program_facades/native_token_transfer/private.rs +++ b/wallet/src/program_facades/native_token_transfer/private.rs @@ -5,7 +5,7 @@ use nssa::{AccountId, program::Program}; use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey}; use super::{NativeTokenTransfer, auth_transfer_preparation}; -use crate::PrivacyPreservingAccount; +use crate::{AccDecodeData, PrivacyPreservingAccount}; impl NativeTokenTransfer<'_> { pub async fn register_account_private( @@ -29,6 +29,42 @@ impl NativeTokenTransfer<'_> { }) } + pub async fn send_private_transfer_to_owned_account_gen( + &self, + from: AccountId, + to: AccountId, + balance_to_move: u128, + ) -> Result<(SendTxResponse, Vec), ExecutionFailureKind> { + self.send_privacy_preserving_transfer_unified( + vec![ + PrivacyPreservingAccount::PrivateOwned(from), + PrivacyPreservingAccount::PrivateOwned(to), + ], + balance_to_move, + ) + .await + } + + pub async fn send_private_transfer_to_outer_account_gen( + &self, + from: AccountId, + to_npk: NullifierPublicKey, + to_ipk: IncomingViewingPublicKey, + balance_to_move: u128, + ) -> Result<(SendTxResponse, Vec), ExecutionFailureKind> { + self.send_privacy_preserving_transfer_unified( + vec![ + PrivacyPreservingAccount::PrivateOwned(from), + PrivacyPreservingAccount::PrivateForeign { + npk: to_npk, + ipk: to_ipk, + }, + ], + balance_to_move, + ) + .await + } + pub async fn send_private_transfer_to_outer_account( &self, from: AccountId,