From 5b7e162e4d6db4ca4cec6b1578d3bd4b9792252d Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Tue, 21 Oct 2025 10:32:42 +0300 Subject: [PATCH 1/7] fix: wallet transaction creation refactor --- .../src/cli/native_token_transfer_program.rs | 6 +- wallet/src/lib.rs | 1 + wallet/src/token_program_interactions.rs | 742 +++--------------- wallet/src/token_transfers/deshielded.rs | 80 +- wallet/src/token_transfers/mod.rs | 28 + wallet/src/token_transfers/private.rs | 288 +------ wallet/src/token_transfers/shielded.rs | 210 +---- wallet/src/transaction_utils.rs | 538 +++++++++++++ 8 files changed, 757 insertions(+), 1136 deletions(-) create mode 100644 wallet/src/transaction_utils.rs diff --git a/wallet/src/cli/native_token_transfer_program.rs b/wallet/src/cli/native_token_transfer_program.rs index 666ea68..b568931 100644 --- a/wallet/src/cli/native_token_transfer_program.rs +++ b/wallet/src/cli/native_token_transfer_program.rs @@ -224,7 +224,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded { let to_initialization = wallet_core.check_private_account_initialized(&to).await?; - let (res, secret) = if let Some(to_proof) = to_initialization { + let (res, [secret]) = if let Some(to_proof) = to_initialization { wallet_core .send_shielded_native_token_transfer_already_initialized( from, to, amount, to_proof, @@ -277,7 +277,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded { let to_ipk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec()); - let (res, _) = wallet_core + let res = wallet_core .send_shielded_native_token_transfer_outer_account(from, to_npk, to_ipk, amount) .await?; @@ -311,7 +311,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand { let from: Address = from.parse().unwrap(); let to: Address = to.parse().unwrap(); - let (res, secret) = wallet_core + let (res, [secret]) = wallet_core .send_deshielded_native_token_transfer(from, to, amount) .await?; diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 5adfa39..833422f 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -43,6 +43,7 @@ pub mod pinata_interactions; pub mod poller; pub mod token_program_interactions; pub mod token_transfers; +pub mod transaction_utils; pub struct WalletCore { pub storage: WalletChainStore, diff --git a/wallet/src/token_program_interactions.rs b/wallet/src/token_program_interactions.rs index a77a512..4e30a4b 100644 --- a/wallet/src/token_program_interactions.rs +++ b/wallet/src/token_program_interactions.rs @@ -1,14 +1,50 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; -use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; -use nssa::{Address, privacy_preserving_transaction::circuit, program::Program}; +use nssa::{Account, Address, program::Program}; use nssa_core::{ - Commitment, MembershipProof, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata, - encryption::IncomingViewingPublicKey, + MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey, + program::InstructionData, }; -use crate::{WalletCore, helperfunctions::produce_random_nonces}; +use crate::WalletCore; impl WalletCore { + pub fn token_program_preparation_transfer( + amount: u128, + ) -> ( + InstructionData, + Program, + impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + ) { + // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. + let mut instruction = [0; 23]; + instruction[0] = 0x01; + instruction[1..17].copy_from_slice(&amount.to_le_bytes()); + let instruction_data = Program::serialize_instruction(instruction).unwrap(); + let program = Program::token(); + let tx_pre_check = |_: &Account, _: &Account| Ok(()); + + (instruction_data, program, tx_pre_check) + } + + pub fn token_program_preparation_definition( + name: [u8; 6], + total_supply: u128, + ) -> ( + InstructionData, + Program, + impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + ) { + // Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)] + let mut instruction = [0; 23]; + instruction[1..17].copy_from_slice(&total_supply.to_le_bytes()); + instruction[17..].copy_from_slice(&name); + let instruction_data = Program::serialize_instruction(instruction).unwrap(); + let program = Program::token(); + let tx_pre_check = |_: &Account, _: &Account| Ok(()); + + (instruction_data, program, tx_pre_check) + } + pub async fn send_new_token_definition( &self, definition_address: Address, @@ -40,71 +76,19 @@ impl WalletCore { name: [u8; 6], total_supply: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { - let Some((supply_keys, supply_acc)) = self - .storage - .user_data - .get_private_account(&supply_addr) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_definition(name, total_supply); - //It makes more sence to have definition acc as public - let definition_acc = self.get_account_public(definition_addr).await.unwrap(); - - let supply_npk = supply_keys.nullifer_public_key; - let supply_ipk = supply_keys.incoming_viewing_public_key; - - let program = nssa::program::Program::token(); - - let definition_pre = - AccountWithMetadata::new(definition_acc.clone(), false, definition_addr); - let supply_pre = AccountWithMetadata::new(supply_acc.clone(), false, &supply_npk); - - let eph_holder_supply = EphemeralKeyHolder::new(&supply_npk); - let shared_secret_supply = eph_holder_supply.calculate_shared_secret_sender(&supply_ipk); - - // Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)] - let mut instruction = [0; 23]; - instruction[1..17].copy_from_slice(&total_supply.to_le_bytes()); - instruction[17..].copy_from_slice(&name); - - let (output, proof) = circuit::execute_and_prove( - &[definition_pre, supply_pre], - &nssa::program::Program::serialize_instruction(instruction).unwrap(), - &[0, 2], - &produce_random_nonces(1), - &[(supply_npk.clone(), shared_secret_supply.clone())], - &[], - &program, + // Kind of non-obvious naming + // Basically this funtion is called because authentication mask is [0, 2] + self.shielded_two_accs_receiver_uninit( + definition_addr, + supply_addr, + instruction_data, + tx_pre_check, + program, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![definition_addr], - vec![], - vec![( - supply_npk.clone(), - supply_ipk.clone(), - eph_holder_supply.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_supply], - )) + .await } pub async fn send_transfer_token_transaction( @@ -148,107 +132,18 @@ impl WalletCore { amount: u128, recipient_proof: MembershipProof, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((sender_keys, sender_acc)) = self - .storage - .user_data - .get_private_account(&sender_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_transfer(amount); - let Some((recipient_keys, recipient_acc)) = self - .storage - .user_data - .get_private_account(&recipient_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let sender_npk = sender_keys.nullifer_public_key; - let sender_ipk = sender_keys.incoming_viewing_public_key; - let recipient_npk = recipient_keys.nullifer_public_key.clone(); - let recipient_ipk = recipient_keys.incoming_viewing_public_key.clone(); - - let program = Program::token(); - - let sender_commitment = Commitment::new(&sender_npk, &sender_acc); - - let sender_pre = AccountWithMetadata::new(sender_acc.clone(), true, &sender_npk); - let recipient_pre = AccountWithMetadata::new(recipient_acc.clone(), true, &recipient_npk); - - let eph_holder_sender = EphemeralKeyHolder::new(&sender_npk); - let shared_secret_sender = eph_holder_sender.calculate_shared_secret_sender(&sender_ipk); - - let eph_holder_recipient = EphemeralKeyHolder::new(&recipient_npk); - let shared_secret_recipient = - eph_holder_recipient.calculate_shared_secret_sender(&recipient_ipk); - - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(instruction).unwrap(), - &[1, 1], - &produce_random_nonces(2), - &[ - (sender_npk.clone(), shared_secret_sender.clone()), - (recipient_npk.clone(), shared_secret_recipient.clone()), - ], - &[ - ( - sender_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - ), - ( - recipient_keys.private_key_holder.nullifier_secret_key, - recipient_proof, - ), - ], - &program, + self.private_tx_two_accs_all_init( + sender_address, + recipient_address, + instruction_data, + tx_pre_check, + program, + recipient_proof, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![], - vec![], - vec![ - ( - sender_npk.clone(), - sender_ipk.clone(), - eph_holder_sender.generate_ephemeral_public_key(), - ), - ( - recipient_npk.clone(), - recipient_ipk.clone(), - eph_holder_recipient.generate_ephemeral_public_key(), - ), - ], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_sender, shared_secret_recipient], - )) + .await } pub async fn send_transfer_token_transaction_private_owned_account_not_initialized( @@ -257,101 +152,17 @@ impl WalletCore { recipient_address: Address, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((sender_keys, sender_acc)) = self - .storage - .user_data - .get_private_account(&sender_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_transfer(amount); - let Some((recipient_keys, recipient_acc)) = self - .storage - .user_data - .get_private_account(&recipient_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let sender_npk = sender_keys.nullifer_public_key; - let sender_ipk = sender_keys.incoming_viewing_public_key; - let recipient_npk = recipient_keys.nullifer_public_key.clone(); - let recipient_ipk = recipient_keys.incoming_viewing_public_key.clone(); - - let program = Program::token(); - - let sender_commitment = Commitment::new(&sender_npk, &sender_acc); - - let sender_pre = AccountWithMetadata::new(sender_acc.clone(), true, &sender_npk); - let recipient_pre = AccountWithMetadata::new(recipient_acc.clone(), false, &recipient_npk); - - let eph_holder_sender = EphemeralKeyHolder::new(&sender_npk); - let shared_secret_sender = eph_holder_sender.calculate_shared_secret_sender(&sender_ipk); - - let eph_holder_recipient = EphemeralKeyHolder::new(&recipient_npk); - let shared_secret_recipient = - eph_holder_recipient.calculate_shared_secret_sender(&recipient_ipk); - - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(instruction).unwrap(), - &[1, 2], - &produce_random_nonces(2), - &[ - (sender_npk.clone(), shared_secret_sender.clone()), - (recipient_npk.clone(), shared_secret_recipient.clone()), - ], - &[( - sender_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - )], - &program, + self.private_tx_two_accs_receiver_uninit( + sender_address, + recipient_address, + instruction_data, + tx_pre_check, + program, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![], - vec![], - vec![ - ( - sender_npk.clone(), - sender_ipk.clone(), - eph_holder_sender.generate_ephemeral_public_key(), - ), - ( - recipient_npk.clone(), - recipient_ipk.clone(), - eph_holder_recipient.generate_ephemeral_public_key(), - ), - ], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_sender, shared_secret_recipient], - )) + .await } pub async fn send_transfer_token_transaction_private_foreign_account( @@ -361,92 +172,18 @@ impl WalletCore { recipient_ipk: IncomingViewingPublicKey, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((sender_keys, sender_acc)) = self - .storage - .user_data - .get_private_account(&sender_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_transfer(amount); - let recipient_acc = nssa_core::account::Account::default(); - - let sender_npk = sender_keys.nullifer_public_key; - let sender_ipk = sender_keys.incoming_viewing_public_key; - - let program = Program::token(); - - let sender_commitment = Commitment::new(&sender_npk, &sender_acc); - - let sender_pre = AccountWithMetadata::new(sender_acc.clone(), true, &sender_npk); - let recipient_pre = AccountWithMetadata::new(recipient_acc.clone(), false, &recipient_npk); - - let eph_holder_sender = EphemeralKeyHolder::new(&sender_npk); - let shared_secret_sender = eph_holder_sender.calculate_shared_secret_sender(&sender_ipk); - - let eph_holder_recipient = EphemeralKeyHolder::new(&recipient_npk); - let shared_secret_recipient = - eph_holder_recipient.calculate_shared_secret_sender(&recipient_ipk); - - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(instruction).unwrap(), - &[1, 2], - &produce_random_nonces(2), - &[ - (sender_npk.clone(), shared_secret_sender.clone()), - (recipient_npk.clone(), shared_secret_recipient.clone()), - ], - &[( - sender_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - )], - &program, + self.private_tx_two_accs_receiver_outer( + sender_address, + recipient_npk, + recipient_ipk, + instruction_data, + tx_pre_check, + program, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![], - vec![], - vec![ - ( - sender_npk.clone(), - sender_ipk.clone(), - eph_holder_sender.generate_ephemeral_public_key(), - ), - ( - recipient_npk.clone(), - recipient_ipk.clone(), - eph_holder_recipient.generate_ephemeral_public_key(), - ), - ], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_sender, shared_secret_recipient], - )) + .await } pub async fn send_transfer_token_transaction_deshielded( @@ -455,81 +192,17 @@ impl WalletCore { recipient_address: Address, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { - let Some((sender_keys, sender_acc)) = self - .storage - .user_data - .get_private_account(&sender_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_transfer(amount); - let Ok(recipient_acc) = self.get_account_public(recipient_address).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let sender_npk = sender_keys.nullifer_public_key; - let sender_ipk = sender_keys.incoming_viewing_public_key; - - let program = Program::token(); - - let sender_commitment = Commitment::new(&sender_npk, &sender_acc); - - let sender_pre = AccountWithMetadata::new(sender_acc.clone(), true, &sender_npk); - let recipient_pre = - AccountWithMetadata::new(recipient_acc.clone(), false, recipient_address); - - let eph_holder_sender = EphemeralKeyHolder::new(&sender_npk); - let shared_secret_sender = eph_holder_sender.calculate_shared_secret_sender(&sender_ipk); - - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(instruction).unwrap(), - &[1, 0], - &produce_random_nonces(1), - &[(sender_npk.clone(), shared_secret_sender.clone())], - &[( - sender_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - )], - &program, + self.deshielded_tx_two_accs( + sender_address, + recipient_address, + instruction_data, + tx_pre_check, + program, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![recipient_address], - vec![], - vec![( - sender_npk.clone(), - sender_ipk.clone(), - eph_holder_sender.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_sender], - )) + .await } pub async fn send_transfer_token_transaction_shielded_owned_account_already_initialized( @@ -539,83 +212,18 @@ impl WalletCore { amount: u128, recipient_proof: MembershipProof, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { - let Ok(sender_acc) = self.get_account_public(sender_address).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_transfer(amount); - let Some(sender_priv_key) = self - .storage - .user_data - .get_pub_account_signing_key(&sender_address) - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let Some((recipient_keys, recipient_acc)) = self - .storage - .user_data - .get_private_account(&recipient_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let recipient_npk = recipient_keys.nullifer_public_key.clone(); - let recipient_ipk = recipient_keys.incoming_viewing_public_key.clone(); - - let program = Program::token(); - - let sender_pre = AccountWithMetadata::new(sender_acc.clone(), true, sender_address); - let recipient_pre = AccountWithMetadata::new(recipient_acc.clone(), true, &recipient_npk); - - let eph_holder_recipient = EphemeralKeyHolder::new(&recipient_npk); - let shared_secret_recipient = - eph_holder_recipient.calculate_shared_secret_sender(&recipient_ipk); - - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(instruction).unwrap(), - &[0, 1], - &produce_random_nonces(1), - &[(recipient_npk.clone(), shared_secret_recipient.clone())], - &[( - recipient_keys.private_key_holder.nullifier_secret_key, - recipient_proof, - )], - &program, + self.shielded_two_accs_all_init( + sender_address, + recipient_address, + instruction_data, + tx_pre_check, + program, + recipient_proof, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![sender_address], - vec![sender_acc.nonce], - vec![( - recipient_npk.clone(), - recipient_ipk.clone(), - eph_holder_recipient.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[sender_priv_key], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_recipient], - )) + .await } pub async fn send_transfer_token_transaction_shielded_owned_account_not_initialized( @@ -624,80 +232,17 @@ impl WalletCore { recipient_address: Address, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { - let Ok(sender_acc) = self.get_account_public(sender_address).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_transfer(amount); - let Some(sender_priv_key) = self - .storage - .user_data - .get_pub_account_signing_key(&sender_address) - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let Some((recipient_keys, recipient_acc)) = self - .storage - .user_data - .get_private_account(&recipient_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let recipient_npk = recipient_keys.nullifer_public_key.clone(); - let recipient_ipk = recipient_keys.incoming_viewing_public_key.clone(); - - let program = Program::token(); - - let sender_pre = AccountWithMetadata::new(sender_acc.clone(), true, sender_address); - let recipient_pre = AccountWithMetadata::new(recipient_acc.clone(), false, &recipient_npk); - - let eph_holder_recipient = EphemeralKeyHolder::new(&recipient_npk); - let shared_secret_recipient = - eph_holder_recipient.calculate_shared_secret_sender(&recipient_ipk); - - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(instruction).unwrap(), - &[0, 2], - &produce_random_nonces(1), - &[(recipient_npk.clone(), shared_secret_recipient.clone())], - &[], - &program, + self.shielded_two_accs_receiver_uninit( + sender_address, + recipient_address, + instruction_data, + tx_pre_check, + program, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![sender_address], - vec![sender_acc.nonce], - vec![( - recipient_npk.clone(), - recipient_ipk.clone(), - eph_holder_recipient.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[sender_priv_key], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_recipient], - )) + .await } pub async fn send_transfer_token_transaction_shielded_foreign_account( @@ -707,66 +252,17 @@ impl WalletCore { recipient_ipk: IncomingViewingPublicKey, amount: u128, ) -> Result { - let Ok(sender_acc) = self.get_account_public(sender_address).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_transfer(amount); - let Some(sender_priv_key) = self - .storage - .user_data - .get_pub_account_signing_key(&sender_address) - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let recipient_acc = nssa_core::account::Account::default(); - - let program = Program::token(); - - let sender_pre = AccountWithMetadata::new(sender_acc.clone(), true, sender_address); - let recipient_pre = AccountWithMetadata::new(recipient_acc.clone(), false, &recipient_npk); - - let eph_holder_recipient = EphemeralKeyHolder::new(&recipient_npk); - let shared_secret_recipient = - eph_holder_recipient.calculate_shared_secret_sender(&recipient_ipk); - - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(instruction).unwrap(), - &[0, 2], - &produce_random_nonces(1), - &[(recipient_npk.clone(), shared_secret_recipient.clone())], - &[], - &program, + self.shielded_two_accs_receiver_outer( + sender_address, + recipient_npk, + recipient_ipk, + instruction_data, + tx_pre_check, + program, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![sender_address], - vec![sender_acc.nonce], - vec![( - recipient_npk.clone(), - recipient_ipk.clone(), - eph_holder_recipient.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[sender_priv_key], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(self.sequencer_client.send_tx_private(tx).await?) + .await } } diff --git a/wallet/src/token_transfers/deshielded.rs b/wallet/src/token_transfers/deshielded.rs index 6bc812b..c724425 100644 --- a/wallet/src/token_transfers/deshielded.rs +++ b/wallet/src/token_transfers/deshielded.rs @@ -1,13 +1,7 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; -use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; -use nssa::{ - Address, PrivacyPreservingTransaction, - privacy_preserving_transaction::{circuit, message::Message, witness_set::WitnessSet}, - program::Program, -}; -use nssa_core::{Commitment, account::AccountWithMetadata}; +use nssa::Address; -use crate::{WalletCore, helperfunctions::produce_random_nonces}; +use crate::WalletCore; impl WalletCore { pub async fn send_deshielded_native_token_transfer( @@ -15,71 +9,11 @@ impl WalletCore { from: Address, to: Address, balance_to_move: u128, - ) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> { - let Some((from_keys, from_acc)) = - self.storage.user_data.get_private_account(&from).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + ) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 1]), ExecutionFailureKind> { + let (instruction_data, program, tx_pre_check) = + WalletCore::auth_transfer_preparation(balance_to_move); - let Ok(to_acc) = self.get_account_public(to).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - if from_acc.balance >= balance_to_move { - let program = Program::authenticated_transfer_program(); - - let npk_from = from_keys.nullifer_public_key; - let ipk_from = from_keys.incoming_viewing_public_key; - - let sender_commitment = Commitment::new(&npk_from, &from_acc); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &npk_from); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, to); - - let eph_holder = EphemeralKeyHolder::new(&npk_from); - let shared_secret = eph_holder.calculate_shared_secret_sender(&ipk_from); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(balance_to_move).unwrap(), - &[1, 0], - &produce_random_nonces(1), - &[(npk_from.clone(), shared_secret.clone())], - &[( - from_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - )], - &program, - ) - .unwrap(); - - let message = Message::try_from_circuit_output( - vec![to], - vec![], - vec![( - npk_from.clone(), - ipk_from.clone(), - eph_holder.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, - )) - } else { - Err(ExecutionFailureKind::InsufficientFundsError) - } + self.deshielded_tx_two_accs(from, to, instruction_data, tx_pre_check, program) + .await } } diff --git a/wallet/src/token_transfers/mod.rs b/wallet/src/token_transfers/mod.rs index edfbe3e..e87ce9a 100644 --- a/wallet/src/token_transfers/mod.rs +++ b/wallet/src/token_transfers/mod.rs @@ -1,4 +1,32 @@ +use common::ExecutionFailureKind; +use nssa::{Account, program::Program}; +use nssa_core::program::InstructionData; + +use crate::WalletCore; + pub mod deshielded; pub mod private; pub mod public; pub mod shielded; + +impl WalletCore { + pub fn auth_transfer_preparation( + balance_to_move: u128, + ) -> ( + InstructionData, + Program, + impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + ) { + let instruction_data = Program::serialize_instruction(balance_to_move).unwrap(); + let program = Program::authenticated_transfer_program(); + let tx_pre_check = move |from: &Account, _: &Account| { + if from.balance >= balance_to_move { + Ok(()) + } else { + Err(ExecutionFailureKind::InsufficientFundsError) + } + }; + + (instruction_data, program, tx_pre_check) + } +} diff --git a/wallet/src/token_transfers/private.rs b/wallet/src/token_transfers/private.rs index 0c6751b..35a9145 100644 --- a/wallet/src/token_transfers/private.rs +++ b/wallet/src/token_transfers/private.rs @@ -1,16 +1,10 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; -use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; -use nssa::{ - Address, PrivacyPreservingTransaction, - privacy_preserving_transaction::{circuit, message::Message, witness_set::WitnessSet}, - program::Program, -}; +use nssa::Address; use nssa_core::{ - Commitment, MembershipProof, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata, - encryption::IncomingViewingPublicKey, + MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey, }; -use crate::{WalletCore, helperfunctions::produce_random_nonces}; +use crate::WalletCore; impl WalletCore { pub async fn send_private_native_token_transfer_outer_account( @@ -20,82 +14,31 @@ impl WalletCore { to_ipk: IncomingViewingPublicKey, balance_to_move: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((from_keys, from_acc)) = - self.storage.user_data.get_private_account(&from).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::auth_transfer_preparation(balance_to_move); - let to_acc = nssa_core::account::Account::default(); + self.private_tx_two_accs_receiver_outer( + from, + to_npk, + to_ipk, + instruction_data, + tx_pre_check, + program, + ) + .await + } - if from_acc.balance >= balance_to_move { - let program = Program::authenticated_transfer_program(); + pub async fn send_private_native_token_transfer_owned_account_not_initialized( + &self, + from: Address, + to: Address, + balance_to_move: u128, + ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + let (instruction_data, program, tx_pre_check) = + WalletCore::auth_transfer_preparation(balance_to_move); - let from_npk = from_keys.nullifer_public_key; - let from_ipk = from_keys.incoming_viewing_public_key; - - let sender_commitment = Commitment::new(&from_npk, &from_acc); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); - - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); - - let eph_holder = EphemeralKeyHolder::new(&to_npk); - - let shared_secret_from = eph_holder.calculate_shared_secret_sender(&from_ipk); - let shared_secret_to = eph_holder.calculate_shared_secret_sender(&to_ipk); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(balance_to_move).unwrap(), - &[1, 2], - &produce_random_nonces(2), - &[ - (from_npk.clone(), shared_secret_from.clone()), - (to_npk.clone(), shared_secret_to.clone()), - ], - &[( - from_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - )], - &program, - ) - .unwrap(); - - let message = Message::try_from_circuit_output( - vec![], - vec![], - vec![ - ( - from_npk.clone(), - from_ipk.clone(), - eph_holder.generate_ephemeral_public_key(), - ), - ( - to_npk.clone(), - to_ipk.clone(), - eph_holder.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, shared_secret_to], - )) - } else { - Err(ExecutionFailureKind::InsufficientFundsError) - } + self.private_tx_two_accs_receiver_uninit(from, to, instruction_data, tx_pre_check, program) + .await } pub async fn send_private_native_token_transfer_owned_account_already_initialized( @@ -105,176 +48,17 @@ impl WalletCore { balance_to_move: u128, to_proof: MembershipProof, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((from_keys, from_acc)) = - self.storage.user_data.get_private_account(&from).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::auth_transfer_preparation(balance_to_move); - let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let from_npk = from_keys.nullifer_public_key; - let from_ipk = from_keys.incoming_viewing_public_key; - let to_npk = to_keys.nullifer_public_key.clone(); - let to_ipk = to_keys.incoming_viewing_public_key.clone(); - - if from_acc.balance >= balance_to_move { - let program = Program::authenticated_transfer_program(); - - let sender_commitment = Commitment::new(&from_npk, &from_acc); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk); - - let eph_holder_from = EphemeralKeyHolder::new(&from_npk); - let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk); - - let eph_holder_to = EphemeralKeyHolder::new(&to_npk); - let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_ipk); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(balance_to_move).unwrap(), - &[1, 1], - &produce_random_nonces(2), - &[ - (from_npk.clone(), shared_secret_from.clone()), - (to_npk.clone(), shared_secret_to.clone()), - ], - &[ - ( - from_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - ), - (to_keys.private_key_holder.nullifier_secret_key, to_proof), - ], - &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(), - ), - ( - to_npk.clone(), - to_ipk.clone(), - eph_holder_to.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, shared_secret_to], - )) - } else { - Err(ExecutionFailureKind::InsufficientFundsError) - } - } - - pub async fn send_private_native_token_transfer_owned_account_not_initialized( - &self, - from: Address, - to: Address, - balance_to_move: u128, - ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((from_keys, from_acc)) = - self.storage.user_data.get_private_account(&from).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let from_npk = from_keys.nullifer_public_key; - let from_ipk = from_keys.incoming_viewing_public_key; - let to_npk = to_keys.nullifer_public_key.clone(); - let to_ipk = to_keys.incoming_viewing_public_key.clone(); - - if from_acc.balance >= balance_to_move { - let program = Program::authenticated_transfer_program(); - - let sender_commitment = Commitment::new(&from_npk, &from_acc); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); - - let eph_holder_from = EphemeralKeyHolder::new(&from_npk); - let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk); - - let eph_holder_to = EphemeralKeyHolder::new(&to_npk); - let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_ipk); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(balance_to_move).unwrap(), - &[1, 2], - &produce_random_nonces(2), - &[ - (from_npk.clone(), shared_secret_from.clone()), - (to_npk.clone(), shared_secret_to.clone()), - ], - &[( - from_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - )], - &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(), - ), - ( - to_npk.clone(), - to_ipk.clone(), - eph_holder_to.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, shared_secret_to], - )) - } else { - Err(ExecutionFailureKind::InsufficientFundsError) - } + self.private_tx_two_accs_all_init( + from, + to, + instruction_data, + tx_pre_check, + program, + to_proof, + ) + .await } } diff --git a/wallet/src/token_transfers/shielded.rs b/wallet/src/token_transfers/shielded.rs index 8fabedd..ce7c0d3 100644 --- a/wallet/src/token_transfers/shielded.rs +++ b/wallet/src/token_transfers/shielded.rs @@ -1,16 +1,10 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; -use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; -use nssa::{ - Account, Address, PrivacyPreservingTransaction, - privacy_preserving_transaction::{circuit, message::Message, witness_set::WitnessSet}, - program::Program, -}; +use nssa::Address; use nssa_core::{ - MembershipProof, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata, - encryption::IncomingViewingPublicKey, + MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey, }; -use crate::{WalletCore, helperfunctions::produce_random_nonces}; +use crate::WalletCore; impl WalletCore { pub async fn send_shielded_native_token_transfer_already_initialized( @@ -19,68 +13,12 @@ impl WalletCore { to: Address, balance_to_move: u128, to_proof: MembershipProof, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let Ok(from_acc) = self.get_account_public(from).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { + let (instruction_data, program, tx_pre_check) = + WalletCore::auth_transfer_preparation(balance_to_move); - let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let to_npk = to_keys.nullifer_public_key.clone(); - let to_ipk = to_keys.incoming_viewing_public_key.clone(); - - if from_acc.balance >= balance_to_move { - let program = Program::authenticated_transfer_program(); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk); - - let eph_holder = EphemeralKeyHolder::new(&to_npk); - let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &nssa::program::Program::serialize_instruction(balance_to_move).unwrap(), - &[0, 1], - &produce_random_nonces(1), - &[(to_npk.clone(), shared_secret.clone())], - &[(to_keys.private_key_holder.nullifier_secret_key, to_proof)], - &program, - ) - .unwrap(); - - let message = Message::try_from_circuit_output( - vec![from], - vec![from_acc.nonce], - vec![( - to_npk.clone(), - to_ipk.clone(), - eph_holder.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); - - let Some(signing_key) = signing_key else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]); - - let tx = PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - shared_secret, - )) - } else { - Err(ExecutionFailureKind::InsufficientFundsError) - } + self.shielded_two_accs_all_init(from, to, instruction_data, tx_pre_check, program, to_proof) + .await } pub async fn send_shielded_native_token_transfer_not_initialized( @@ -88,68 +26,12 @@ impl WalletCore { from: Address, to: Address, balance_to_move: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let Ok(from_acc) = self.get_account_public(from).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { + let (instruction_data, program, tx_pre_check) = + WalletCore::auth_transfer_preparation(balance_to_move); - let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let to_npk = to_keys.nullifer_public_key.clone(); - let to_ipk = to_keys.incoming_viewing_public_key.clone(); - - if from_acc.balance >= balance_to_move { - let program = Program::authenticated_transfer_program(); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); - - let eph_holder = EphemeralKeyHolder::new(&to_npk); - let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &nssa::program::Program::serialize_instruction(balance_to_move).unwrap(), - &[0, 2], - &produce_random_nonces(1), - &[(to_npk.clone(), shared_secret.clone())], - &[], - &program, - ) - .unwrap(); - - let message = Message::try_from_circuit_output( - vec![from], - vec![from_acc.nonce], - vec![( - to_npk.clone(), - to_ipk.clone(), - eph_holder.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); - - let Some(signing_key) = signing_key else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]); - - let tx = PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - shared_secret, - )) - } else { - Err(ExecutionFailureKind::InsufficientFundsError) - } + self.shielded_two_accs_receiver_uninit(from, to, instruction_data, tx_pre_check, program) + .await } pub async fn send_shielded_native_token_transfer_outer_account( @@ -158,60 +40,18 @@ impl WalletCore { to_npk: NullifierPublicKey, to_ipk: IncomingViewingPublicKey, balance_to_move: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let Ok(from_acc) = self.get_account_public(from).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + ) -> Result { + let (instruction_data, program, tx_pre_check) = + WalletCore::auth_transfer_preparation(balance_to_move); - let to_acc = Account::default(); - - if from_acc.balance >= balance_to_move { - let program = Program::authenticated_transfer_program(); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); - - let eph_holder = EphemeralKeyHolder::new(&to_npk); - let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(balance_to_move).unwrap(), - &[0, 2], - &produce_random_nonces(1), - &[(to_npk.clone(), shared_secret.clone())], - &[], - &program, - ) - .unwrap(); - - let message = Message::try_from_circuit_output( - vec![from], - vec![from_acc.nonce], - vec![( - to_npk.clone(), - to_ipk.clone(), - eph_holder.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); - - let Some(signing_key) = signing_key else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]); - let tx = PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - shared_secret, - )) - } else { - Err(ExecutionFailureKind::InsufficientFundsError) - } + self.shielded_two_accs_receiver_outer( + from, + to_npk, + to_ipk, + instruction_data, + tx_pre_check, + program, + ) + .await } } diff --git a/wallet/src/transaction_utils.rs b/wallet/src/transaction_utils.rs new file mode 100644 index 0000000..355b908 --- /dev/null +++ b/wallet/src/transaction_utils.rs @@ -0,0 +1,538 @@ +use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; +use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; +use nssa::{ + Account, Address, PrivacyPreservingTransaction, + privacy_preserving_transaction::{circuit, message::Message, witness_set::WitnessSet}, + program::Program, +}; +use nssa_core::{ + Commitment, MembershipProof, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata, + encryption::IncomingViewingPublicKey, program::InstructionData, +}; + +use crate::{WalletCore, helperfunctions::produce_random_nonces}; + +impl WalletCore { + pub(crate) async fn private_tx_two_accs_all_init( + &self, + from: Address, + to: Address, + instruction_data: InstructionData, + tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + program: Program, + to_proof: MembershipProof, + ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + let Some((from_keys, from_acc)) = + self.storage.user_data.get_private_account(&from).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + tx_pre_check(&from_acc, &to_acc)?; + + let from_npk = from_keys.nullifer_public_key; + let from_ipk = from_keys.incoming_viewing_public_key; + let to_npk = to_keys.nullifer_public_key.clone(); + let to_ipk = to_keys.incoming_viewing_public_key.clone(); + + let sender_commitment = Commitment::new(&from_npk, &from_acc); + + let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); + let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk); + + let eph_holder_from = EphemeralKeyHolder::new(&from_npk); + let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk); + + let eph_holder_to = EphemeralKeyHolder::new(&to_npk); + let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_ipk); + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre, recipient_pre], + &instruction_data, + &[1, 1], + &produce_random_nonces(2), + &[ + (from_npk.clone(), shared_secret_from.clone()), + (to_npk.clone(), shared_secret_to.clone()), + ], + &[ + ( + from_keys.private_key_holder.nullifier_secret_key, + self.sequencer_client + .get_proof_for_commitment(sender_commitment) + .await + .unwrap() + .unwrap(), + ), + (to_keys.private_key_holder.nullifier_secret_key, to_proof), + ], + &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(), + ), + ( + to_npk.clone(), + to_ipk.clone(), + eph_holder_to.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, shared_secret_to], + )) + } + + pub(crate) async fn private_tx_two_accs_receiver_uninit( + &self, + from: Address, + to: Address, + instruction_data: InstructionData, + tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + program: Program, + ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + let Some((from_keys, from_acc)) = + self.storage.user_data.get_private_account(&from).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + tx_pre_check(&from_acc, &to_acc)?; + + let from_npk = from_keys.nullifer_public_key; + let from_ipk = from_keys.incoming_viewing_public_key; + let to_npk = to_keys.nullifer_public_key.clone(); + let to_ipk = to_keys.incoming_viewing_public_key.clone(); + + let sender_commitment = Commitment::new(&from_npk, &from_acc); + + let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); + let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); + + let eph_holder_from = EphemeralKeyHolder::new(&from_npk); + let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk); + + let eph_holder_to = EphemeralKeyHolder::new(&to_npk); + let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_ipk); + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre, recipient_pre], + &instruction_data, + &[1, 2], + &produce_random_nonces(2), + &[ + (from_npk.clone(), shared_secret_from.clone()), + (to_npk.clone(), shared_secret_to.clone()), + ], + &[( + from_keys.private_key_holder.nullifier_secret_key, + self.sequencer_client + .get_proof_for_commitment(sender_commitment) + .await + .unwrap() + .unwrap(), + )], + &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(), + ), + ( + to_npk.clone(), + to_ipk.clone(), + eph_holder_to.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, shared_secret_to], + )) + } + + pub(crate) async fn private_tx_two_accs_receiver_outer( + &self, + from: Address, + to_npk: NullifierPublicKey, + to_ipk: IncomingViewingPublicKey, + instruction_data: InstructionData, + tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + program: Program, + ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + let Some((from_keys, from_acc)) = + self.storage.user_data.get_private_account(&from).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let to_acc = nssa_core::account::Account::default(); + + tx_pre_check(&from_acc, &to_acc)?; + + let from_npk = from_keys.nullifer_public_key; + let from_ipk = from_keys.incoming_viewing_public_key; + + let sender_commitment = Commitment::new(&from_npk, &from_acc); + + let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); + + let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); + + let eph_holder = EphemeralKeyHolder::new(&to_npk); + + let shared_secret_from = eph_holder.calculate_shared_secret_sender(&from_ipk); + let shared_secret_to = eph_holder.calculate_shared_secret_sender(&to_ipk); + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre, recipient_pre], + &instruction_data, + &[1, 2], + &produce_random_nonces(2), + &[ + (from_npk.clone(), shared_secret_from.clone()), + (to_npk.clone(), shared_secret_to.clone()), + ], + &[( + from_keys.private_key_holder.nullifier_secret_key, + self.sequencer_client + .get_proof_for_commitment(sender_commitment) + .await + .unwrap() + .unwrap(), + )], + &program, + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![], + vec![], + vec![ + ( + from_npk.clone(), + from_ipk.clone(), + eph_holder.generate_ephemeral_public_key(), + ), + ( + to_npk.clone(), + to_ipk.clone(), + eph_holder.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, shared_secret_to], + )) + } + + pub(crate) async fn deshielded_tx_two_accs( + &self, + from: Address, + to: Address, + instruction_data: InstructionData, + tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + program: Program, + ) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 1]), ExecutionFailureKind> { + let Some((from_keys, from_acc)) = + self.storage.user_data.get_private_account(&from).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let Ok(to_acc) = self.get_account_public(to).await else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + tx_pre_check(&from_acc, &to_acc)?; + + let npk_from = from_keys.nullifer_public_key; + let ipk_from = from_keys.incoming_viewing_public_key; + + let sender_commitment = Commitment::new(&npk_from, &from_acc); + + let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &npk_from); + let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, to); + + let eph_holder = EphemeralKeyHolder::new(&npk_from); + let shared_secret = eph_holder.calculate_shared_secret_sender(&ipk_from); + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre, recipient_pre], + &instruction_data, + &[1, 0], + &produce_random_nonces(1), + &[(npk_from.clone(), shared_secret.clone())], + &[( + from_keys.private_key_holder.nullifier_secret_key, + self.sequencer_client + .get_proof_for_commitment(sender_commitment) + .await + .unwrap() + .unwrap(), + )], + &program, + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![to], + vec![], + vec![( + npk_from.clone(), + ipk_from.clone(), + eph_holder.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], + )) + } + + pub(crate) async fn shielded_two_accs_all_init( + &self, + from: Address, + to: Address, + instruction_data: InstructionData, + tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + program: Program, + to_proof: MembershipProof, + ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { + let Ok(from_acc) = self.get_account_public(from).await else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let to_npk = to_keys.nullifer_public_key.clone(); + let to_ipk = to_keys.incoming_viewing_public_key.clone(); + + tx_pre_check(&from_acc, &to_acc)?; + + let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); + let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk); + + let eph_holder = EphemeralKeyHolder::new(&to_npk); + let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre, recipient_pre], + &instruction_data, + &[0, 1], + &produce_random_nonces(1), + &[(to_npk.clone(), shared_secret.clone())], + &[(to_keys.private_key_holder.nullifier_secret_key, to_proof)], + &program, + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![from], + vec![from_acc.nonce], + vec![( + to_npk.clone(), + to_ipk.clone(), + eph_holder.generate_ephemeral_public_key(), + )], + output, + ) + .unwrap(); + + let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); + + let Some(signing_key) = signing_key else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]); + + let tx = PrivacyPreservingTransaction::new(message, witness_set); + + Ok(( + self.sequencer_client.send_tx_private(tx).await?, + [shared_secret], + )) + } + + pub(crate) async fn shielded_two_accs_receiver_uninit( + &self, + from: Address, + to: Address, + instruction_data: InstructionData, + tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + program: Program, + ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { + let Ok(from_acc) = self.get_account_public(from).await else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let to_npk = to_keys.nullifer_public_key.clone(); + let to_ipk = to_keys.incoming_viewing_public_key.clone(); + + tx_pre_check(&from_acc, &to_acc)?; + + let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); + let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); + + let eph_holder = EphemeralKeyHolder::new(&to_npk); + let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre, recipient_pre], + &instruction_data, + &[0, 2], + &produce_random_nonces(1), + &[(to_npk.clone(), shared_secret.clone())], + &[], + &program, + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![from], + vec![from_acc.nonce], + vec![( + to_npk.clone(), + to_ipk.clone(), + eph_holder.generate_ephemeral_public_key(), + )], + output, + ) + .unwrap(); + + let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); + + let Some(signing_key) = signing_key else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]); + + let tx = PrivacyPreservingTransaction::new(message, witness_set); + + Ok(( + self.sequencer_client.send_tx_private(tx).await?, + [shared_secret], + )) + } + + pub(crate) async fn shielded_two_accs_receiver_outer( + &self, + from: Address, + to_npk: NullifierPublicKey, + to_ipk: IncomingViewingPublicKey, + instruction_data: InstructionData, + tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + program: Program, + ) -> Result { + let Ok(from_acc) = self.get_account_public(from).await else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let to_acc = Account::default(); + + tx_pre_check(&from_acc, &to_acc)?; + + let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); + let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); + + let eph_holder = EphemeralKeyHolder::new(&to_npk); + let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre, recipient_pre], + &instruction_data, + &[0, 2], + &produce_random_nonces(1), + &[(to_npk.clone(), shared_secret.clone())], + &[], + &program, + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![from], + vec![from_acc.nonce], + vec![( + to_npk.clone(), + to_ipk.clone(), + eph_holder.generate_ephemeral_public_key(), + )], + output, + ) + .unwrap(); + + let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); + + let Some(signing_key) = signing_key else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]); + let tx = PrivacyPreservingTransaction::new(message, witness_set); + + Ok(self.sequencer_client.send_tx_private(tx).await?) + } +} From a01bfe368803ed30489a320a38a205e89a3ded3c Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Tue, 21 Oct 2025 15:15:41 +0300 Subject: [PATCH 2/7] fix: private account preparation unified --- wallet/src/pinata_interactions.rs | 51 +++--- wallet/src/transaction_utils.rs | 250 +++++++++++++++--------------- 2 files changed, 148 insertions(+), 153 deletions(-) diff --git a/wallet/src/pinata_interactions.rs b/wallet/src/pinata_interactions.rs index 4506161..491114d 100644 --- a/wallet/src/pinata_interactions.rs +++ b/wallet/src/pinata_interactions.rs @@ -3,7 +3,9 @@ use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use nssa::{Address, privacy_preserving_transaction::circuit}; use nssa_core::{MembershipProof, SharedSecretKey, account::AccountWithMetadata}; -use crate::{WalletCore, helperfunctions::produce_random_nonces}; +use crate::{ + WalletCore, helperfunctions::produce_random_nonces, transaction_utils::AccountPreparedData, +}; impl WalletCore { pub async fn claim_pinata( @@ -31,24 +33,21 @@ impl WalletCore { solution: u128, winner_proof: MembershipProof, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { - let Some((winner_keys, winner_acc)) = self - .storage - .user_data - .get_private_account(&winner_addr) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let AccountPreparedData { + nsk: winner_nsk, + npk: winner_npk, + ipk: winner_ipk, + auth_acc: winner_pre, + proof: _, + } = self + .private_acc_preparation(winner_addr, true, false) + .await?; let pinata_acc = self.get_account_public(pinata_addr).await.unwrap(); - let winner_npk = winner_keys.nullifer_public_key; - let winner_ipk = winner_keys.incoming_viewing_public_key; - let program = nssa::program::Program::pinata(); let pinata_pre = AccountWithMetadata::new(pinata_acc.clone(), false, pinata_addr); - let winner_pre = AccountWithMetadata::new(winner_acc.clone(), true, &winner_npk); let eph_holder_winner = EphemeralKeyHolder::new(&winner_npk); let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk); @@ -59,10 +58,7 @@ impl WalletCore { &[0, 1], &produce_random_nonces(1), &[(winner_npk.clone(), shared_secret_winner.clone())], - &[( - winner_keys.private_key_holder.nullifier_secret_key, - winner_proof, - )], + &[(winner_nsk.unwrap(), winner_proof)], &program, ) .unwrap(); @@ -103,24 +99,21 @@ impl WalletCore { winner_addr: Address, solution: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { - let Some((winner_keys, winner_acc)) = self - .storage - .user_data - .get_private_account(&winner_addr) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let AccountPreparedData { + nsk: _, + npk: winner_npk, + ipk: winner_ipk, + auth_acc: winner_pre, + proof: _, + } = self + .private_acc_preparation(winner_addr, false, false) + .await?; let pinata_acc = self.get_account_public(pinata_addr).await.unwrap(); - let winner_npk = winner_keys.nullifer_public_key; - let winner_ipk = winner_keys.incoming_viewing_public_key; - let program = nssa::program::Program::pinata(); let pinata_pre = AccountWithMetadata::new(pinata_acc.clone(), false, pinata_addr); - let winner_pre = AccountWithMetadata::new(winner_acc.clone(), false, &winner_npk); let eph_holder_winner = EphemeralKeyHolder::new(&winner_npk); let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk); diff --git a/wallet/src/transaction_utils.rs b/wallet/src/transaction_utils.rs index 355b908..b7f219d 100644 --- a/wallet/src/transaction_utils.rs +++ b/wallet/src/transaction_utils.rs @@ -6,13 +6,64 @@ use nssa::{ program::Program, }; use nssa_core::{ - Commitment, MembershipProof, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata, - encryption::IncomingViewingPublicKey, program::InstructionData, + Commitment, MembershipProof, NullifierPublicKey, NullifierSecretKey, SharedSecretKey, + account::AccountWithMetadata, encryption::IncomingViewingPublicKey, program::InstructionData, }; use crate::{WalletCore, helperfunctions::produce_random_nonces}; +pub(crate) struct AccountPreparedData { + pub nsk: Option, + pub npk: NullifierPublicKey, + pub ipk: IncomingViewingPublicKey, + pub auth_acc: AccountWithMetadata, + pub proof: Option, +} + impl WalletCore { + pub(crate) async fn private_acc_preparation( + &self, + addr: Address, + is_authorized: bool, + needs_proof: bool, + ) -> Result { + let Some((from_keys, from_acc)) = + self.storage.user_data.get_private_account(&addr).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let mut nsk = None; + let mut proof = None; + + let from_npk = from_keys.nullifer_public_key; + let from_ipk = from_keys.incoming_viewing_public_key; + + let sender_commitment = Commitment::new(&from_npk, &from_acc); + + let sender_pre = AccountWithMetadata::new(from_acc.clone(), is_authorized, &from_npk); + + if is_authorized { + nsk = Some(from_keys.private_key_holder.nullifier_secret_key); + } + + if needs_proof { + proof = self + .sequencer_client + .get_proof_for_commitment(sender_commitment) + .await + .unwrap(); + } + + Ok(AccountPreparedData { + nsk, + npk: from_npk, + ipk: from_ipk, + auth_acc: sender_pre, + proof, + }) + } + pub(crate) async fn private_tx_two_accs_all_init( &self, from: Address, @@ -22,28 +73,23 @@ impl WalletCore { program: Program, to_proof: MembershipProof, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((from_keys, from_acc)) = - self.storage.user_data.get_private_account(&from).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let AccountPreparedData { + nsk: from_nsk, + npk: from_npk, + ipk: from_ipk, + auth_acc: sender_pre, + proof: from_proof, + } = self.private_acc_preparation(from, true, true).await?; - let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let AccountPreparedData { + nsk: to_nsk, + npk: to_npk, + ipk: to_ipk, + auth_acc: recipient_pre, + proof: _, + } = self.private_acc_preparation(to, true, false).await?; - tx_pre_check(&from_acc, &to_acc)?; - - let from_npk = from_keys.nullifer_public_key; - let from_ipk = from_keys.incoming_viewing_public_key; - let to_npk = to_keys.nullifer_public_key.clone(); - let to_ipk = to_keys.incoming_viewing_public_key.clone(); - - let sender_commitment = Commitment::new(&from_npk, &from_acc); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk); + tx_pre_check(&sender_pre.account, &recipient_pre.account)?; let eph_holder_from = EphemeralKeyHolder::new(&from_npk); let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk); @@ -61,15 +107,8 @@ impl WalletCore { (to_npk.clone(), shared_secret_to.clone()), ], &[ - ( - from_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - ), - (to_keys.private_key_holder.nullifier_secret_key, to_proof), + (from_nsk.unwrap(), from_proof.unwrap()), + (to_nsk.unwrap(), to_proof), ], &program, ) @@ -111,28 +150,23 @@ impl WalletCore { tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, program: Program, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((from_keys, from_acc)) = - self.storage.user_data.get_private_account(&from).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let AccountPreparedData { + nsk: from_nsk, + npk: from_npk, + ipk: from_ipk, + auth_acc: sender_pre, + proof: from_proof, + } = self.private_acc_preparation(from, true, true).await?; - let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let AccountPreparedData { + nsk: _, + npk: to_npk, + ipk: to_ipk, + auth_acc: recipient_pre, + proof: _, + } = self.private_acc_preparation(to, false, false).await?; - tx_pre_check(&from_acc, &to_acc)?; - - let from_npk = from_keys.nullifer_public_key; - let from_ipk = from_keys.incoming_viewing_public_key; - let to_npk = to_keys.nullifer_public_key.clone(); - let to_ipk = to_keys.incoming_viewing_public_key.clone(); - - let sender_commitment = Commitment::new(&from_npk, &from_acc); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); + tx_pre_check(&sender_pre.account, &recipient_pre.account)?; let eph_holder_from = EphemeralKeyHolder::new(&from_npk); let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk); @@ -149,14 +183,7 @@ impl WalletCore { (from_npk.clone(), shared_secret_from.clone()), (to_npk.clone(), shared_secret_to.clone()), ], - &[( - from_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - )], + &[(from_nsk.unwrap(), from_proof.unwrap())], &program, ) .unwrap(); @@ -198,22 +225,17 @@ impl WalletCore { tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, program: Program, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((from_keys, from_acc)) = - self.storage.user_data.get_private_account(&from).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let AccountPreparedData { + nsk: from_nsk, + npk: from_npk, + ipk: from_ipk, + auth_acc: sender_pre, + proof: from_proof, + } = self.private_acc_preparation(from, true, true).await?; let to_acc = nssa_core::account::Account::default(); - tx_pre_check(&from_acc, &to_acc)?; - - let from_npk = from_keys.nullifer_public_key; - let from_ipk = from_keys.incoming_viewing_public_key; - - let sender_commitment = Commitment::new(&from_npk, &from_acc); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); + tx_pre_check(&sender_pre.account, &to_acc)?; let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); @@ -231,14 +253,7 @@ impl WalletCore { (from_npk.clone(), shared_secret_from.clone()), (to_npk.clone(), shared_secret_to.clone()), ], - &[( - from_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - )], + &[(from_nsk.unwrap(), from_proof.unwrap())], &program, ) .unwrap(); @@ -280,43 +295,32 @@ impl WalletCore { tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, program: Program, ) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 1]), ExecutionFailureKind> { - let Some((from_keys, from_acc)) = - self.storage.user_data.get_private_account(&from).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let AccountPreparedData { + nsk: from_nsk, + npk: from_npk, + ipk: from_ipk, + auth_acc: sender_pre, + proof: from_proof, + } = self.private_acc_preparation(from, true, true).await?; let Ok(to_acc) = self.get_account_public(to).await else { return Err(ExecutionFailureKind::KeyNotFoundError); }; - tx_pre_check(&from_acc, &to_acc)?; + tx_pre_check(&sender_pre.account, &to_acc)?; - let npk_from = from_keys.nullifer_public_key; - let ipk_from = from_keys.incoming_viewing_public_key; - - let sender_commitment = Commitment::new(&npk_from, &from_acc); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &npk_from); let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, to); - let eph_holder = EphemeralKeyHolder::new(&npk_from); - let shared_secret = eph_holder.calculate_shared_secret_sender(&ipk_from); + let eph_holder = EphemeralKeyHolder::new(&from_npk); + let shared_secret = eph_holder.calculate_shared_secret_sender(&from_ipk); let (output, proof) = circuit::execute_and_prove( &[sender_pre, recipient_pre], &instruction_data, &[1, 0], &produce_random_nonces(1), - &[(npk_from.clone(), shared_secret.clone())], - &[( - from_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - )], + &[(from_npk.clone(), shared_secret.clone())], + &[(from_nsk.unwrap(), from_proof.unwrap())], &program, ) .unwrap(); @@ -325,8 +329,8 @@ impl WalletCore { vec![to], vec![], vec![( - npk_from.clone(), - ipk_from.clone(), + from_npk.clone(), + from_ipk.clone(), eph_holder.generate_ephemeral_public_key(), )], output, @@ -356,18 +360,17 @@ impl WalletCore { return Err(ExecutionFailureKind::KeyNotFoundError); }; - let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let AccountPreparedData { + nsk: to_nsk, + npk: to_npk, + ipk: to_ipk, + auth_acc: recipient_pre, + proof: _, + } = self.private_acc_preparation(to, true, false).await?; - let to_npk = to_keys.nullifer_public_key.clone(); - let to_ipk = to_keys.incoming_viewing_public_key.clone(); - - tx_pre_check(&from_acc, &to_acc)?; + tx_pre_check(&from_acc, &recipient_pre.account)?; let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk); let eph_holder = EphemeralKeyHolder::new(&to_npk); let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); @@ -378,7 +381,7 @@ impl WalletCore { &[0, 1], &produce_random_nonces(1), &[(to_npk.clone(), shared_secret.clone())], - &[(to_keys.private_key_holder.nullifier_secret_key, to_proof)], + &[(to_nsk.unwrap(), to_proof)], &program, ) .unwrap(); @@ -423,18 +426,17 @@ impl WalletCore { return Err(ExecutionFailureKind::KeyNotFoundError); }; - let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let AccountPreparedData { + nsk: _, + npk: to_npk, + ipk: to_ipk, + auth_acc: recipient_pre, + proof: _, + } = self.private_acc_preparation(to, false, false).await?; - let to_npk = to_keys.nullifer_public_key.clone(); - let to_ipk = to_keys.incoming_viewing_public_key.clone(); - - tx_pre_check(&from_acc, &to_acc)?; + tx_pre_check(&from_acc, &recipient_pre.account)?; let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); let eph_holder = EphemeralKeyHolder::new(&to_npk); let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); From 37360e6d8cd410f4026200fc928687fbd8844b60 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Tue, 21 Oct 2025 15:17:44 +0300 Subject: [PATCH 3/7] fix: merge fix --- integration_tests/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index a170564..ec04130 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -1410,7 +1410,7 @@ pub async fn test_program_deployment() { let message = nssa::program_deployment_transaction::Message::new(bytecode.clone()); let transaction = ProgramDeploymentTransaction::new(message); - let wallet_config = fetch_config().unwrap(); + let wallet_config = fetch_config().await.unwrap(); let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); let _response = seq_client.send_tx_program(transaction).await.unwrap(); From 31783d9b78a6654da5656c0de078b2ce66b8923b Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Wed, 22 Oct 2025 13:55:35 +0300 Subject: [PATCH 4/7] fix: test suite proc macro --- Cargo.toml | 3 +- integration_tests/Cargo.toml | 2 + integration_tests/src/lib.rs | 1710 +---------------------- integration_tests/src/test_suite_map.rs | 1573 +++++++++++++++++++++ proc_macro_test_attribute/Cargo.toml | 9 + proc_macro_test_attribute/src/lib.rs | 49 + 6 files changed, 1653 insertions(+), 1693 deletions(-) create mode 100644 integration_tests/src/test_suite_map.rs create mode 100644 proc_macro_test_attribute/Cargo.toml create mode 100644 proc_macro_test_attribute/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 11e3144..df38af7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,8 @@ members = [ "wallet", "sequencer_core", "common", - "nssa", + "nssa", + "proc_macro_test_attribute", ] [workspace.dependencies] diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index f7bd131..979c523 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -17,6 +17,8 @@ borsh.workspace = true nssa-core = { path = "../nssa/core", features = ["host"] } +proc_macro_test_attribute = { path = "../proc_macro_test_attribute" } + [dependencies.clap] features = ["derive", "env"] workspace = true diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index ec04130..bbd5066 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -1,5 +1,5 @@ use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; -use std::{path::PathBuf, time::Duration}; +use std::path::PathBuf; use actix_web::dev::ServerHandle; use anyhow::Result; @@ -9,34 +9,19 @@ use common::{ transaction::{EncodedTransaction, NSSATransaction}, }; use log::{info, warn}; -use nssa::{Address, PrivacyPreservingTransaction, ProgramDeploymentTransaction, program::Program}; -use nssa_core::{ - Commitment, NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point, -}; +use nssa::PrivacyPreservingTransaction; +use nssa_core::Commitment; use sequencer_core::config::SequencerConfig; use sequencer_runner::startup_sequencer; use tempfile::TempDir; use tokio::task::JoinHandle; -use wallet::{ - Command, SubcommandReturnValue, WalletCore, - cli::{ - account::{AccountSubcommand, FetchSubcommand, RegisterSubcommand}, - native_token_transfer_program::{ - NativeTokenTransferProgramSubcommand, NativeTokenTransferProgramSubcommandPrivate, - NativeTokenTransferProgramSubcommandShielded, - }, - pinata_program::{ - PinataProgramSubcommand, PinataProgramSubcommandPrivate, PinataProgramSubcommandPublic, - }, - token_program::{ - TokenProgramSubcommand, TokenProgramSubcommandDeshielded, - TokenProgramSubcommandPrivate, TokenProgramSubcommandPublic, - TokenProgramSubcommandShielded, - }, - }, - config::PersistentAccountData, - helperfunctions::{fetch_config, fetch_persistent_accounts}, -}; + +use crate::test_suite_map::prepare_function_map; + +#[macro_use] +extern crate proc_macro_test_attribute; + +pub mod test_suite_map; #[derive(Parser, Debug)] #[clap(version)] @@ -112,1508 +97,6 @@ pub async fn post_test(residual: (ServerHandle, JoinHandle>, TempDir) //So they are dropped and tempdirs will be dropped too, } -pub async fn test_success() { - info!("test_success"); - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { - from: ACC_SENDER.to_string(), - to: ACC_RECEIVER.to_string(), - amount: 100, - }); - - let wallet_config = fetch_config().await.unwrap(); - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - wallet::execute_subcommand(command).await.unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - info!("Checking correct balance move"); - let acc_1_balance = seq_client - .get_account_balance(ACC_SENDER.to_string()) - .await - .unwrap(); - let acc_2_balance = seq_client - .get_account_balance(ACC_RECEIVER.to_string()) - .await - .unwrap(); - - info!("Balance of sender : {acc_1_balance:#?}"); - info!("Balance of receiver : {acc_2_balance:#?}"); - - assert_eq!(acc_1_balance.balance, 9900); - assert_eq!(acc_2_balance.balance, 20100); - - info!("Success!"); -} - -pub async fn test_success_move_to_another_account() { - info!("test_success_move_to_another_account"); - let command = Command::Account(AccountSubcommand::Register(RegisterSubcommand::Public {})); - - let wallet_config = fetch_config().await.unwrap(); - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - wallet::execute_subcommand(command).await.unwrap(); - - let persistent_accounts = fetch_persistent_accounts().await.unwrap(); - - let mut new_persistent_account_addr = String::new(); - - for per_acc in persistent_accounts { - if (per_acc.address().to_string() != ACC_RECEIVER) - && (per_acc.address().to_string() != ACC_SENDER) - { - new_persistent_account_addr = per_acc.address().to_string(); - } - } - - if new_persistent_account_addr == String::new() { - panic!("Failed to produce new account, not present in persistent accounts"); - } - - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { - from: ACC_SENDER.to_string(), - to: new_persistent_account_addr.clone(), - amount: 100, - }); - - wallet::execute_subcommand(command).await.unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - info!("Checking correct balance move"); - let acc_1_balance = seq_client - .get_account_balance(ACC_SENDER.to_string()) - .await - .unwrap(); - let acc_2_balance = seq_client - .get_account_balance(new_persistent_account_addr) - .await - .unwrap(); - - info!("Balance of sender : {acc_1_balance:#?}"); - info!("Balance of receiver : {acc_2_balance:#?}"); - - assert_eq!(acc_1_balance.balance, 9900); - assert_eq!(acc_2_balance.balance, 100); - - info!("Success!"); -} - -pub async fn test_failure() { - info!("test_failure"); - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { - from: ACC_SENDER.to_string(), - to: ACC_RECEIVER.to_string(), - amount: 1000000, - }); - - let wallet_config = fetch_config().await.unwrap(); - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - let failed_send = wallet::execute_subcommand(command).await; - - assert!(failed_send.is_err()); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - info!("Checking correct balance move"); - let acc_1_balance = seq_client - .get_account_balance(ACC_SENDER.to_string()) - .await - .unwrap(); - let acc_2_balance = seq_client - .get_account_balance(ACC_RECEIVER.to_string()) - .await - .unwrap(); - - info!("Balance of sender : {acc_1_balance:#?}"); - info!("Balance of receiver : {acc_2_balance:#?}"); - - assert_eq!(acc_1_balance.balance, 10000); - assert_eq!(acc_2_balance.balance, 20000); - - info!("Success!"); -} - -pub async fn test_success_two_transactions() { - info!("test_success_two_transactions"); - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { - from: ACC_SENDER.to_string(), - to: ACC_RECEIVER.to_string(), - amount: 100, - }); - - let wallet_config = fetch_config().await.unwrap(); - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - wallet::execute_subcommand(command).await.unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - info!("Checking correct balance move"); - let acc_1_balance = seq_client - .get_account_balance(ACC_SENDER.to_string()) - .await - .unwrap(); - let acc_2_balance = seq_client - .get_account_balance(ACC_RECEIVER.to_string()) - .await - .unwrap(); - - info!("Balance of sender : {acc_1_balance:#?}"); - info!("Balance of receiver : {acc_2_balance:#?}"); - - assert_eq!(acc_1_balance.balance, 9900); - assert_eq!(acc_2_balance.balance, 20100); - - info!("First TX Success!"); - - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { - from: ACC_SENDER.to_string(), - to: ACC_RECEIVER.to_string(), - amount: 100, - }); - - wallet::execute_subcommand(command).await.unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - info!("Checking correct balance move"); - let acc_1_balance = seq_client - .get_account_balance(ACC_SENDER.to_string()) - .await - .unwrap(); - let acc_2_balance = seq_client - .get_account_balance(ACC_RECEIVER.to_string()) - .await - .unwrap(); - - info!("Balance of sender : {acc_1_balance:#?}"); - info!("Balance of receiver : {acc_2_balance:#?}"); - - assert_eq!(acc_1_balance.balance, 9800); - assert_eq!(acc_2_balance.balance, 20200); - - info!("Second TX Success!"); -} - -pub async fn test_get_account() { - info!("test_get_account"); - let wallet_config = fetch_config().await.unwrap(); - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - let account = seq_client - .get_account(ACC_SENDER.to_string()) - .await - .unwrap() - .account; - - assert_eq!( - account.program_owner, - Program::authenticated_transfer_program().id() - ); - assert_eq!(account.balance, 10000); - assert!(account.data.is_empty()); - assert_eq!(account.nonce, 0); -} - -/// This test creates a new token using the token program. After creating the token, the test executes a -/// token transfer to a new account. -pub async fn test_success_token_program() { - let wallet_config = fetch_config().await.unwrap(); - - // Create new account for the token definition - wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, - ))) - .await - .unwrap(); - // Create new account for the token supply holder - wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, - ))) - .await - .unwrap(); - // Create new account for receiving a token transaction - wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, - ))) - .await - .unwrap(); - - let persistent_accounts = fetch_persistent_accounts().await.unwrap(); - - let mut new_persistent_accounts_addr = Vec::new(); - - for per_acc in persistent_accounts { - match per_acc { - PersistentAccountData::Public(per_acc) => { - if (per_acc.address.to_string() != ACC_RECEIVER) - && (per_acc.address.to_string() != ACC_SENDER) - { - new_persistent_accounts_addr.push(per_acc.address); - } - } - _ => continue, - } - } - - let [definition_addr, supply_addr, recipient_addr] = new_persistent_accounts_addr - .try_into() - .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, - }); - wallet::execute_subcommand(Command::TokenProgram(subcommand)) - .await - .unwrap(); - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - // Check the status of the token definition account is the expected after the execution - let definition_acc = seq_client - .get_account(definition_addr.to_string()) - .await - .unwrap() - .account; - - assert_eq!(definition_acc.program_owner, Program::token().id()); - // The data of a token definition account has the following layout: - // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] - assert_eq!( - definition_acc.data, - vec![ - 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] - ); - - // Check the status of the token holding account with the total supply is the expected after the execution - let supply_acc = seq_client - .get_account(supply_addr.to_string()) - .await - .unwrap() - .account; - - // The account must be owned by the token program - assert_eq!(supply_acc.program_owner, Program::token().id()); - // The data of a token definition account has the following layout: - // [ 0x01 || corresponding_token_definition_id (32 bytes) || balance (little endian 16 bytes) ] - // First byte of the data equal to 1 means it's a token holding account - assert_eq!(supply_acc.data[0], 1); - // Bytes from 1 to 33 represent the id of the token this account is associated with. - // In this example, this is a token account of the newly created token, so it is expected - // to be equal to the address of the token definition account. - assert_eq!(&supply_acc.data[1..33], definition_addr.to_bytes()); - assert_eq!( - u128::from_le_bytes(supply_acc.data[33..].try_into().unwrap()), - 37 - ); - - // 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, - }); - wallet::execute_subcommand(Command::TokenProgram(subcommand)) - .await - .unwrap(); - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - // Check the status of the account at `supply_addr` is the expected after the execution - let supply_acc = seq_client - .get_account(supply_addr.to_string()) - .await - .unwrap() - .account; - // The account must be owned by the token program - assert_eq!(supply_acc.program_owner, Program::token().id()); - // First byte equal to 1 means it's a token holding account - assert_eq!(supply_acc.data[0], 1); - // Bytes from 1 to 33 represent the id of the token this account is associated with. - assert_eq!(&supply_acc.data[1..33], definition_addr.to_bytes()); - assert_eq!( - u128::from_le_bytes(supply_acc.data[33..].try_into().unwrap()), - 30 - ); - - // Check the status of the account at `recipient_addr` is the expected after the execution - let recipient_acc = seq_client - .get_account(recipient_addr.to_string()) - .await - .unwrap() - .account; - - // The account must be owned by the token program - assert_eq!(recipient_acc.program_owner, Program::token().id()); - // First byte equal to 1 means it's a token holding account - assert_eq!(recipient_acc.data[0], 1); - // Bytes from 1 to 33 represent the id of the token this account is associated with. - assert_eq!(&recipient_acc.data[1..33], definition_addr.to_bytes()); - assert_eq!( - u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()), - 7 - ); -} - -/// This test creates a new private token using the token program. After creating the token, the test executes a -/// private token transfer to a new account. All accounts are owned except definition. -pub async fn test_success_token_program_private_owned() { - let wallet_config = fetch_config().await.unwrap(); - - // Create new account for the token definition (public) - let SubcommandReturnValue::RegisterAccount { - addr: definition_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, - ))) - .await - .unwrap() - else { - panic!("invalid subcommand return value"); - }; - // Create new account for the token supply holder (private) - let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = wallet::execute_subcommand( - Command::Account(AccountSubcommand::Register(RegisterSubcommand::Private {})), - ) - .await - .unwrap() else { - panic!("invalid subcommand return value"); - }; - // Create new account for receiving a token transaction - let SubcommandReturnValue::RegisterAccount { - addr: recipient_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Private {}, - ))) - .await - .unwrap() - else { - panic!("invalid subcommand return value"); - }; - - // 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, - }, - ); - - wallet::execute_subcommand(Command::TokenProgram(subcommand)) - .await - .unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - // Check the status of the token definition account is the expected after the execution - let definition_acc = seq_client - .get_account(definition_addr.to_string()) - .await - .unwrap() - .account; - - assert_eq!(definition_acc.program_owner, Program::token().id()); - // The data of a token definition account has the following layout: - // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] - assert_eq!( - definition_acc.data, - vec![ - 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] - ); - - let wallet_config = fetch_config().await.unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) - .unwrap(); - 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, - }); - - wallet::execute_subcommand(Command::TokenProgram(subcommand)) - .await - .unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let wallet_config = fetch_config().await.unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) - .unwrap(); - assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); - - let new_commitment2 = wallet_storage - .get_private_account_commitment(&recipient_addr) - .unwrap(); - 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, - }); - - wallet::execute_subcommand(Command::TokenProgram(subcommand)) - .await - .unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let wallet_config = fetch_config().await.unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) - .unwrap(); - assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); - - let new_commitment2 = wallet_storage - .get_private_account_commitment(&recipient_addr) - .unwrap(); - assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); -} - -/// This test creates a new private token using the token program. After creating the token, the test executes a -/// private token transfer to a new account. -pub async fn test_success_token_program_private_claiming_path() { - let wallet_config = fetch_config().await.unwrap(); - - // Create new account for the token definition (public) - let SubcommandReturnValue::RegisterAccount { - addr: definition_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, - ))) - .await - .unwrap() - else { - panic!("invalid subcommand return value"); - }; - // Create new account for the token supply holder (private) - let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = wallet::execute_subcommand( - Command::Account(AccountSubcommand::Register(RegisterSubcommand::Private {})), - ) - .await - .unwrap() else { - panic!("invalid subcommand return value"); - }; - // Create new account for receiving a token transaction - let SubcommandReturnValue::RegisterAccount { - addr: recipient_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Private {}, - ))) - .await - .unwrap() - else { - panic!("invalid subcommand return value"); - }; - - // 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, - }, - ); - - wallet::execute_subcommand(Command::TokenProgram(subcommand)) - .await - .unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - // Check the status of the token definition account is the expected after the execution - let definition_acc = seq_client - .get_account(definition_addr.to_string()) - .await - .unwrap() - .account; - - assert_eq!(definition_acc.program_owner, Program::token().id()); - // The data of a token definition account has the following layout: - // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] - assert_eq!( - definition_acc.data, - vec![ - 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] - ); - - let wallet_config = fetch_config().await.unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) - .unwrap(); - assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); - - let (recipient_keys, _) = wallet_storage - .storage - .user_data - .get_private_account(&recipient_addr) - .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 SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = - wallet::execute_subcommand(Command::TokenProgram(subcommand)) - .await - .unwrap() - else { - panic!("invalid subcommand return value"); - }; - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let command = Command::Account(AccountSubcommand::Fetch(FetchSubcommand::PrivateAccount { - tx_hash, - acc_addr: recipient_addr.to_string(), - output_id: 1, - })); - - wallet::execute_subcommand(command).await.unwrap(); - - let wallet_config = fetch_config().await.unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) - .unwrap(); - assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); - - let new_commitment2 = wallet_storage - .get_private_account_commitment(&recipient_addr) - .unwrap(); - assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); -} - -/// This test creates a new public token using the token program. After creating the token, the test executes a -/// shielded token transfer to a new account. All accounts are owned except definition. -pub async fn test_success_token_program_shielded_owned() { - let wallet_config = fetch_config().await.unwrap(); - - // Create new account for the token definition (public) - let SubcommandReturnValue::RegisterAccount { - addr: definition_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, - ))) - .await - .unwrap() - else { - panic!("invalid subcommand return value"); - }; - // Create new account for the token supply holder (public) - let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = wallet::execute_subcommand( - Command::Account(AccountSubcommand::Register(RegisterSubcommand::Public {})), - ) - .await - .unwrap() else { - panic!("invalid subcommand return value"); - }; - // Create new account for receiving a token transaction - let SubcommandReturnValue::RegisterAccount { - addr: recipient_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Private {}, - ))) - .await - .unwrap() - else { - panic!("invalid subcommand return value"); - }; - - // 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, - }); - - wallet::execute_subcommand(Command::TokenProgram(subcommand)) - .await - .unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - // Check the status of the token definition account is the expected after the execution - let definition_acc = seq_client - .get_account(definition_addr.to_string()) - .await - .unwrap() - .account; - - assert_eq!(definition_acc.program_owner, Program::token().id()); - // The data of a token definition account has the following layout: - // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] - assert_eq!( - definition_acc.data, - vec![ - 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] - ); - - // 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, - }, - ); - - wallet::execute_subcommand(Command::TokenProgram(subcommand)) - .await - .unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let wallet_config = fetch_config().await.unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment2 = wallet_storage - .get_private_account_commitment(&recipient_addr) - .unwrap(); - 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, - }, - ); - - wallet::execute_subcommand(Command::TokenProgram(subcommand)) - .await - .unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let wallet_config = fetch_config().await.unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment2 = wallet_storage - .get_private_account_commitment(&recipient_addr) - .unwrap(); - assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); -} - -/// This test creates a new private token using the token program. After creating the token, the test executes a -/// deshielded token transfer to a new account. All accounts are owned except definition. -pub async fn test_success_token_program_deshielded_owned() { - let wallet_config = fetch_config().await.unwrap(); - - // Create new account for the token definition (public) - let SubcommandReturnValue::RegisterAccount { - addr: definition_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, - ))) - .await - .unwrap() - else { - panic!("invalid subcommand return value"); - }; - // Create new account for the token supply holder (private) - let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = wallet::execute_subcommand( - Command::Account(AccountSubcommand::Register(RegisterSubcommand::Private {})), - ) - .await - .unwrap() else { - panic!("invalid subcommand return value"); - }; - // Create new account for receiving a token transaction - let SubcommandReturnValue::RegisterAccount { - addr: recipient_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, - ))) - .await - .unwrap() - else { - panic!("invalid subcommand return value"); - }; - - // 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, - }, - ); - - wallet::execute_subcommand(Command::TokenProgram(subcommand)) - .await - .unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - // Check the status of the token definition account is the expected after the execution - let definition_acc = seq_client - .get_account(definition_addr.to_string()) - .await - .unwrap() - .account; - - assert_eq!(definition_acc.program_owner, Program::token().id()); - // The data of a token definition account has the following layout: - // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] - assert_eq!( - definition_acc.data, - vec![ - 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] - ); - - let wallet_config = fetch_config().await.unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) - .unwrap(); - 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, - }, - ); - - wallet::execute_subcommand(Command::TokenProgram(subcommand)) - .await - .unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let wallet_config = fetch_config().await.unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) - .unwrap(); - 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, - }, - ); - - wallet::execute_subcommand(Command::TokenProgram(subcommand)) - .await - .unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let wallet_config = fetch_config().await.unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) - .unwrap(); - assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); -} - -pub async fn test_success_private_transfer_to_another_owned_account() { - info!("test_success_private_transfer_to_another_owned_account"); - let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); - let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap(); - - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Private( - NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { - from: from.to_string(), - to: to.to_string(), - amount: 100, - }, - )); - - wallet::execute_subcommand(command).await.unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let wallet_config = fetch_config().await.unwrap(); - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment1 = wallet_storage - .get_private_account_commitment(&from) - .unwrap(); - assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); - - let new_commitment2 = wallet_storage.get_private_account_commitment(&to).unwrap(); - assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); - - info!("Success!"); -} - -pub async fn test_success_private_transfer_to_another_foreign_account() { - info!("test_success_private_transfer_to_another_foreign_account"); - let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); - let to_npk = NullifierPublicKey([42; 32]); - let to_npk_string = hex::encode(to_npk.0); - let to_ipk = Secp256k1Point::from_scalar(to_npk.0); - - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Private( - NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { - from: from.to_string(), - to_npk: to_npk_string, - to_ipk: hex::encode(to_ipk.0), - amount: 100, - }, - )); - - let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = - wallet::execute_subcommand(command).await.unwrap() - else { - panic!("invalid subcommand return value"); - }; - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let wallet_config = fetch_config().await.unwrap(); - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment1 = wallet_storage - .get_private_account_commitment(&from) - .unwrap(); - - let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await; - assert_eq!(tx.message.new_commitments[0], new_commitment1); - - assert_eq!(tx.message.new_commitments.len(), 2); - for commitment in tx.message.new_commitments.into_iter() { - assert!(verify_commitment_is_in_state(commitment, &seq_client).await); - } - - info!("Success!"); -} - -pub async fn test_success_private_transfer_to_another_owned_account_claiming_path() { - info!("test_success_private_transfer_to_another_owned_account_claiming_path"); - let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); - - let command = Command::Account(AccountSubcommand::Register(RegisterSubcommand::Private {})); - - let sub_ret = wallet::execute_subcommand(command).await.unwrap(); - let SubcommandReturnValue::RegisterAccount { addr: to_addr } = sub_ret else { - panic!("FAILED TO REGISTER ACCOUNT"); - }; - - let wallet_config = fetch_config().await.unwrap(); - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config.clone()) - .await - .unwrap(); - - let (to_keys, _) = wallet_storage - .storage - .user_data - .user_private_accounts - .get(&to_addr) - .cloned() - .unwrap(); - - let command = Command::Transfer(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 sub_ret = wallet::execute_subcommand(command).await.unwrap(); - let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else { - panic!("FAILED TO SEND TX"); - }; - - let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await; - - let command = Command::Account(AccountSubcommand::Fetch(FetchSubcommand::PrivateAccount { - tx_hash, - acc_addr: to_addr.to_string(), - output_id: 1, - })); - wallet::execute_subcommand(command).await.unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment1 = wallet_storage - .get_private_account_commitment(&from) - .unwrap(); - assert_eq!(tx.message.new_commitments[0], new_commitment1); - - assert_eq!(tx.message.new_commitments.len(), 2); - for commitment in tx.message.new_commitments.into_iter() { - assert!(verify_commitment_is_in_state(commitment, &seq_client).await); - } - - let to_res_acc = wallet_storage.get_account_private(&to_addr).unwrap(); - - assert_eq!(to_res_acc.balance, 100); - - info!("Success!"); -} - -pub async fn test_success_private_transfer_to_another_owned_account_cont_run_path() { - info!("test_success_private_transfer_to_another_owned_account_cont_run_path"); - let continious_run_handle = tokio::spawn(wallet::execute_continious_run()); - - let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); - - let command = Command::Account(AccountSubcommand::Register(RegisterSubcommand::Private {})); - - let sub_ret = wallet::execute_subcommand(command).await.unwrap(); - let SubcommandReturnValue::RegisterAccount { addr: to_addr } = sub_ret else { - panic!("FAILED TO REGISTER ACCOUNT"); - }; - - let wallet_config = fetch_config().await.unwrap(); - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config.clone()) - .await - .unwrap(); - - let (to_keys, _) = wallet_storage - .storage - .user_data - .user_private_accounts - .get(&to_addr) - .cloned() - .unwrap(); - - let command = Command::Transfer(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 sub_ret = wallet::execute_subcommand(command).await.unwrap(); - let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else { - panic!("FAILED TO SEND TX"); - }; - - let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await; - - println!("Waiting for next blocks to check if continoius run fetch account"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment1 = wallet_storage - .get_private_account_commitment(&from) - .unwrap(); - assert_eq!(tx.message.new_commitments[0], new_commitment1); - - assert_eq!(tx.message.new_commitments.len(), 2); - for commitment in tx.message.new_commitments.into_iter() { - assert!(verify_commitment_is_in_state(commitment, &seq_client).await); - } - - let to_res_acc = wallet_storage.get_account_private(&to_addr).unwrap(); - - assert_eq!(to_res_acc.balance, 100); - - continious_run_handle.abort(); - - info!("Success!"); -} - -pub async fn test_success_deshielded_transfer_to_another_account() { - 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::Transfer(NativeTokenTransferProgramSubcommand::Deshielded { - from: from.to_string(), - to: to.to_string(), - amount: 100, - }); - - let wallet_config = fetch_config().await.unwrap(); - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config.clone()) - .await - .unwrap(); - - let from_acc = wallet_storage.get_account_private(&from).unwrap(); - assert_eq!(from_acc.balance, 10000); - - wallet::execute_subcommand(command).await.unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let from_acc = wallet_storage.get_account_private(&from).unwrap(); - let new_commitment = wallet_storage - .get_private_account_commitment(&from) - .unwrap(); - assert!(verify_commitment_is_in_state(new_commitment, &seq_client).await); - - let acc_2_balance = seq_client - .get_account_balance(to.to_string()) - .await - .unwrap(); - - assert_eq!(from_acc.balance, 10000 - 100); - assert_eq!(acc_2_balance.balance, 20100); - - info!("Success!"); -} - -pub async fn test_success_shielded_transfer_to_another_owned_account() { - 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::Transfer(NativeTokenTransferProgramSubcommand::Shielded( - NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { - from: from.to_string(), - to: to.to_string(), - amount: 100, - }, - )); - - let wallet_config = fetch_config().await.unwrap(); - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - wallet::execute_subcommand(command).await.unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let wallet_config = fetch_config().await.unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let acc_to = wallet_storage.get_account_private(&to).unwrap(); - let new_commitment = wallet_storage.get_private_account_commitment(&to).unwrap(); - assert!(verify_commitment_is_in_state(new_commitment, &seq_client).await); - - let acc_from_balance = seq_client - .get_account_balance(from.to_string()) - .await - .unwrap(); - - assert_eq!(acc_from_balance.balance, 9900); - assert_eq!(acc_to.balance, 20000 + 100); - - info!("Success!"); -} - -pub async fn test_success_shielded_transfer_to_another_foreign_account() { - info!("test_success_shielded_transfer_to_another_foreign_account"); - let to_npk = NullifierPublicKey([42; 32]); - let to_npk_string = hex::encode(to_npk.0); - let to_ipk = Secp256k1Point::from_scalar(to_npk.0); - let from: Address = ACC_SENDER.parse().unwrap(); - - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Shielded( - NativeTokenTransferProgramSubcommandShielded::ShieldedForeign { - from: from.to_string(), - to_npk: to_npk_string, - to_ipk: hex::encode(to_ipk.0), - amount: 100, - }, - )); - - let wallet_config = fetch_config().await.unwrap(); - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = - wallet::execute_subcommand(command).await.unwrap() - else { - panic!("invalid subcommand return value"); - }; - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash).await; - - let acc_1_balance = seq_client - .get_account_balance(from.to_string()) - .await - .unwrap(); - - assert!( - verify_commitment_is_in_state(tx.message.new_commitments[0].clone(), &seq_client).await - ); - - assert_eq!(acc_1_balance.balance, 9900); - - info!("Success!"); -} - -pub async fn test_pinata() { - info!("test_pinata"); - let pinata_addr = "cafe".repeat(16); - let pinata_prize = 150; - let solution = 989106; - let command = Command::PinataProgram(PinataProgramSubcommand::Public( - PinataProgramSubcommandPublic::Claim { - pinata_addr: pinata_addr.clone(), - winner_addr: ACC_SENDER.to_string(), - solution, - }, - )); - - let wallet_config = fetch_config().await.unwrap(); - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - let pinata_balance_pre = seq_client - .get_account_balance(pinata_addr.clone()) - .await - .unwrap() - .balance; - - wallet::execute_subcommand(command).await.unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - info!("Checking correct balance move"); - let pinata_balance_post = seq_client - .get_account_balance(pinata_addr.clone()) - .await - .unwrap() - .balance; - - let winner_balance_post = seq_client - .get_account_balance(ACC_SENDER.to_string()) - .await - .unwrap() - .balance; - - assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize); - assert_eq!(winner_balance_post, 10000 + pinata_prize); - - info!("Success!"); -} - -pub async fn test_program_deployment() { - info!("test program deployment"); - let bytecode = NSSA_PROGRAM_FOR_TEST_DATA_CHANGER.to_vec(); - let message = nssa::program_deployment_transaction::Message::new(bytecode.clone()); - let transaction = ProgramDeploymentTransaction::new(message); - - let wallet_config = fetch_config().await.unwrap(); - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - let _response = seq_client.send_tx_program(transaction).await.unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - // The program is the data changer and takes one account as input. - // We pass an uninitialized account and we expect after execution to be owned by the data - // changer program (NSSA account claiming mechanism) with data equal to [0] (due to program logic) - let data_changer = Program::new(bytecode).unwrap(); - let address: Address = "deadbeef".repeat(8).parse().unwrap(); - let message = - nssa::public_transaction::Message::try_new(data_changer.id(), vec![address], vec![], ()) - .unwrap(); - let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]); - let transaction = nssa::PublicTransaction::new(message, witness_set); - let _response = seq_client.send_tx_public(transaction).await.unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let post_state_account = seq_client - .get_account(address.to_string()) - .await - .unwrap() - .account; - assert_eq!(post_state_account.program_owner, data_changer.id()); - assert_eq!(post_state_account.balance, 0); - assert_eq!(post_state_account.data, vec![0]); - assert_eq!(post_state_account.nonce, 0); - - info!("Success!"); -} - -pub async fn test_authenticated_transfer_initialize_function() { - info!("test initialize account for authenticated transfer"); - let command = Command::AuthenticatedTransferInitializePublicAccount {}; - - let SubcommandReturnValue::RegisterAccount { addr } = - wallet::execute_subcommand(command).await.unwrap() - else { - panic!("Error creating account"); - }; - - info!("Checking correct execution"); - let wallet_config = fetch_config().await.unwrap(); - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - let account = seq_client - .get_account(addr.to_string()) - .await - .unwrap() - .account; - - let expected_program_owner = Program::authenticated_transfer_program().id(); - let expected_nonce = 1; - let expected_balance = 0; - - assert_eq!(account.program_owner, expected_program_owner); - assert_eq!(account.balance, expected_balance); - assert_eq!(account.nonce, expected_nonce); - assert!(account.data.is_empty()); - - info!("Success!"); -} - -pub async fn test_pinata_private_receiver() { - info!("test_pinata_private_receiver"); - let pinata_addr = "cafe".repeat(16); - let pinata_prize = 150; - let solution = 989106; - - let command = Command::PinataProgram(PinataProgramSubcommand::Private( - PinataProgramSubcommandPrivate::ClaimPrivateOwned { - pinata_addr: pinata_addr.clone(), - winner_addr: ACC_SENDER_PRIVATE.to_string(), - solution, - }, - )); - - let wallet_config = fetch_config().await.unwrap(); - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - let pinata_balance_pre = seq_client - .get_account_balance(pinata_addr.clone()) - .await - .unwrap() - .balance; - - let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = - wallet::execute_subcommand(command).await.unwrap() - else { - panic!("invalid subcommand return value"); - }; - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - info!("Checking correct balance move"); - let pinata_balance_post = seq_client - .get_account_balance(pinata_addr.clone()) - .await - .unwrap() - .balance; - - let command = Command::Account(AccountSubcommand::Fetch(FetchSubcommand::PrivateAccount { - tx_hash: tx_hash.clone(), - acc_addr: ACC_SENDER_PRIVATE.to_string(), - output_id: 0, - })); - wallet::execute_subcommand(command).await.unwrap(); - - let wallet_config = fetch_config().await.unwrap(); - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment1 = wallet_storage - .get_private_account_commitment(&ACC_SENDER_PRIVATE.parse().unwrap()) - .unwrap(); - assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); - - assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize); - - info!("Success!"); -} - -pub async fn test_pinata_private_receiver_new_account() { - info!("test_pinata_private_receiver"); - let pinata_addr = "cafe".repeat(16); - let pinata_prize = 150; - let solution = 989106; - - // Create new account for the token supply holder (private) - let SubcommandReturnValue::RegisterAccount { addr: winner_addr } = wallet::execute_subcommand( - Command::Account(AccountSubcommand::Register(RegisterSubcommand::Private {})), - ) - .await - .unwrap() else { - panic!("invalid subcommand return value"); - }; - - let command = Command::PinataProgram(PinataProgramSubcommand::Private( - PinataProgramSubcommandPrivate::ClaimPrivateOwned { - pinata_addr: pinata_addr.clone(), - winner_addr: winner_addr.to_string(), - solution, - }, - )); - - let wallet_config = fetch_config().await.unwrap(); - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - let pinata_balance_pre = seq_client - .get_account_balance(pinata_addr.clone()) - .await - .unwrap() - .balance; - - wallet::execute_subcommand(command).await.unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - info!("Checking correct balance move"); - let pinata_balance_post = seq_client - .get_account_balance(pinata_addr.clone()) - .await - .unwrap() - .balance; - - let wallet_config = fetch_config().await.unwrap(); - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); - - let new_commitment1 = wallet_storage - .get_private_account_commitment(&winner_addr) - .unwrap(); - assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); - - assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize); - - info!("Success!"); -} - -macro_rules! test_cleanup_wrap { - ($home_dir:ident, $test_func:ident) => {{ - let res = pre_test($home_dir.clone()).await.unwrap(); - - info!("Waiting for first block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - $test_func().await; - - post_test(res).await; - }}; -} - pub async fn main_tests_runner() -> Result<()> { env_logger::init(); @@ -1623,175 +106,18 @@ pub async fn main_tests_runner() -> Result<()> { test_name, } = args; + let function_map = prepare_function_map(); + match test_name.as_str() { - "test_success_token_program" => { - test_cleanup_wrap!(home_dir, test_success_token_program); - } - "test_success_move_to_another_account" => { - test_cleanup_wrap!(home_dir, test_success_move_to_another_account); - } - "test_success" => { - test_cleanup_wrap!(home_dir, test_success); - } - "test_failure" => { - test_cleanup_wrap!(home_dir, test_failure); - } - "test_get_account" => { - test_cleanup_wrap!(home_dir, test_get_account); - } - "test_success_two_transactions" => { - test_cleanup_wrap!(home_dir, test_success_two_transactions); - } - "test_success_private_transfer_to_another_owned_account" => { - test_cleanup_wrap!( - home_dir, - test_success_private_transfer_to_another_owned_account - ); - } - "test_success_private_transfer_to_another_foreign_account" => { - test_cleanup_wrap!( - home_dir, - test_success_private_transfer_to_another_foreign_account - ); - } - "test_success_private_transfer_to_another_owned_account_claiming_path" => { - test_cleanup_wrap!( - home_dir, - test_success_private_transfer_to_another_owned_account_claiming_path - ); - } - "test_success_deshielded_transfer_to_another_account" => { - test_cleanup_wrap!( - home_dir, - test_success_deshielded_transfer_to_another_account - ); - } - "test_success_shielded_transfer_to_another_owned_account" => { - test_cleanup_wrap!( - home_dir, - test_success_shielded_transfer_to_another_owned_account - ); - } - "test_success_shielded_transfer_to_another_foreign_account" => { - test_cleanup_wrap!( - home_dir, - test_success_shielded_transfer_to_another_foreign_account - ); - } - "test_pinata" => { - test_cleanup_wrap!(home_dir, test_pinata); - } - "test_program_deployment" => { - test_cleanup_wrap!(home_dir, test_program_deployment); - } - "test_authenticated_transfer_initialize_function" => { - test_cleanup_wrap!(home_dir, test_authenticated_transfer_initialize_function); - } - "test_pinata_private_receiver" => { - test_cleanup_wrap!(home_dir, test_pinata_private_receiver); - } - "test_success_token_program_private_owned" => { - test_cleanup_wrap!(home_dir, test_success_token_program_private_owned); - } - "test_success_token_program_private_claiming_path" => { - test_cleanup_wrap!(home_dir, test_success_token_program_private_claiming_path); - } - "test_pinata_private_receiver_new_account" => { - test_cleanup_wrap!(home_dir, test_pinata_private_receiver_new_account); - } - "test_success_private_transfer_to_another_owned_account_cont_run_path" => { - test_cleanup_wrap!( - home_dir, - test_success_private_transfer_to_another_owned_account_cont_run_path - ); - } - "test_success_token_program_shielded_owned" => { - test_cleanup_wrap!(home_dir, test_success_token_program_shielded_owned); - } - "test_success_token_program_deshielded_owned" => { - test_cleanup_wrap!(home_dir, test_success_token_program_deshielded_owned); - } "all" => { - test_cleanup_wrap!(home_dir, test_success_move_to_another_account); - test_cleanup_wrap!(home_dir, test_success); - test_cleanup_wrap!(home_dir, test_failure); - test_cleanup_wrap!(home_dir, test_get_account); - test_cleanup_wrap!(home_dir, test_success_two_transactions); - test_cleanup_wrap!(home_dir, test_success_token_program); - test_cleanup_wrap!( - home_dir, - test_success_private_transfer_to_another_owned_account - ); - test_cleanup_wrap!( - home_dir, - test_success_private_transfer_to_another_foreign_account - ); - test_cleanup_wrap!( - home_dir, - test_success_deshielded_transfer_to_another_account - ); - test_cleanup_wrap!( - home_dir, - test_success_shielded_transfer_to_another_owned_account - ); - test_cleanup_wrap!( - home_dir, - test_success_shielded_transfer_to_another_foreign_account - ); - test_cleanup_wrap!( - home_dir, - test_success_private_transfer_to_another_owned_account_claiming_path - ); - test_cleanup_wrap!(home_dir, test_success_token_program_shielded_owned); - test_cleanup_wrap!(home_dir, test_pinata); - test_cleanup_wrap!(home_dir, test_program_deployment); - test_cleanup_wrap!(home_dir, test_authenticated_transfer_initialize_function); - test_cleanup_wrap!(home_dir, test_pinata_private_receiver); - test_cleanup_wrap!(home_dir, test_success_token_program_private_owned); - test_cleanup_wrap!(home_dir, test_success_token_program_deshielded_owned); - test_cleanup_wrap!(home_dir, test_success_token_program_private_claiming_path); - test_cleanup_wrap!(home_dir, test_pinata_private_receiver_new_account); - test_cleanup_wrap!( - home_dir, - test_success_private_transfer_to_another_owned_account_cont_run_path - ); - } - "all_private" => { - test_cleanup_wrap!( - home_dir, - test_success_private_transfer_to_another_owned_account - ); - test_cleanup_wrap!( - home_dir, - test_success_private_transfer_to_another_foreign_account - ); - test_cleanup_wrap!( - home_dir, - test_success_deshielded_transfer_to_another_account - ); - test_cleanup_wrap!( - home_dir, - test_success_shielded_transfer_to_another_owned_account - ); - test_cleanup_wrap!( - home_dir, - test_success_shielded_transfer_to_another_foreign_account - ); - test_cleanup_wrap!( - home_dir, - test_success_private_transfer_to_another_owned_account_claiming_path - ); - test_cleanup_wrap!(home_dir, test_pinata_private_receiver); - test_cleanup_wrap!(home_dir, test_success_token_program_private_owned); - test_cleanup_wrap!(home_dir, test_success_token_program_private_claiming_path); - test_cleanup_wrap!(home_dir, test_pinata_private_receiver_new_account); - test_cleanup_wrap!( - home_dir, - test_success_private_transfer_to_another_owned_account_cont_run_path - ); + for (_, fn_pointer) in function_map { + fn_pointer(home_dir.clone()).await; + } } _ => { - anyhow::bail!("Unknown test name"); + let fn_pointer = function_map.get(&test_name).expect("Unknown test name"); + + fn_pointer(home_dir.clone()).await; } } diff --git a/integration_tests/src/test_suite_map.rs b/integration_tests/src/test_suite_map.rs new file mode 100644 index 0000000..99a1371 --- /dev/null +++ b/integration_tests/src/test_suite_map.rs @@ -0,0 +1,1573 @@ +use std::{collections::HashMap, path::PathBuf, pin::Pin, time::Duration}; + +use common::sequencer_client::SequencerClient; +use log::info; +use nssa::{Address, ProgramDeploymentTransaction, program::Program}; +use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point}; +use wallet::{ + Command, SubcommandReturnValue, WalletCore, + cli::{ + account::{AccountSubcommand, FetchSubcommand, RegisterSubcommand}, + native_token_transfer_program::{ + NativeTokenTransferProgramSubcommand, NativeTokenTransferProgramSubcommandPrivate, + NativeTokenTransferProgramSubcommandShielded, + }, + pinata_program::{ + PinataProgramSubcommand, PinataProgramSubcommandPrivate, PinataProgramSubcommandPublic, + }, + token_program::{ + TokenProgramSubcommand, TokenProgramSubcommandDeshielded, + TokenProgramSubcommandPrivate, TokenProgramSubcommandPublic, + TokenProgramSubcommandShielded, + }, + }, + config::PersistentAccountData, + helperfunctions::{fetch_config, fetch_persistent_accounts}, +}; + +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, +}; +use crate::{post_test, pre_test, verify_commitment_is_in_state}; + +type TestFunction = fn(PathBuf) -> Pin>>; + +pub fn prepare_function_map() -> HashMap { + let mut function_map: HashMap = HashMap::new(); + + #[test_suite_fn] + pub async fn test_success() { + info!("test_success"); + let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { + from: ACC_SENDER.to_string(), + to: ACC_RECEIVER.to_string(), + amount: 100, + }); + + let wallet_config = fetch_config().await.unwrap(); + + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + wallet::execute_subcommand(command).await.unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + info!("Checking correct balance move"); + let acc_1_balance = seq_client + .get_account_balance(ACC_SENDER.to_string()) + .await + .unwrap(); + let acc_2_balance = seq_client + .get_account_balance(ACC_RECEIVER.to_string()) + .await + .unwrap(); + + info!("Balance of sender : {acc_1_balance:#?}"); + info!("Balance of receiver : {acc_2_balance:#?}"); + + assert_eq!(acc_1_balance.balance, 9900); + assert_eq!(acc_2_balance.balance, 20100); + + info!("Success!"); + } + + #[test_suite_fn] + pub async fn test_success_move_to_another_account() { + info!("test_success_move_to_another_account"); + let command = Command::Account(AccountSubcommand::Register(RegisterSubcommand::Public {})); + + let wallet_config = fetch_config().await.unwrap(); + + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + wallet::execute_subcommand(command).await.unwrap(); + + let persistent_accounts = fetch_persistent_accounts().await.unwrap(); + + let mut new_persistent_account_addr = String::new(); + + for per_acc in persistent_accounts { + if (per_acc.address().to_string() != ACC_RECEIVER) + && (per_acc.address().to_string() != ACC_SENDER) + { + new_persistent_account_addr = per_acc.address().to_string(); + } + } + + if new_persistent_account_addr == String::new() { + panic!("Failed to produce new account, not present in persistent accounts"); + } + + let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { + from: ACC_SENDER.to_string(), + to: new_persistent_account_addr.clone(), + amount: 100, + }); + + wallet::execute_subcommand(command).await.unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + info!("Checking correct balance move"); + let acc_1_balance = seq_client + .get_account_balance(ACC_SENDER.to_string()) + .await + .unwrap(); + let acc_2_balance = seq_client + .get_account_balance(new_persistent_account_addr) + .await + .unwrap(); + + info!("Balance of sender : {acc_1_balance:#?}"); + info!("Balance of receiver : {acc_2_balance:#?}"); + + assert_eq!(acc_1_balance.balance, 9900); + assert_eq!(acc_2_balance.balance, 100); + + info!("Success!"); + } + + #[test_suite_fn] + pub async fn test_failure() { + info!("test_failure"); + let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { + from: ACC_SENDER.to_string(), + to: ACC_RECEIVER.to_string(), + amount: 1000000, + }); + + let wallet_config = fetch_config().await.unwrap(); + + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + let failed_send = wallet::execute_subcommand(command).await; + + assert!(failed_send.is_err()); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + info!("Checking correct balance move"); + let acc_1_balance = seq_client + .get_account_balance(ACC_SENDER.to_string()) + .await + .unwrap(); + let acc_2_balance = seq_client + .get_account_balance(ACC_RECEIVER.to_string()) + .await + .unwrap(); + + info!("Balance of sender : {acc_1_balance:#?}"); + info!("Balance of receiver : {acc_2_balance:#?}"); + + assert_eq!(acc_1_balance.balance, 10000); + assert_eq!(acc_2_balance.balance, 20000); + + info!("Success!"); + } + + #[test_suite_fn] + pub async fn test_success_two_transactions() { + info!("test_success_two_transactions"); + let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { + from: ACC_SENDER.to_string(), + to: ACC_RECEIVER.to_string(), + amount: 100, + }); + + let wallet_config = fetch_config().await.unwrap(); + + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + wallet::execute_subcommand(command).await.unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + info!("Checking correct balance move"); + let acc_1_balance = seq_client + .get_account_balance(ACC_SENDER.to_string()) + .await + .unwrap(); + let acc_2_balance = seq_client + .get_account_balance(ACC_RECEIVER.to_string()) + .await + .unwrap(); + + info!("Balance of sender : {acc_1_balance:#?}"); + info!("Balance of receiver : {acc_2_balance:#?}"); + + assert_eq!(acc_1_balance.balance, 9900); + assert_eq!(acc_2_balance.balance, 20100); + + info!("First TX Success!"); + + let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { + from: ACC_SENDER.to_string(), + to: ACC_RECEIVER.to_string(), + amount: 100, + }); + + wallet::execute_subcommand(command).await.unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + info!("Checking correct balance move"); + let acc_1_balance = seq_client + .get_account_balance(ACC_SENDER.to_string()) + .await + .unwrap(); + let acc_2_balance = seq_client + .get_account_balance(ACC_RECEIVER.to_string()) + .await + .unwrap(); + + info!("Balance of sender : {acc_1_balance:#?}"); + info!("Balance of receiver : {acc_2_balance:#?}"); + + assert_eq!(acc_1_balance.balance, 9800); + assert_eq!(acc_2_balance.balance, 20200); + + info!("Second TX Success!"); + } + + #[test_suite_fn] + pub async fn test_get_account() { + info!("test_get_account"); + let wallet_config = fetch_config().await.unwrap(); + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + let account = seq_client + .get_account(ACC_SENDER.to_string()) + .await + .unwrap() + .account; + + assert_eq!( + account.program_owner, + Program::authenticated_transfer_program().id() + ); + assert_eq!(account.balance, 10000); + assert!(account.data.is_empty()); + assert_eq!(account.nonce, 0); + } + + /// This test creates a new token using the token program. After creating the token, the test executes a + /// token transfer to a new account. + #[test_suite_fn] + pub async fn test_success_token_program() { + let wallet_config = fetch_config().await.unwrap(); + + // Create new account for the token definition + wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Public {}, + ))) + .await + .unwrap(); + // Create new account for the token supply holder + wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Public {}, + ))) + .await + .unwrap(); + // Create new account for receiving a token transaction + wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Public {}, + ))) + .await + .unwrap(); + + let persistent_accounts = fetch_persistent_accounts().await.unwrap(); + + let mut new_persistent_accounts_addr = Vec::new(); + + for per_acc in persistent_accounts { + match per_acc { + PersistentAccountData::Public(per_acc) => { + if (per_acc.address.to_string() != ACC_RECEIVER) + && (per_acc.address.to_string() != ACC_SENDER) + { + new_persistent_accounts_addr.push(per_acc.address); + } + } + _ => continue, + } + } + + let [definition_addr, supply_addr, recipient_addr] = new_persistent_accounts_addr + .try_into() + .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, + }); + wallet::execute_subcommand(Command::TokenProgram(subcommand)) + .await + .unwrap(); + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + // Check the status of the token definition account is the expected after the execution + let definition_acc = seq_client + .get_account(definition_addr.to_string()) + .await + .unwrap() + .account; + + assert_eq!(definition_acc.program_owner, Program::token().id()); + // The data of a token definition account has the following layout: + // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] + assert_eq!( + definition_acc.data, + vec![ + 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ] + ); + + // Check the status of the token holding account with the total supply is the expected after the execution + let supply_acc = seq_client + .get_account(supply_addr.to_string()) + .await + .unwrap() + .account; + + // The account must be owned by the token program + assert_eq!(supply_acc.program_owner, Program::token().id()); + // The data of a token definition account has the following layout: + // [ 0x01 || corresponding_token_definition_id (32 bytes) || balance (little endian 16 bytes) ] + // First byte of the data equal to 1 means it's a token holding account + assert_eq!(supply_acc.data[0], 1); + // Bytes from 1 to 33 represent the id of the token this account is associated with. + // In this example, this is a token account of the newly created token, so it is expected + // to be equal to the address of the token definition account. + assert_eq!(&supply_acc.data[1..33], definition_addr.to_bytes()); + assert_eq!( + u128::from_le_bytes(supply_acc.data[33..].try_into().unwrap()), + 37 + ); + + // 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, + }); + wallet::execute_subcommand(Command::TokenProgram(subcommand)) + .await + .unwrap(); + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + // Check the status of the account at `supply_addr` is the expected after the execution + let supply_acc = seq_client + .get_account(supply_addr.to_string()) + .await + .unwrap() + .account; + // The account must be owned by the token program + assert_eq!(supply_acc.program_owner, Program::token().id()); + // First byte equal to 1 means it's a token holding account + assert_eq!(supply_acc.data[0], 1); + // Bytes from 1 to 33 represent the id of the token this account is associated with. + assert_eq!(&supply_acc.data[1..33], definition_addr.to_bytes()); + assert_eq!( + u128::from_le_bytes(supply_acc.data[33..].try_into().unwrap()), + 30 + ); + + // Check the status of the account at `recipient_addr` is the expected after the execution + let recipient_acc = seq_client + .get_account(recipient_addr.to_string()) + .await + .unwrap() + .account; + + // The account must be owned by the token program + assert_eq!(recipient_acc.program_owner, Program::token().id()); + // First byte equal to 1 means it's a token holding account + assert_eq!(recipient_acc.data[0], 1); + // Bytes from 1 to 33 represent the id of the token this account is associated with. + assert_eq!(&recipient_acc.data[1..33], definition_addr.to_bytes()); + assert_eq!( + u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()), + 7 + ); + } + + /// This test creates a new private token using the token program. After creating the token, the test executes a + /// private token transfer to a new account. All accounts are owned except definition. + #[test_suite_fn] + pub async fn test_success_token_program_private_owned() { + let wallet_config = fetch_config().await.unwrap(); + + // Create new account for the token definition (public) + let SubcommandReturnValue::RegisterAccount { + addr: definition_addr, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Public {}, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + // Create new account for the token supply holder (private) + let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = + wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Private {}, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + // Create new account for receiving a token transaction + let SubcommandReturnValue::RegisterAccount { + addr: recipient_addr, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Private {}, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + + // 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, + }, + ); + + wallet::execute_subcommand(Command::TokenProgram(subcommand)) + .await + .unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + // Check the status of the token definition account is the expected after the execution + let definition_acc = seq_client + .get_account(definition_addr.to_string()) + .await + .unwrap() + .account; + + assert_eq!(definition_acc.program_owner, Program::token().id()); + // The data of a token definition account has the following layout: + // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] + assert_eq!( + definition_acc.data, + vec![ + 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ] + ); + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment1 = wallet_storage + .get_private_account_commitment(&supply_addr) + .unwrap(); + 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, + }, + ); + + wallet::execute_subcommand(Command::TokenProgram(subcommand)) + .await + .unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment1 = wallet_storage + .get_private_account_commitment(&supply_addr) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); + + let new_commitment2 = wallet_storage + .get_private_account_commitment(&recipient_addr) + .unwrap(); + 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, + }, + ); + + wallet::execute_subcommand(Command::TokenProgram(subcommand)) + .await + .unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment1 = wallet_storage + .get_private_account_commitment(&supply_addr) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); + + let new_commitment2 = wallet_storage + .get_private_account_commitment(&recipient_addr) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); + } + + /// This test creates a new private token using the token program. After creating the token, the test executes a + /// private token transfer to a new account. + #[test_suite_fn] + pub async fn test_success_token_program_private_claiming_path() { + let wallet_config = fetch_config().await.unwrap(); + + // Create new account for the token definition (public) + let SubcommandReturnValue::RegisterAccount { + addr: definition_addr, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Public {}, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + // Create new account for the token supply holder (private) + let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = + wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Private {}, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + // Create new account for receiving a token transaction + let SubcommandReturnValue::RegisterAccount { + addr: recipient_addr, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Private {}, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + + // 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, + }, + ); + + wallet::execute_subcommand(Command::TokenProgram(subcommand)) + .await + .unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + // Check the status of the token definition account is the expected after the execution + let definition_acc = seq_client + .get_account(definition_addr.to_string()) + .await + .unwrap() + .account; + + assert_eq!(definition_acc.program_owner, Program::token().id()); + // The data of a token definition account has the following layout: + // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] + assert_eq!( + definition_acc.data, + vec![ + 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ] + ); + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment1 = wallet_storage + .get_private_account_commitment(&supply_addr) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); + + let (recipient_keys, _) = wallet_storage + .storage + .user_data + .get_private_account(&recipient_addr) + .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 SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = + wallet::execute_subcommand(Command::TokenProgram(subcommand)) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let command = Command::Account(AccountSubcommand::Fetch(FetchSubcommand::PrivateAccount { + tx_hash, + acc_addr: recipient_addr.to_string(), + output_id: 1, + })); + + wallet::execute_subcommand(command).await.unwrap(); + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment1 = wallet_storage + .get_private_account_commitment(&supply_addr) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); + + let new_commitment2 = wallet_storage + .get_private_account_commitment(&recipient_addr) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); + } + + /// This test creates a new public token using the token program. After creating the token, the test executes a + /// shielded token transfer to a new account. All accounts are owned except definition. + #[test_suite_fn] + pub async fn test_success_token_program_shielded_owned() { + let wallet_config = fetch_config().await.unwrap(); + + // Create new account for the token definition (public) + let SubcommandReturnValue::RegisterAccount { + addr: definition_addr, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Public {}, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + // Create new account for the token supply holder (public) + let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = + wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Public {}, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + // Create new account for receiving a token transaction + let SubcommandReturnValue::RegisterAccount { + addr: recipient_addr, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Private {}, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + + // 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, + }); + + wallet::execute_subcommand(Command::TokenProgram(subcommand)) + .await + .unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + // Check the status of the token definition account is the expected after the execution + let definition_acc = seq_client + .get_account(definition_addr.to_string()) + .await + .unwrap() + .account; + + assert_eq!(definition_acc.program_owner, Program::token().id()); + // The data of a token definition account has the following layout: + // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] + assert_eq!( + definition_acc.data, + vec![ + 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ] + ); + + // 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, + }, + ); + + wallet::execute_subcommand(Command::TokenProgram(subcommand)) + .await + .unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment2 = wallet_storage + .get_private_account_commitment(&recipient_addr) + .unwrap(); + 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, + }, + ); + + wallet::execute_subcommand(Command::TokenProgram(subcommand)) + .await + .unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment2 = wallet_storage + .get_private_account_commitment(&recipient_addr) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); + } + + /// This test creates a new private token using the token program. After creating the token, the test executes a + /// deshielded token transfer to a new account. All accounts are owned except definition. + #[test_suite_fn] + pub async fn test_success_token_program_deshielded_owned() { + let wallet_config = fetch_config().await.unwrap(); + + // Create new account for the token definition (public) + let SubcommandReturnValue::RegisterAccount { + addr: definition_addr, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Public {}, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + // Create new account for the token supply holder (private) + let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = + wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Private {}, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + // Create new account for receiving a token transaction + let SubcommandReturnValue::RegisterAccount { + addr: recipient_addr, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Public {}, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + + // 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, + }, + ); + + wallet::execute_subcommand(Command::TokenProgram(subcommand)) + .await + .unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + // Check the status of the token definition account is the expected after the execution + let definition_acc = seq_client + .get_account(definition_addr.to_string()) + .await + .unwrap() + .account; + + assert_eq!(definition_acc.program_owner, Program::token().id()); + // The data of a token definition account has the following layout: + // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] + assert_eq!( + definition_acc.data, + vec![ + 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ] + ); + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment1 = wallet_storage + .get_private_account_commitment(&supply_addr) + .unwrap(); + 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, + }, + ); + + wallet::execute_subcommand(Command::TokenProgram(subcommand)) + .await + .unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment1 = wallet_storage + .get_private_account_commitment(&supply_addr) + .unwrap(); + 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, + }, + ); + + wallet::execute_subcommand(Command::TokenProgram(subcommand)) + .await + .unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment1 = wallet_storage + .get_private_account_commitment(&supply_addr) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); + } + + #[test_suite_fn] + pub async fn test_success_private_transfer_to_another_owned_account() { + info!("test_success_private_transfer_to_another_owned_account"); + let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); + let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap(); + + let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Private( + NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { + from: from.to_string(), + to: to.to_string(), + amount: 100, + }, + )); + + wallet::execute_subcommand(command).await.unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let wallet_config = fetch_config().await.unwrap(); + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment1 = wallet_storage + .get_private_account_commitment(&from) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); + + let new_commitment2 = wallet_storage.get_private_account_commitment(&to).unwrap(); + assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); + + info!("Success!"); + } + + #[test_suite_fn] + pub async fn test_success_private_transfer_to_another_foreign_account() { + info!("test_success_private_transfer_to_another_foreign_account"); + let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); + let to_npk = NullifierPublicKey([42; 32]); + let to_npk_string = hex::encode(to_npk.0); + let to_ipk = Secp256k1Point::from_scalar(to_npk.0); + + let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Private( + NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { + from: from.to_string(), + to_npk: to_npk_string, + to_ipk: hex::encode(to_ipk.0), + amount: 100, + }, + )); + + let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = + wallet::execute_subcommand(command).await.unwrap() + else { + panic!("invalid subcommand return value"); + }; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let wallet_config = fetch_config().await.unwrap(); + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment1 = wallet_storage + .get_private_account_commitment(&from) + .unwrap(); + + let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await; + assert_eq!(tx.message.new_commitments[0], new_commitment1); + + assert_eq!(tx.message.new_commitments.len(), 2); + for commitment in tx.message.new_commitments.into_iter() { + assert!(verify_commitment_is_in_state(commitment, &seq_client).await); + } + + info!("Success!"); + } + + #[test_suite_fn] + pub async fn test_success_private_transfer_to_another_owned_account_claiming_path() { + info!("test_success_private_transfer_to_another_owned_account_claiming_path"); + let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); + + let command = Command::Account(AccountSubcommand::Register(RegisterSubcommand::Private {})); + + let sub_ret = wallet::execute_subcommand(command).await.unwrap(); + let SubcommandReturnValue::RegisterAccount { addr: to_addr } = sub_ret else { + panic!("FAILED TO REGISTER ACCOUNT"); + }; + + let wallet_config = fetch_config().await.unwrap(); + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config.clone()) + .await + .unwrap(); + + let (to_keys, _) = wallet_storage + .storage + .user_data + .user_private_accounts + .get(&to_addr) + .cloned() + .unwrap(); + + let command = Command::Transfer(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 sub_ret = wallet::execute_subcommand(command).await.unwrap(); + let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else { + panic!("FAILED TO SEND TX"); + }; + + let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await; + + let command = Command::Account(AccountSubcommand::Fetch(FetchSubcommand::PrivateAccount { + tx_hash, + acc_addr: to_addr.to_string(), + output_id: 1, + })); + wallet::execute_subcommand(command).await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment1 = wallet_storage + .get_private_account_commitment(&from) + .unwrap(); + assert_eq!(tx.message.new_commitments[0], new_commitment1); + + assert_eq!(tx.message.new_commitments.len(), 2); + for commitment in tx.message.new_commitments.into_iter() { + assert!(verify_commitment_is_in_state(commitment, &seq_client).await); + } + + let to_res_acc = wallet_storage.get_account_private(&to_addr).unwrap(); + + assert_eq!(to_res_acc.balance, 100); + + info!("Success!"); + } + + #[test_suite_fn] + pub async fn test_success_private_transfer_to_another_owned_account_cont_run_path() { + info!("test_success_private_transfer_to_another_owned_account_cont_run_path"); + let continious_run_handle = tokio::spawn(wallet::execute_continious_run()); + + let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); + + let command = Command::Account(AccountSubcommand::Register(RegisterSubcommand::Private {})); + + let sub_ret = wallet::execute_subcommand(command).await.unwrap(); + let SubcommandReturnValue::RegisterAccount { addr: to_addr } = sub_ret else { + panic!("FAILED TO REGISTER ACCOUNT"); + }; + + let wallet_config = fetch_config().await.unwrap(); + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config.clone()) + .await + .unwrap(); + + let (to_keys, _) = wallet_storage + .storage + .user_data + .user_private_accounts + .get(&to_addr) + .cloned() + .unwrap(); + + let command = Command::Transfer(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 sub_ret = wallet::execute_subcommand(command).await.unwrap(); + let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else { + panic!("FAILED TO SEND TX"); + }; + + let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await; + + println!("Waiting for next blocks to check if continoius run fetch account"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment1 = wallet_storage + .get_private_account_commitment(&from) + .unwrap(); + assert_eq!(tx.message.new_commitments[0], new_commitment1); + + assert_eq!(tx.message.new_commitments.len(), 2); + for commitment in tx.message.new_commitments.into_iter() { + assert!(verify_commitment_is_in_state(commitment, &seq_client).await); + } + + let to_res_acc = wallet_storage.get_account_private(&to_addr).unwrap(); + + assert_eq!(to_res_acc.balance, 100); + + continious_run_handle.abort(); + + info!("Success!"); + } + + #[test_suite_fn] + pub async fn test_success_deshielded_transfer_to_another_account() { + 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::Transfer(NativeTokenTransferProgramSubcommand::Deshielded { + from: from.to_string(), + to: to.to_string(), + amount: 100, + }); + + let wallet_config = fetch_config().await.unwrap(); + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config.clone()) + .await + .unwrap(); + + let from_acc = wallet_storage.get_account_private(&from).unwrap(); + assert_eq!(from_acc.balance, 10000); + + wallet::execute_subcommand(command).await.unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let from_acc = wallet_storage.get_account_private(&from).unwrap(); + let new_commitment = wallet_storage + .get_private_account_commitment(&from) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment, &seq_client).await); + + let acc_2_balance = seq_client + .get_account_balance(to.to_string()) + .await + .unwrap(); + + assert_eq!(from_acc.balance, 10000 - 100); + assert_eq!(acc_2_balance.balance, 20100); + + info!("Success!"); + } + + #[test_suite_fn] + pub async fn test_success_shielded_transfer_to_another_owned_account() { + 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::Transfer(NativeTokenTransferProgramSubcommand::Shielded( + NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { + from: from.to_string(), + to: to.to_string(), + amount: 100, + }, + )); + + let wallet_config = fetch_config().await.unwrap(); + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + wallet::execute_subcommand(command).await.unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let acc_to = wallet_storage.get_account_private(&to).unwrap(); + let new_commitment = wallet_storage.get_private_account_commitment(&to).unwrap(); + assert!(verify_commitment_is_in_state(new_commitment, &seq_client).await); + + let acc_from_balance = seq_client + .get_account_balance(from.to_string()) + .await + .unwrap(); + + assert_eq!(acc_from_balance.balance, 9900); + assert_eq!(acc_to.balance, 20000 + 100); + + info!("Success!"); + } + + #[test_suite_fn] + pub async fn test_success_shielded_transfer_to_another_foreign_account() { + info!("test_success_shielded_transfer_to_another_foreign_account"); + let to_npk = NullifierPublicKey([42; 32]); + let to_npk_string = hex::encode(to_npk.0); + let to_ipk = Secp256k1Point::from_scalar(to_npk.0); + let from: Address = ACC_SENDER.parse().unwrap(); + + let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Shielded( + NativeTokenTransferProgramSubcommandShielded::ShieldedForeign { + from: from.to_string(), + to_npk: to_npk_string, + to_ipk: hex::encode(to_ipk.0), + amount: 100, + }, + )); + + let wallet_config = fetch_config().await.unwrap(); + + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = + wallet::execute_subcommand(command).await.unwrap() + else { + panic!("invalid subcommand return value"); + }; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash).await; + + let acc_1_balance = seq_client + .get_account_balance(from.to_string()) + .await + .unwrap(); + + assert!( + verify_commitment_is_in_state(tx.message.new_commitments[0].clone(), &seq_client).await + ); + + assert_eq!(acc_1_balance.balance, 9900); + + info!("Success!"); + } + + #[test_suite_fn] + pub async fn test_pinata() { + info!("test_pinata"); + let pinata_addr = "cafe".repeat(16); + let pinata_prize = 150; + let solution = 989106; + let command = Command::PinataProgram(PinataProgramSubcommand::Public( + PinataProgramSubcommandPublic::Claim { + pinata_addr: pinata_addr.clone(), + winner_addr: ACC_SENDER.to_string(), + solution, + }, + )); + + let wallet_config = fetch_config().await.unwrap(); + + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + let pinata_balance_pre = seq_client + .get_account_balance(pinata_addr.clone()) + .await + .unwrap() + .balance; + + wallet::execute_subcommand(command).await.unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + info!("Checking correct balance move"); + let pinata_balance_post = seq_client + .get_account_balance(pinata_addr.clone()) + .await + .unwrap() + .balance; + + let winner_balance_post = seq_client + .get_account_balance(ACC_SENDER.to_string()) + .await + .unwrap() + .balance; + + assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize); + assert_eq!(winner_balance_post, 10000 + pinata_prize); + + info!("Success!"); + } + + #[test_suite_fn] + pub async fn test_program_deployment() { + info!("test program deployment"); + let bytecode = NSSA_PROGRAM_FOR_TEST_DATA_CHANGER.to_vec(); + let message = nssa::program_deployment_transaction::Message::new(bytecode.clone()); + let transaction = ProgramDeploymentTransaction::new(message); + + let wallet_config = fetch_config().await.unwrap(); + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + let _response = seq_client.send_tx_program(transaction).await.unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + // The program is the data changer and takes one account as input. + // We pass an uninitialized account and we expect after execution to be owned by the data + // changer program (NSSA account claiming mechanism) with data equal to [0] (due to program logic) + let data_changer = Program::new(bytecode).unwrap(); + let address: Address = "deadbeef".repeat(8).parse().unwrap(); + let message = nssa::public_transaction::Message::try_new( + data_changer.id(), + vec![address], + vec![], + (), + ) + .unwrap(); + let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]); + let transaction = nssa::PublicTransaction::new(message, witness_set); + let _response = seq_client.send_tx_public(transaction).await.unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let post_state_account = seq_client + .get_account(address.to_string()) + .await + .unwrap() + .account; + assert_eq!(post_state_account.program_owner, data_changer.id()); + assert_eq!(post_state_account.balance, 0); + assert_eq!(post_state_account.data, vec![0]); + assert_eq!(post_state_account.nonce, 0); + + info!("Success!"); + } + + #[test_suite_fn] + pub async fn test_authenticated_transfer_initialize_function() { + info!("test initialize account for authenticated transfer"); + let command = Command::AuthenticatedTransferInitializePublicAccount {}; + + let SubcommandReturnValue::RegisterAccount { addr } = + wallet::execute_subcommand(command).await.unwrap() + else { + panic!("Error creating account"); + }; + + info!("Checking correct execution"); + let wallet_config = fetch_config().await.unwrap(); + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + let account = seq_client + .get_account(addr.to_string()) + .await + .unwrap() + .account; + + let expected_program_owner = Program::authenticated_transfer_program().id(); + let expected_nonce = 1; + let expected_balance = 0; + + assert_eq!(account.program_owner, expected_program_owner); + assert_eq!(account.balance, expected_balance); + assert_eq!(account.nonce, expected_nonce); + assert!(account.data.is_empty()); + + info!("Success!"); + } + + #[test_suite_fn] + pub async fn test_pinata_private_receiver() { + info!("test_pinata_private_receiver"); + let pinata_addr = "cafe".repeat(16); + let pinata_prize = 150; + let solution = 989106; + + let command = Command::PinataProgram(PinataProgramSubcommand::Private( + PinataProgramSubcommandPrivate::ClaimPrivateOwned { + pinata_addr: pinata_addr.clone(), + winner_addr: ACC_SENDER_PRIVATE.to_string(), + solution, + }, + )); + + let wallet_config = fetch_config().await.unwrap(); + + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + let pinata_balance_pre = seq_client + .get_account_balance(pinata_addr.clone()) + .await + .unwrap() + .balance; + + let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = + wallet::execute_subcommand(command).await.unwrap() + else { + panic!("invalid subcommand return value"); + }; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + info!("Checking correct balance move"); + let pinata_balance_post = seq_client + .get_account_balance(pinata_addr.clone()) + .await + .unwrap() + .balance; + + let command = Command::Account(AccountSubcommand::Fetch(FetchSubcommand::PrivateAccount { + tx_hash: tx_hash.clone(), + acc_addr: ACC_SENDER_PRIVATE.to_string(), + output_id: 0, + })); + wallet::execute_subcommand(command).await.unwrap(); + + let wallet_config = fetch_config().await.unwrap(); + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment1 = wallet_storage + .get_private_account_commitment(&ACC_SENDER_PRIVATE.parse().unwrap()) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); + + assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize); + + info!("Success!"); + } + + #[test_suite_fn] + pub async fn test_pinata_private_receiver_new_account() { + info!("test_pinata_private_receiver"); + let pinata_addr = "cafe".repeat(16); + let pinata_prize = 150; + let solution = 989106; + + // Create new account for the token supply holder (private) + let SubcommandReturnValue::RegisterAccount { addr: winner_addr } = + wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( + RegisterSubcommand::Private {}, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + + let command = Command::PinataProgram(PinataProgramSubcommand::Private( + PinataProgramSubcommandPrivate::ClaimPrivateOwned { + pinata_addr: pinata_addr.clone(), + winner_addr: winner_addr.to_string(), + solution, + }, + )); + + let wallet_config = fetch_config().await.unwrap(); + + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + let pinata_balance_pre = seq_client + .get_account_balance(pinata_addr.clone()) + .await + .unwrap() + .balance; + + wallet::execute_subcommand(command).await.unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + info!("Checking correct balance move"); + let pinata_balance_post = seq_client + .get_account_balance(pinata_addr.clone()) + .await + .unwrap() + .balance; + + let wallet_config = fetch_config().await.unwrap(); + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment1 = wallet_storage + .get_private_account_commitment(&winner_addr) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); + + assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize); + + info!("Success!"); + } + + println!("{function_map:#?}"); + + function_map +} diff --git a/proc_macro_test_attribute/Cargo.toml b/proc_macro_test_attribute/Cargo.toml new file mode 100644 index 0000000..7e8ab69 --- /dev/null +++ b/proc_macro_test_attribute/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "proc_macro_test_attribute" +version = "0.1.0" +edition = "2024" + +[dependencies] + +[lib] +proc-macro = true \ No newline at end of file diff --git a/proc_macro_test_attribute/src/lib.rs b/proc_macro_test_attribute/src/lib.rs new file mode 100644 index 0000000..59d2d0c --- /dev/null +++ b/proc_macro_test_attribute/src/lib.rs @@ -0,0 +1,49 @@ +extern crate proc_macro; + +use proc_macro::*; + +#[proc_macro_attribute] +pub fn test_suite_fn(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input = item.to_string(); + + let fn_keyword = "fn "; + let fn_keyword_alternative = "fn\n"; + + let mut start_opt = None; + let mut fn_name = String::new(); + + if let Some(start) = input.find(fn_keyword) { + start_opt = Some(start); + } else if let Some(start) = input.find(fn_keyword_alternative) { + start_opt = Some(start); + } + + if let Some(start) = start_opt { + let rest = &input[start + fn_keyword.len()..]; + if let Some(end) = rest.find(|c: char| c == '(' || c.is_whitespace()) { + let name = &rest[..end]; + fn_name = name.to_string(); + } + } else { + println!("ERROR: keyword fn not found"); + } + + let extension = format!( + r#" + {input} + + function_map.insert("{fn_name}".to_string(), |home_dir: PathBuf| Box::pin(async {{ + let res = pre_test(home_dir).await.unwrap(); + + info!("Waiting for first block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + {fn_name}().await; + + post_test(res).await; + }})); + "# + ); + + extension.parse().unwrap() +} From d7089eac9603287fa0bf3b1f3759fc6cf37cacff Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Wed, 22 Oct 2025 16:28:19 +0300 Subject: [PATCH 5/7] fix: taplo fmt --- Cargo.toml | 2 +- proc_macro_test_attribute/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index df38af7..2019628 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ members = [ "wallet", "sequencer_core", "common", - "nssa", + "nssa", "proc_macro_test_attribute", ] diff --git a/proc_macro_test_attribute/Cargo.toml b/proc_macro_test_attribute/Cargo.toml index 7e8ab69..a50c3f3 100644 --- a/proc_macro_test_attribute/Cargo.toml +++ b/proc_macro_test_attribute/Cargo.toml @@ -6,4 +6,4 @@ edition = "2024" [dependencies] [lib] -proc-macro = true \ No newline at end of file +proc-macro = true From a14b15d1232d7728768b708f1c336c4bf8a8c854 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Sat, 25 Oct 2025 00:34:02 -0300 Subject: [PATCH 6/7] add Cargo.lock --- nssa/program_methods/guest/Cargo.lock | 3618 +++++++++++++++++++++++++ 1 file changed, 3618 insertions(+) create mode 100644 nssa/program_methods/guest/Cargo.lock diff --git a/nssa/program_methods/guest/Cargo.lock b/nssa/program_methods/guest/Cargo.lock new file mode 100644 index 0000000..47585ba --- /dev/null +++ b/nssa/program_methods/guest/Cargo.lock @@ -0,0 +1,3618 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-r1cs-std", + "ark-std", +] + +[[package]] +name = "ark-crypto-primitives" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0c292754729c8a190e50414fd1a37093c786c709899f29c9f7daccecfa855e" +dependencies = [ + "ahash", + "ark-crypto-primitives-macros", + "ark-ec", + "ark-ff", + "ark-relations", + "ark-serialize", + "ark-snark", + "ark-std", + "blake2", + "derivative", + "digest", + "fnv", + "merlin", + "sha2", +] + +[[package]] +name = "ark-crypto-primitives-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e89fe77d1f0f4fe5b96dfc940923d88d17b6a773808124f21e764dfb063c6a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "educe", + "fnv", + "hashbrown 0.15.5", + "itertools 0.13.0", + "num-bigint", + "num-integer", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "arrayvec", + "digest", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.106", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "ark-groth16" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88f1d0f3a534bb54188b8dcc104307db6c56cdae574ddc3212aec0625740fc7e" +dependencies = [ + "ark-crypto-primitives", + "ark-ec", + "ark-ff", + "ark-poly", + "ark-relations", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff", + "ark-serialize", + "ark-std", + "educe", + "fnv", + "hashbrown 0.15.5", +] + +[[package]] +name = "ark-r1cs-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941551ef1df4c7a401de7068758db6503598e6f01850bdb2cfdb614a1f9dbea1" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-relations", + "ark-std", + "educe", + "num-bigint", + "num-integer", + "num-traits", + "tracing", +] + +[[package]] +name = "ark-relations" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384" +dependencies = [ + "ark-ff", + "ark-std", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "arrayvec", + "digest", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "ark-snark" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d368e2848c2d4c129ce7679a7d0d2d612b6a274d3ea6a13bad4445d61b381b88" +dependencies = [ + "ark-ff", + "ark-relations", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "arraydeque" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bonsai-sdk" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21055e2f49cbbdbfe9f8f96d597c5527b0c6ab7933341fdc2f147180e48a988e" +dependencies = [ + "duplicate", + "maybe-async", + "reqwest", + "serde", + "thiserror", +] + +[[package]] +name = "borsh" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bytemuck" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +dependencies = [ + "serde", +] + +[[package]] +name = "camino" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.2.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chrono" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.106", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.106", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.106", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "docker-generate" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf673e0848ef09fa4aeeba78e681cf651c0c7d35f76ee38cec8e55bc32fa111" + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "duplicate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97af9b5f014e228b33e77d75ee0e6e87960124f0f4b16337b586a6bec91867b1" +dependencies = [ + "heck", + "proc-macro2", + "proc-macro2-diagnostics", +] + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elf" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasi 0.14.7+wasi-0.2.4", + "wasm-bindgen", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "include_bytes_aligned" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee796ad498c8d9a1d68e477df8f754ed784ef875de1414ebdaf169f70a6a784" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown 0.16.0", + "serde", + "serde_core", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy-regex" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60c7310b93682b36b98fa7ea4de998d3463ccbebd94d935d6b48ba5b6ffa7126" +dependencies = [ + "lazy-regex-proc_macros", + "once_cell", + "regex", +] + +[[package]] +name = "lazy-regex-proc_macros" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ba01db5ef81e17eb10a5e0f2109d1b3a3e29bac3070fdbd7d156bf7dbd206a1" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 2.0.106", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags 2.9.4", + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "maybe-async" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "metal" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" +dependencies = [ + "bitflags 2.9.4", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", + "paste", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "no_std_strings" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e" + +[[package]] +name = "nssa-core" +version = "0.1.0" +dependencies = [ + "chacha20", + "risc0-zkvm", + "serde", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_enum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + +[[package]] +name = "potential_utf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit 0.23.7", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "version_check", + "yansi", +] + +[[package]] +name = "programs" +version = "0.1.0" +dependencies = [ + "nssa-core", + "risc0-zkvm", + "serde", +] + +[[package]] +name = "proptest" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bb0be07becd10686a0bb407298fb425360a5c44a663774406340c59a22de4ce" +dependencies = [ + "bitflags 2.9.4", + "num-traits", + "rand 0.9.2", + "rand_chacha 0.9.0", + "rand_xorshift", + "unarray", +] + +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +dependencies = [ + "bytes", + "getrandom 0.3.3", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.3", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "reqwest" +version = "0.12.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "risc0-binfmt" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c8f97f81bcdead4101bca06469ecef481a2695cd04e7e877b49dea56a7f6f2a" +dependencies = [ + "anyhow", + "borsh", + "bytemuck", + "derive_more", + "elf", + "lazy_static", + "postcard", + "rand 0.9.2", + "risc0-zkp", + "risc0-zkvm-platform", + "ruint", + "semver", + "serde", + "tracing", +] + +[[package]] +name = "risc0-build" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bbb512d728e011d03ce0958ca7954624ee13a215bcafd859623b3c63b2a3f60" +dependencies = [ + "anyhow", + "cargo_metadata", + "derive_builder", + "dirs", + "docker-generate", + "hex", + "risc0-binfmt", + "risc0-zkos-v1compat", + "risc0-zkp", + "risc0-zkvm-platform", + "rzup", + "semver", + "serde", + "serde_json", + "stability", + "tempfile", +] + +[[package]] +name = "risc0-circuit-keccak" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f195f865ac1afdc21a172d7756fdcc21be18e13eb01d78d3d7f2b128fa881ba" +dependencies = [ + "anyhow", + "bytemuck", + "paste", + "risc0-binfmt", + "risc0-circuit-recursion", + "risc0-core", + "risc0-zkp", + "tracing", +] + +[[package]] +name = "risc0-circuit-recursion" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dca8f15c8abc0fd8c097aa7459879110334d191c63dd51d4c28881c4a497279e" +dependencies = [ + "anyhow", + "bytemuck", + "hex", + "metal", + "risc0-core", + "risc0-zkp", + "tracing", +] + +[[package]] +name = "risc0-circuit-rv32im" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1b0689f4a270a2f247b04397ebb431b8f64fe5170e98ee4f9d71bd04825205" +dependencies = [ + "anyhow", + "bit-vec", + "bytemuck", + "derive_more", + "paste", + "risc0-binfmt", + "risc0-core", + "risc0-zkp", + "serde", + "tracing", +] + +[[package]] +name = "risc0-core" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80f2723fedace48c6c5a505bd8f97ac4e1712bc4cb769083e10536d862b66987" +dependencies = [ + "bytemuck", + "rand_core 0.9.3", +] + +[[package]] +name = "risc0-groth16" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "724285dc79604abfb2d40feaefe3e335420a6b293511661f77d6af62f1f5fae9" +dependencies = [ + "anyhow", + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-groth16", + "ark-serialize", + "bytemuck", + "hex", + "num-bigint", + "num-traits", + "risc0-binfmt", + "risc0-zkp", + "serde", +] + +[[package]] +name = "risc0-zkos-v1compat" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "840c2228803557a8b7dc035a8f196516b6fd68c9dc6ac092f0c86241b5b1bafb" +dependencies = [ + "include_bytes_aligned", + "no_std_strings", + "risc0-zkvm-platform", +] + +[[package]] +name = "risc0-zkp" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb6bf356f469bb8744f72a07a37134c5812c1d55d6271bba80e87bdb7a58c8e" +dependencies = [ + "anyhow", + "blake2", + "borsh", + "bytemuck", + "cfg-if", + "digest", + "hex", + "hex-literal", + "metal", + "paste", + "rand_core 0.9.3", + "risc0-core", + "risc0-zkvm-platform", + "serde", + "sha2", + "stability", + "tracing", +] + +[[package]] +name = "risc0-zkvm" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fcce11648a9ff60b8e7af2f0ce7fbf8d25275ab6d414cc91b9da69ee75bc978" +dependencies = [ + "anyhow", + "bincode", + "bonsai-sdk", + "borsh", + "bytemuck", + "bytes", + "derive_more", + "hex", + "lazy-regex", + "prost", + "risc0-binfmt", + "risc0-build", + "risc0-circuit-keccak", + "risc0-circuit-recursion", + "risc0-circuit-rv32im", + "risc0-core", + "risc0-groth16", + "risc0-zkos-v1compat", + "risc0-zkp", + "risc0-zkvm-platform", + "rrs-lib", + "rzup", + "semver", + "serde", + "sha2", + "stability", + "tempfile", + "tracing", +] + +[[package]] +name = "risc0-zkvm-platform" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfaa10feba15828c788837ddde84b994393936d8f5715228627cfe8625122a40" +dependencies = [ + "bytemuck", + "cfg-if", + "getrandom 0.2.16", + "getrandom 0.3.3", + "libm", + "num_enum", + "paste", + "stability", +] + +[[package]] +name = "rrs-lib" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4382d3af3a4ebdae7f64ba6edd9114fff92c89808004c4943b393377a25d001" +dependencies = [ + "downcast-rs", + "paste", +] + +[[package]] +name = "rsa" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "ruint" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68df0380e5c9d20ce49534f292a36a7514ae21350726efe1865bdb1fa91d278" +dependencies = [ + "borsh", + "proptest", + "rand 0.8.5", + "rand 0.9.2", + "ruint-macro", + "serde_core", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "rzup" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d2aed296f203fa64bcb4b52069356dd86d6ec578593985b919b6995bee1f0ae" +dependencies = [ + "hex", + "rsa", + "semver", + "serde", + "serde_with", + "sha2", + "strum", + "tempfile", + "thiserror", + "toml", + "yaml-rust2", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6093cd8c01b25262b84927e0f7151692158fab02d961e04c979d3903eba7ecc5" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.11.4", + "schemars 0.9.0", + "schemars 1.0.4", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e6c180db0816026a61afa1cff5344fb7ebded7e4d3062772179f2501481c27" +dependencies = [ + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stability" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" +dependencies = [ + "quote", + "syn 2.0.106", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "time-macros" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap 2.11.4", + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.23.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" +dependencies = [ + "indexmap 2.11.4", + "toml_datetime 0.7.3", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags 2.9.4", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yaml-rust2" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2462ea039c445496d8793d052e13787f2b90e750b833afee748e601c17621ed9" +dependencies = [ + "arraydeque", + "encoding_rs", + "hashlink", +] + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] From bf25c92b308b5eb074947b44e72310e153804aec Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Tue, 28 Oct 2025 10:41:40 +0200 Subject: [PATCH 7/7] fix: suggestions fix --- Cargo.toml | 2 +- integration_tests/Cargo.toml | 2 +- .../proc_macro_test_attribute}/Cargo.toml | 0 .../proc_macro_test_attribute}/src/lib.rs | 2 +- integration_tests/src/test_suite_map.rs | 44 +++++++++---------- 5 files changed, 25 insertions(+), 25 deletions(-) rename {proc_macro_test_attribute => integration_tests/proc_macro_test_attribute}/Cargo.toml (100%) rename {proc_macro_test_attribute => integration_tests/proc_macro_test_attribute}/src/lib.rs (93%) diff --git a/Cargo.toml b/Cargo.toml index 6866046..e340ffb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ members = [ "sequencer_core", "common", "nssa", - "proc_macro_test_attribute", + "integration_tests/proc_macro_test_attribute", ] [workspace.dependencies] diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index 979c523..c10869a 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -17,7 +17,7 @@ borsh.workspace = true nssa-core = { path = "../nssa/core", features = ["host"] } -proc_macro_test_attribute = { path = "../proc_macro_test_attribute" } +proc_macro_test_attribute = { path = "./proc_macro_test_attribute" } [dependencies.clap] features = ["derive", "env"] diff --git a/proc_macro_test_attribute/Cargo.toml b/integration_tests/proc_macro_test_attribute/Cargo.toml similarity index 100% rename from proc_macro_test_attribute/Cargo.toml rename to integration_tests/proc_macro_test_attribute/Cargo.toml diff --git a/proc_macro_test_attribute/src/lib.rs b/integration_tests/proc_macro_test_attribute/src/lib.rs similarity index 93% rename from proc_macro_test_attribute/src/lib.rs rename to integration_tests/proc_macro_test_attribute/src/lib.rs index 59d2d0c..29852a0 100644 --- a/proc_macro_test_attribute/src/lib.rs +++ b/integration_tests/proc_macro_test_attribute/src/lib.rs @@ -3,7 +3,7 @@ extern crate proc_macro; use proc_macro::*; #[proc_macro_attribute] -pub fn test_suite_fn(_attr: TokenStream, item: TokenStream) -> TokenStream { +pub fn nssa_integration_test(_attr: TokenStream, item: TokenStream) -> TokenStream { let input = item.to_string(); let fn_keyword = "fn "; diff --git a/integration_tests/src/test_suite_map.rs b/integration_tests/src/test_suite_map.rs index 99a1371..65b2095 100644 --- a/integration_tests/src/test_suite_map.rs +++ b/integration_tests/src/test_suite_map.rs @@ -37,7 +37,7 @@ type TestFunction = fn(PathBuf) -> Pin>>; pub fn prepare_function_map() -> HashMap { let mut function_map: HashMap = HashMap::new(); - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_success() { info!("test_success"); let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { @@ -74,7 +74,7 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_success_move_to_another_account() { info!("test_success_move_to_another_account"); let command = Command::Account(AccountSubcommand::Register(RegisterSubcommand::Public {})); @@ -131,7 +131,7 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_failure() { info!("test_failure"); let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { @@ -170,7 +170,7 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_success_two_transactions() { info!("test_success_two_transactions"); let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { @@ -236,7 +236,7 @@ pub fn prepare_function_map() -> HashMap { info!("Second TX Success!"); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_get_account() { info!("test_get_account"); let wallet_config = fetch_config().await.unwrap(); @@ -259,7 +259,7 @@ pub fn prepare_function_map() -> HashMap { /// This test creates a new token using the token program. After creating the token, the test executes a /// token transfer to a new account. - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_success_token_program() { let wallet_config = fetch_config().await.unwrap(); @@ -409,7 +409,7 @@ pub fn prepare_function_map() -> HashMap { /// This test creates a new private token using the token program. After creating the token, the test executes a /// private token transfer to a new account. All accounts are owned except definition. - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_success_token_program_private_owned() { let wallet_config = fetch_config().await.unwrap(); @@ -557,7 +557,7 @@ pub fn prepare_function_map() -> HashMap { /// This test creates a new private token using the token program. After creating the token, the test executes a /// private token transfer to a new account. - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_success_token_program_private_claiming_path() { let wallet_config = fetch_config().await.unwrap(); @@ -693,7 +693,7 @@ pub fn prepare_function_map() -> HashMap { /// This test creates a new public token using the token program. After creating the token, the test executes a /// shielded token transfer to a new account. All accounts are owned except definition. - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_success_token_program_shielded_owned() { let wallet_config = fetch_config().await.unwrap(); @@ -820,7 +820,7 @@ pub fn prepare_function_map() -> HashMap { /// This test creates a new private token using the token program. After creating the token, the test executes a /// deshielded token transfer to a new account. All accounts are owned except definition. - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_success_token_program_deshielded_owned() { let wallet_config = fetch_config().await.unwrap(); @@ -956,7 +956,7 @@ pub fn prepare_function_map() -> HashMap { assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_success_private_transfer_to_another_owned_account() { info!("test_success_private_transfer_to_another_owned_account"); let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); @@ -992,7 +992,7 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_success_private_transfer_to_another_foreign_account() { info!("test_success_private_transfer_to_another_foreign_account"); let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); @@ -1039,7 +1039,7 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_success_private_transfer_to_another_owned_account_claiming_path() { info!("test_success_private_transfer_to_another_owned_account_claiming_path"); let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); @@ -1108,7 +1108,7 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_success_private_transfer_to_another_owned_account_cont_run_path() { info!("test_success_private_transfer_to_another_owned_account_cont_run_path"); let continious_run_handle = tokio::spawn(wallet::execute_continious_run()); @@ -1179,7 +1179,7 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_success_deshielded_transfer_to_another_account() { info!("test_success_deshielded_transfer_to_another_account"); let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); @@ -1225,7 +1225,7 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_success_shielded_transfer_to_another_owned_account() { info!("test_success_shielded_transfer_to_another_owned_account"); let from: Address = ACC_SENDER.parse().unwrap(); @@ -1266,7 +1266,7 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_success_shielded_transfer_to_another_foreign_account() { info!("test_success_shielded_transfer_to_another_foreign_account"); let to_npk = NullifierPublicKey([42; 32]); @@ -1312,7 +1312,7 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_pinata() { info!("test_pinata"); let pinata_addr = "cafe".repeat(16); @@ -1360,7 +1360,7 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_program_deployment() { info!("test program deployment"); let bytecode = NSSA_PROGRAM_FOR_TEST_DATA_CHANGER.to_vec(); @@ -1407,7 +1407,7 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_authenticated_transfer_initialize_function() { info!("test initialize account for authenticated transfer"); let command = Command::AuthenticatedTransferInitializePublicAccount {}; @@ -1439,7 +1439,7 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_pinata_private_receiver() { info!("test_pinata_private_receiver"); let pinata_addr = "cafe".repeat(16); @@ -1503,7 +1503,7 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } - #[test_suite_fn] + #[nssa_integration_test] pub async fn test_pinata_private_receiver_new_account() { info!("test_pinata_private_receiver"); let pinata_addr = "cafe".repeat(16);