diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index 5b21057..f09d808 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -42,6 +42,14 @@ pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12; pub const NSSA_PROGRAM_FOR_TEST_DATA_CHANGER: &[u8] = include_bytes!("data_changer.bin"); +fn make_public_account_input_from_str(addr: &str) -> String { + format!("Public/{addr:?}") +} + +fn make_private_account_input_from_str(addr: &str) -> String { + format!("Private/{addr:?}") +} + #[allow(clippy::type_complexity)] pub async fn pre_test( home_dir: PathBuf, diff --git a/integration_tests/src/test_suite_map.rs b/integration_tests/src/test_suite_map.rs index 67d78e8..7874b5c 100644 --- a/integration_tests/src/test_suite_map.rs +++ b/integration_tests/src/test_suite_map.rs @@ -8,18 +8,11 @@ use wallet::{ Command, SubcommandReturnValue, WalletCore, cli::{ account::{AccountSubcommand, FetchSubcommand, NewSubcommand}, - native_token_transfer_program::{ - NativeTokenTransferProgramSubcommand, NativeTokenTransferProgramSubcommandPrivate, - NativeTokenTransferProgramSubcommandShielded, - }, + native_token_transfer_program::AuthTransferSubcommand, pinata_program::{ PinataProgramSubcommand, PinataProgramSubcommandPrivate, PinataProgramSubcommandPublic, }, - token_program::{ - TokenProgramSubcommand, TokenProgramSubcommandDeshielded, - TokenProgramSubcommandPrivate, TokenProgramSubcommandPublic, - TokenProgramSubcommandShielded, - }, + token_program::TokenProgramAgnosticSubcommand, }, config::PersistentAccountData, helperfunctions::{fetch_config, fetch_persistent_accounts}, @@ -30,7 +23,8 @@ use sequencer_core::sequencer_store::PINATA_BASE58; use crate::{ ACC_RECEIVER, ACC_RECEIVER_PRIVATE, ACC_SENDER, ACC_SENDER_PRIVATE, NSSA_PROGRAM_FOR_TEST_DATA_CHANGER, TIME_TO_WAIT_FOR_BLOCK_SECONDS, - fetch_privacy_preserving_tx, + fetch_privacy_preserving_tx, make_private_account_input_from_str, + make_public_account_input_from_str, }; use crate::{post_test, pre_test, verify_commitment_is_in_state}; @@ -42,9 +36,11 @@ pub fn prepare_function_map() -> HashMap { #[test_suite_fn] pub async fn test_success() { info!("test_success"); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public { - from: ACC_SENDER.to_string(), - to: ACC_RECEIVER.to_string(), + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_public_account_input_from_str(ACC_SENDER), + to: Some(make_public_account_input_from_str(ACC_RECEIVER)), + to_npk: None, + to_ipk: None, amount: 100, }); @@ -103,9 +99,13 @@ pub fn prepare_function_map() -> HashMap { panic!("Failed to produce new account, not present in persistent accounts"); } - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public { - from: ACC_SENDER.to_string(), - to: new_persistent_account_addr.clone(), + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_public_account_input_from_str(ACC_SENDER), + to: Some(make_public_account_input_from_str( + &new_persistent_account_addr, + )), + to_npk: None, + to_ipk: None, amount: 100, }); @@ -136,9 +136,11 @@ pub fn prepare_function_map() -> HashMap { #[test_suite_fn] pub async fn test_failure() { info!("test_failure"); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public { - from: ACC_SENDER.to_string(), - to: ACC_RECEIVER.to_string(), + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_public_account_input_from_str(ACC_SENDER), + to: Some(make_public_account_input_from_str(ACC_RECEIVER)), + to_npk: None, + to_ipk: None, amount: 1000000, }); @@ -175,9 +177,11 @@ pub fn prepare_function_map() -> HashMap { #[test_suite_fn] pub async fn test_success_two_transactions() { info!("test_success_two_transactions"); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public { - from: ACC_SENDER.to_string(), - to: ACC_RECEIVER.to_string(), + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_public_account_input_from_str(ACC_SENDER), + to: Some(make_public_account_input_from_str(ACC_RECEIVER)), + to_npk: None, + to_ipk: None, amount: 100, }); @@ -208,9 +212,11 @@ pub fn prepare_function_map() -> HashMap { info!("First TX Success!"); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public { - from: ACC_SENDER.to_string(), - to: ACC_RECEIVER.to_string(), + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_public_account_input_from_str(ACC_SENDER), + to: Some(make_public_account_input_from_str(ACC_RECEIVER)), + to_npk: None, + to_ipk: None, amount: 100, }); @@ -306,13 +312,12 @@ pub fn prepare_function_map() -> HashMap { .expect("Failed to produce new account, not present in persistent accounts"); // Create new token - let subcommand = - TokenProgramSubcommand::Public(TokenProgramSubcommandPublic::CreateNewToken { - definition_addr: definition_addr.to_string(), - supply_addr: supply_addr.to_string(), - name: "A NAME".to_string(), - total_supply: 37, - }); + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_addr: make_public_account_input_from_str(&definition_addr.to_string()), + supply_addr: make_public_account_input_from_str(&supply_addr.to_string()), + name: "A NAME".to_string(), + total_supply: 37, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); @@ -361,12 +366,16 @@ pub fn prepare_function_map() -> HashMap { ); // Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = - TokenProgramSubcommand::Public(TokenProgramSubcommandPublic::TransferToken { - sender_addr: supply_addr.to_string(), - recipient_addr: recipient_addr.to_string(), - balance_to_move: 7, - }); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_public_account_input_from_str(&supply_addr.to_string()), + to: Some(make_public_account_input_from_str( + &recipient_addr.to_string(), + )), + to_npk: None, + to_ipk: None, + amount: 7, + }; + wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); @@ -449,14 +458,12 @@ pub fn prepare_function_map() -> HashMap { }; // Create new token - let subcommand = TokenProgramSubcommand::Private( - TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned { - definition_addr: definition_addr.to_string(), - supply_addr: supply_addr.to_string(), - name: "A NAME".to_string(), - total_supply: 37, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_addr: make_public_account_input_from_str(&definition_addr.to_string()), + supply_addr: make_private_account_input_from_str(&supply_addr.to_string()), + name: "A NAME".to_string(), + total_supply: 37, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -495,13 +502,15 @@ pub fn prepare_function_map() -> HashMap { assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); // Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = TokenProgramSubcommand::Private( - TokenProgramSubcommandPrivate::TransferTokenPrivateOwned { - sender_addr: supply_addr.to_string(), - recipient_addr: recipient_addr.to_string(), - balance_to_move: 7, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_private_account_input_from_str(&supply_addr.to_string()), + to: Some(make_private_account_input_from_str( + &recipient_addr.to_string(), + )), + to_npk: None, + to_ipk: None, + amount: 7, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -526,13 +535,15 @@ pub fn prepare_function_map() -> HashMap { assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); // Transfer additional 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = TokenProgramSubcommand::Private( - TokenProgramSubcommandPrivate::TransferTokenPrivateOwned { - sender_addr: supply_addr.to_string(), - recipient_addr: recipient_addr.to_string(), - balance_to_move: 7, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_private_account_input_from_str(&supply_addr.to_string()), + to: Some(make_private_account_input_from_str( + &recipient_addr.to_string(), + )), + to_npk: None, + to_ipk: None, + amount: 7, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -597,14 +608,12 @@ pub fn prepare_function_map() -> HashMap { }; // Create new token - let subcommand = TokenProgramSubcommand::Private( - TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned { - definition_addr: definition_addr.to_string(), - supply_addr: supply_addr.to_string(), - name: "A NAME".to_string(), - total_supply: 37, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_addr: make_public_account_input_from_str(&definition_addr.to_string()), + supply_addr: make_private_account_input_from_str(&supply_addr.to_string()), + name: "A NAME".to_string(), + total_supply: 37, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -649,14 +658,15 @@ pub fn prepare_function_map() -> HashMap { .unwrap(); // Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = TokenProgramSubcommand::Private( - TokenProgramSubcommandPrivate::TransferTokenPrivateForeign { - sender_addr: supply_addr.to_string(), - recipient_npk: hex::encode(recipient_keys.nullifer_public_key.0), - recipient_ipk: hex::encode(recipient_keys.incoming_viewing_public_key.0.clone()), - balance_to_move: 7, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_private_account_input_from_str(&supply_addr.to_string()), + to: None, + to_npk: Some(hex::encode(recipient_keys.nullifer_public_key.0)), + to_ipk: Some(hex::encode( + recipient_keys.incoming_viewing_public_key.0.clone(), + )), + amount: 7, + }; let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = wallet::execute_subcommand(Command::Token(subcommand)) @@ -733,13 +743,12 @@ pub fn prepare_function_map() -> HashMap { }; // Create new token - let subcommand = - TokenProgramSubcommand::Public(TokenProgramSubcommandPublic::CreateNewToken { - definition_addr: definition_addr.to_string(), - supply_addr: supply_addr.to_string(), - name: "A NAME".to_string(), - total_supply: 37, - }); + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_addr: make_public_account_input_from_str(&definition_addr.to_string()), + supply_addr: make_public_account_input_from_str(&supply_addr.to_string()), + name: "A NAME".to_string(), + total_supply: 37, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -768,13 +777,15 @@ pub fn prepare_function_map() -> HashMap { ); // Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = TokenProgramSubcommand::Shielded( - TokenProgramSubcommandShielded::TransferTokenShieldedOwned { - sender_addr: supply_addr.to_string(), - recipient_addr: recipient_addr.to_string(), - balance_to_move: 7, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_public_account_input_from_str(&supply_addr.to_string()), + to: Some(make_private_account_input_from_str( + &recipient_addr.to_string(), + )), + to_npk: None, + to_ipk: None, + amount: 7, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -794,13 +805,15 @@ pub fn prepare_function_map() -> HashMap { assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); // Transfer additional 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = TokenProgramSubcommand::Shielded( - TokenProgramSubcommandShielded::TransferTokenShieldedOwned { - sender_addr: supply_addr.to_string(), - recipient_addr: recipient_addr.to_string(), - balance_to_move: 7, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_public_account_input_from_str(&supply_addr.to_string()), + to: Some(make_private_account_input_from_str( + &recipient_addr.to_string(), + )), + to_npk: None, + to_ipk: None, + amount: 7, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -860,14 +873,12 @@ pub fn prepare_function_map() -> HashMap { }; // Create new token - let subcommand = TokenProgramSubcommand::Private( - TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned { - definition_addr: definition_addr.to_string(), - supply_addr: supply_addr.to_string(), - name: "A NAME".to_string(), - total_supply: 37, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_addr: make_public_account_input_from_str(&definition_addr.to_string()), + supply_addr: make_private_account_input_from_str(&supply_addr.to_string()), + name: "A NAME".to_string(), + total_supply: 37, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -906,13 +917,15 @@ pub fn prepare_function_map() -> HashMap { assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); // Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = TokenProgramSubcommand::Deshielded( - TokenProgramSubcommandDeshielded::TransferTokenDeshielded { - sender_addr: supply_addr.to_string(), - recipient_addr: recipient_addr.to_string(), - balance_to_move: 7, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_private_account_input_from_str(&supply_addr.to_string()), + to: Some(make_public_account_input_from_str( + &recipient_addr.to_string(), + )), + to_npk: None, + to_ipk: None, + amount: 7, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -932,13 +945,15 @@ pub fn prepare_function_map() -> HashMap { assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); // Transfer additional 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = TokenProgramSubcommand::Deshielded( - TokenProgramSubcommandDeshielded::TransferTokenDeshielded { - sender_addr: supply_addr.to_string(), - recipient_addr: recipient_addr.to_string(), - balance_to_move: 7, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_private_account_input_from_str(&supply_addr.to_string()), + to: Some(make_public_account_input_from_str( + &recipient_addr.to_string(), + )), + to_npk: None, + to_ipk: None, + amount: 7, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -964,13 +979,13 @@ pub fn prepare_function_map() -> HashMap { let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap(); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private( - NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { - from: from.to_string(), - to: to.to_string(), - amount: 100, - }, - )); + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_private_account_input_from_str(&from.to_string()), + to: Some(make_private_account_input_from_str(&to.to_string())), + to_npk: None, + to_ipk: None, + amount: 100, + }); wallet::execute_subcommand(command).await.unwrap(); @@ -1002,14 +1017,13 @@ pub fn prepare_function_map() -> HashMap { let to_npk_string = hex::encode(to_npk.0); let to_ipk = Secp256k1Point::from_scalar(to_npk.0); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private( - NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { - from: from.to_string(), - to_npk: to_npk_string, - to_ipk: hex::encode(to_ipk.0), - amount: 100, - }, - )); + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_private_account_input_from_str(&from.to_string()), + to: None, + to_npk: Some(to_npk_string), + to_ipk: Some(hex::encode(to_ipk.0)), + amount: 100, + }); let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = wallet::execute_subcommand(command).await.unwrap() @@ -1067,14 +1081,13 @@ pub fn prepare_function_map() -> HashMap { .cloned() .unwrap(); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private( - NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { - from: from.to_string(), - to_npk: hex::encode(to_keys.nullifer_public_key.0), - to_ipk: hex::encode(to_keys.incoming_viewing_public_key.0), - amount: 100, - }, - )); + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_private_account_input_from_str(&from.to_string()), + to: None, + to_npk: Some(hex::encode(to_keys.nullifer_public_key.0)), + to_ipk: Some(hex::encode(to_keys.incoming_viewing_public_key.0)), + amount: 100, + }); let sub_ret = wallet::execute_subcommand(command).await.unwrap(); let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else { @@ -1138,14 +1151,13 @@ pub fn prepare_function_map() -> HashMap { .cloned() .unwrap(); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private( - NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { - from: from.to_string(), - to_npk: hex::encode(to_keys.nullifer_public_key.0), - to_ipk: hex::encode(to_keys.incoming_viewing_public_key.0), - amount: 100, - }, - )); + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_private_account_input_from_str(&from.to_string()), + to: None, + to_npk: Some(hex::encode(to_keys.nullifer_public_key.0)), + to_ipk: Some(hex::encode(to_keys.incoming_viewing_public_key.0)), + amount: 100, + }); let sub_ret = wallet::execute_subcommand(command).await.unwrap(); let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else { @@ -1186,9 +1198,12 @@ pub fn prepare_function_map() -> HashMap { info!("test_success_deshielded_transfer_to_another_account"); let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); let to: Address = ACC_RECEIVER.parse().unwrap(); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Deshielded { - from: from.to_string(), - to: to.to_string(), + + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_private_account_input_from_str(&from.to_string()), + to: Some(make_public_account_input_from_str(&to.to_string())), + to_npk: None, + to_ipk: None, amount: 100, }); @@ -1232,13 +1247,14 @@ pub fn prepare_function_map() -> HashMap { info!("test_success_shielded_transfer_to_another_owned_account"); let from: Address = ACC_SENDER.parse().unwrap(); let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap(); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Shielded( - NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { - from: from.to_string(), - to: to.to_string(), - amount: 100, - }, - )); + + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_public_account_input_from_str(&from.to_string()), + to: Some(make_private_account_input_from_str(&to.to_string())), + to_npk: None, + to_ipk: None, + amount: 100, + }); let wallet_config = fetch_config().await.unwrap(); let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); @@ -1276,14 +1292,13 @@ pub fn prepare_function_map() -> HashMap { let to_ipk = Secp256k1Point::from_scalar(to_npk.0); let from: Address = ACC_SENDER.parse().unwrap(); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Shielded( - NativeTokenTransferProgramSubcommandShielded::ShieldedForeign { - from: from.to_string(), - to_npk: to_npk_string, - to_ipk: hex::encode(to_ipk.0), - amount: 100, - }, - )); + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_public_account_input_from_str(&from.to_string()), + to: None, + to_npk: Some(to_npk_string), + to_ipk: Some(hex::encode(to_ipk.0)), + amount: 100, + }); let wallet_config = fetch_config().await.unwrap(); diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index d7dac7d..b902346 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -82,6 +82,8 @@ pub enum AccountSubcommand { ///New #[command(subcommand)] New(NewSubcommand), + ///Sync private accounts + SyncPrivate {}, } ///Represents generic getter CLI subcommand @@ -213,7 +215,7 @@ impl WalletSubcommand for NewSubcommand { "Generated new account with addr {}", addr.to_bytes().to_base58() ); - println!("With npk {}", hex::encode(&key.nullifer_public_key.0)); + println!("With npk {}", hex::encode(key.nullifer_public_key.0)); println!( "With ipk {}", hex::encode(key.incoming_viewing_public_key.to_bytes()) @@ -303,12 +305,12 @@ impl WalletSubcommand for AccountSubcommand { let token_prog_id = Program::token().id(); let acc_view = match &account.program_owner { - _ if &account.program_owner == &auth_tr_prog_id => { + _ if account.program_owner == auth_tr_prog_id => { let acc_view: AuthenticatedTransferAccountView = account.into(); serde_json::to_string(&acc_view)? } - _ if &account.program_owner == &token_prog_id => { + _ if account.program_owner == token_prog_id => { if let Some(token_def) = TokenDefinition::parse(&account.data) { let acc_view: TokedDefinitionAccountView = token_def.into(); @@ -337,6 +339,9 @@ impl WalletSubcommand for AccountSubcommand { AccountSubcommand::New(new_subcommand) => { new_subcommand.handle_subcommand(wallet_core).await } + AccountSubcommand::SyncPrivate {} => { + todo!(); + } } } } diff --git a/wallet/src/cli/native_token_transfer_program.rs b/wallet/src/cli/native_token_transfer_program.rs index b568931..883e850 100644 --- a/wallet/src/cli/native_token_transfer_program.rs +++ b/wallet/src/cli/native_token_transfer_program.rs @@ -3,7 +3,187 @@ use clap::Subcommand; use common::transaction::NSSATransaction; use nssa::Address; -use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand}; +use crate::{ + SubcommandReturnValue, WalletCore, + cli::WalletSubcommand, + helperfunctions::{AddressPrivacyKind, parse_addr_with_privacy_prefix}, +}; + +///Represents generic CLI subcommand for a wallet working with native token transfer program +#[derive(Subcommand, Debug, Clone)] +pub enum AuthTransferSubcommand { + Init { + ///addr - valid 32 byte base58 string + #[arg(long)] + addr: String, + }, + Send { + ///from - valid 32 byte base58 string + #[arg(long)] + from: String, + ///to - valid 32 byte base58 string + #[arg(long)] + to: Option, + ///to_npk - valid 32 byte base58 string + #[arg(long)] + to_npk: Option, + ///to_ipk - valid 33 byte base58 string + #[arg(long)] + to_ipk: Option, + ///amount - amount of balance to move + #[arg(long)] + amount: u128, + }, +} + +impl WalletSubcommand for AuthTransferSubcommand { + async fn handle_subcommand( + self, + wallet_core: &mut WalletCore, + ) -> Result { + match self { + AuthTransferSubcommand::Init { addr } => { + let (addr, addr_privacy) = parse_addr_with_privacy_prefix(&addr)?; + + match addr_privacy { + AddressPrivacyKind::Public => { + let res = wallet_core + .register_account_under_authenticated_transfers_programs(addr) + .await?; + + println!("Results of tx send is {res:#?}"); + + let transfer_tx = + wallet_core.poll_native_token_transfer(res.tx_hash).await?; + + println!("Transaction data is {transfer_tx:?}"); + + let path = wallet_core.store_persistent_accounts().await?; + + println!("Stored persistent accounts at {path:#?}"); + } + AddressPrivacyKind::Private => { + let (res, [secret]) = wallet_core + .register_account_under_authenticated_transfers_programs_private(addr) + .await?; + + println!("Results of tx send is {res:#?}"); + + let tx_hash = res.tx_hash; + let transfer_tx = wallet_core + .poll_native_token_transfer(tx_hash.clone()) + .await?; + + if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + let acc_decode_data = vec![(secret, addr)]; + + wallet_core.decode_insert_privacy_preserving_transaction_results( + tx, + &acc_decode_data, + )?; + } + + let path = wallet_core.store_persistent_accounts().await?; + + println!("Stored persistent accounts at {path:#?}"); + } + } + + Ok(SubcommandReturnValue::Empty) + } + AuthTransferSubcommand::Send { + from, + to, + to_npk, + to_ipk, + amount, + } => { + let underlying_subcommand = match (to, to_npk, to_ipk) { + (None, None, None) => { + anyhow::bail!( + "Provide either account address of receiver or their public keys" + ); + } + (Some(_), Some(_), Some(_)) => { + anyhow::bail!( + "Provide only one variant: either account address of receiver or their public keys" + ); + } + (_, Some(_), None) | (_, None, Some(_)) => { + anyhow::bail!("List of public keys is uncomplete"); + } + (Some(to), None, None) => { + let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?; + let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?; + + match (from_privacy, to_privacy) { + (AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { + NativeTokenTransferProgramSubcommand::Public { + from: from.to_string(), + to: to.to_string(), + amount, + } + } + (AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { + NativeTokenTransferProgramSubcommand::Private( + NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { + from: from.to_string(), + to: to.to_string(), + amount, + }, + ) + } + (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { + NativeTokenTransferProgramSubcommand::Deshielded { + from: from.to_string(), + to: to.to_string(), + amount, + } + } + (AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { + NativeTokenTransferProgramSubcommand::Shielded( + NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { + from: from.to_string(), + to: to.to_string(), + amount, + }, + ) + } + } + } + (None, Some(to_npk), Some(to_ipk)) => { + let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?; + + match from_privacy { + AddressPrivacyKind::Private => { + NativeTokenTransferProgramSubcommand::Private( + NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { + from: from.to_string(), + to_npk, + to_ipk, + amount, + }, + ) + } + AddressPrivacyKind::Public => { + NativeTokenTransferProgramSubcommand::Shielded( + NativeTokenTransferProgramSubcommandShielded::ShieldedForeign { + from: from.to_string(), + to_npk, + to_ipk, + amount, + }, + ) + } + } + } + }; + + underlying_subcommand.handle_subcommand(wallet_core).await + } + } + } +} ///Represents generic CLI subcommand for a wallet working with native token transfer program #[derive(Subcommand, Debug, Clone)] diff --git a/wallet/src/cli/token_program.rs b/wallet/src/cli/token_program.rs index 25de77d..dc269e4 100644 --- a/wallet/src/cli/token_program.rs +++ b/wallet/src/cli/token_program.rs @@ -3,7 +3,187 @@ use clap::Subcommand; use common::transaction::NSSATransaction; use nssa::Address; -use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand}; +use crate::{ + SubcommandReturnValue, WalletCore, + cli::WalletSubcommand, + helperfunctions::{AddressPrivacyKind, parse_addr_with_privacy_prefix}, +}; + +///Represents generic CLI subcommand for a wallet working with token program +#[derive(Subcommand, Debug, Clone)] +pub enum TokenProgramAgnosticSubcommand { + New { + ///addr - valid 32 byte base58 string + #[arg(long)] + definition_addr: String, + ///addr - valid 32 byte base58 string + #[arg(long)] + supply_addr: String, + #[arg(short, long)] + name: String, + #[arg(short, long)] + total_supply: u128, + }, + Send { + ///from - valid 32 byte base58 string + #[arg(long)] + from: String, + ///to - valid 32 byte base58 string + #[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, + ///amount - amount of balance to move + #[arg(long)] + amount: u128, + }, +} + +impl WalletSubcommand for TokenProgramAgnosticSubcommand { + async fn handle_subcommand( + self, + wallet_core: &mut WalletCore, + ) -> Result { + match self { + TokenProgramAgnosticSubcommand::New { + definition_addr, + supply_addr, + name, + total_supply, + } => { + let (definition_addr, definition_addr_privacy) = + parse_addr_with_privacy_prefix(&definition_addr)?; + let (supply_addr, supply_addr_privacy) = + parse_addr_with_privacy_prefix(&supply_addr)?; + + let underlying_subcommand = match (definition_addr_privacy, supply_addr_privacy) { + (AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { + TokenProgramSubcommand::Public( + TokenProgramSubcommandPublic::CreateNewToken { + definition_addr: definition_addr.to_string(), + supply_addr: supply_addr.to_string(), + name, + total_supply, + }, + ) + } + (AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { + TokenProgramSubcommand::Private( + TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned { + definition_addr: definition_addr.to_string(), + supply_addr: supply_addr.to_string(), + name, + total_supply, + }, + ) + } + (AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { + todo!(); + } + (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { + todo!(); + } + }; + + underlying_subcommand.handle_subcommand(wallet_core).await + } + TokenProgramAgnosticSubcommand::Send { + from, + to, + to_npk, + to_ipk, + amount, + } => { + let underlying_subcommand = match (to, to_npk, to_ipk) { + (None, None, None) => { + anyhow::bail!( + "Provide either account address of receiver or their public keys" + ); + } + (Some(_), Some(_), Some(_)) => { + anyhow::bail!( + "Provide only one variant: either account address of receiver or their public keys" + ); + } + (_, Some(_), None) | (_, None, Some(_)) => { + anyhow::bail!("List of public keys is uncomplete"); + } + (Some(to), None, None) => { + let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?; + let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?; + + match (from_privacy, to_privacy) { + (AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { + TokenProgramSubcommand::Public( + TokenProgramSubcommandPublic::TransferToken { + sender_addr: from.to_string(), + recipient_addr: to.to_string(), + balance_to_move: amount, + }, + ) + } + (AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { + TokenProgramSubcommand::Private( + TokenProgramSubcommandPrivate::TransferTokenPrivateOwned { + sender_addr: from.to_string(), + recipient_addr: to.to_string(), + balance_to_move: amount, + }, + ) + } + (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { + TokenProgramSubcommand::Deshielded( + TokenProgramSubcommandDeshielded::TransferTokenDeshielded { + sender_addr: from.to_string(), + recipient_addr: to.to_string(), + balance_to_move: amount, + }, + ) + } + (AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { + TokenProgramSubcommand::Shielded( + TokenProgramSubcommandShielded::TransferTokenShieldedOwned { + sender_addr: from.to_string(), + recipient_addr: to.to_string(), + balance_to_move: amount, + }, + ) + } + } + } + (None, Some(to_npk), Some(to_ipk)) => { + let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?; + + match from_privacy { + AddressPrivacyKind::Private => TokenProgramSubcommand::Private( + TokenProgramSubcommandPrivate::TransferTokenPrivateForeign { + sender_addr: from.to_string(), + recipient_npk: to_npk, + recipient_ipk: to_ipk, + balance_to_move: amount, + }, + ), + AddressPrivacyKind::Public => TokenProgramSubcommand::Shielded( + TokenProgramSubcommandShielded::TransferTokenShieldedForeign { + sender_addr: from.to_string(), + recipient_npk: to_npk, + recipient_ipk: to_ipk, + balance_to_move: amount, + }, + ), + } + } + }; + + underlying_subcommand.handle_subcommand(wallet_core).await + } + } + } +} ///Represents generic CLI subcommand for a wallet working with token_program #[derive(Subcommand, Debug, Clone)] diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 5de7f5d..897b7d5 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -22,11 +22,10 @@ use tokio::io::AsyncWriteExt; use crate::cli::{ WalletSubcommand, account::AccountSubcommand, chain::ChainSubcommand, - native_token_transfer_program::NativeTokenTransferProgramSubcommand, - pinata_program::PinataProgramSubcommand, + native_token_transfer_program::AuthTransferSubcommand, pinata_program::PinataProgramSubcommand, + token_program::TokenProgramAgnosticSubcommand, }; use crate::{ - cli::token_program::TokenProgramSubcommand, helperfunctions::{ fetch_config, fetch_persistent_accounts, get_home, produce_data_for_storage, }, @@ -193,7 +192,7 @@ impl WalletCore { pub enum Command { ///Transfer command #[command(subcommand)] - AuthTransfer(NativeTokenTransferProgramSubcommand), + AuthTransfer(AuthTransferSubcommand), ///Chain command #[command(subcommand)] ChainInfo(ChainSubcommand), @@ -205,7 +204,7 @@ pub enum Command { Pinata(PinataProgramSubcommand), ///Token command #[command(subcommand)] - Token(TokenProgramSubcommand), + Token(TokenProgramAgnosticSubcommand), AuthenticatedTransferInitializePublicAccount {}, // Check the wallet can connect to the node and builtin local programs // match the remote versions diff --git a/wallet/src/transaction_utils.rs b/wallet/src/transaction_utils.rs index 0761fa7..2dd69ca 100644 --- a/wallet/src/transaction_utils.rs +++ b/wallet/src/transaction_utils.rs @@ -537,4 +537,53 @@ impl WalletCore { Ok(self.sequencer_client.send_tx_private(tx).await?) } + + pub async fn register_account_under_authenticated_transfers_programs_private( + &self, + from: Address, + ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { + let AccountPreparedData { + nsk: _, + npk: from_npk, + ipk: from_ipk, + auth_acc: sender_pre, + proof: _, + } = self.private_acc_preparation(from, false, false).await?; + + let eph_holder_from = EphemeralKeyHolder::new(&from_npk); + let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk); + + let instruction: u128 = 0; + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre], + &Program::serialize_instruction(instruction).unwrap(), + &[2], + &produce_random_nonces(1), + &[(from_npk.clone(), shared_secret_from.clone())], + &[], + &Program::authenticated_transfer_program(), + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![], + vec![], + vec![( + from_npk.clone(), + from_ipk.clone(), + eph_holder_from.generate_ephemeral_public_key(), + )], + output, + ) + .unwrap(); + + let witness_set = WitnessSet::for_message(&message, proof, &[]); + let tx = PrivacyPreservingTransaction::new(message, witness_set); + + Ok(( + self.sequencer_client.send_tx_private(tx).await?, + [shared_secret_from], + )) + } }