diff --git a/Cargo.lock b/Cargo.lock index 3d7d2921..27c1ae8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3655,7 +3655,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.3", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -7465,7 +7465,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.6.3", + "socket2 0.5.10", "thiserror 2.0.18", "tokio", "tracing", @@ -7502,9 +7502,9 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.3", + "socket2 0.5.10", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -8476,7 +8476,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs 0.26.11", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] diff --git a/artifacts/program_methods/amm.bin b/artifacts/program_methods/amm.bin index 2635cab1..685e01bb 100644 Binary files a/artifacts/program_methods/amm.bin and b/artifacts/program_methods/amm.bin differ diff --git a/artifacts/program_methods/associated_token_account.bin b/artifacts/program_methods/associated_token_account.bin index 155f2ba8..d67cd89d 100644 Binary files a/artifacts/program_methods/associated_token_account.bin and b/artifacts/program_methods/associated_token_account.bin differ diff --git a/artifacts/program_methods/authenticated_transfer.bin b/artifacts/program_methods/authenticated_transfer.bin index 812a5ced..8a335adf 100644 Binary files a/artifacts/program_methods/authenticated_transfer.bin and b/artifacts/program_methods/authenticated_transfer.bin differ diff --git a/artifacts/program_methods/clock.bin b/artifacts/program_methods/clock.bin index 62e16cb9..f24484ee 100644 Binary files a/artifacts/program_methods/clock.bin and b/artifacts/program_methods/clock.bin differ diff --git a/artifacts/program_methods/faucet.bin b/artifacts/program_methods/faucet.bin index 9b1fbbe4..8f091358 100644 Binary files a/artifacts/program_methods/faucet.bin and b/artifacts/program_methods/faucet.bin differ diff --git a/artifacts/program_methods/pinata.bin b/artifacts/program_methods/pinata.bin index 6c8849e6..2a2ec7b5 100644 Binary files a/artifacts/program_methods/pinata.bin and b/artifacts/program_methods/pinata.bin differ diff --git a/artifacts/program_methods/pinata_token.bin b/artifacts/program_methods/pinata_token.bin index baf619e3..94f2598d 100644 Binary files a/artifacts/program_methods/pinata_token.bin and b/artifacts/program_methods/pinata_token.bin differ diff --git a/artifacts/program_methods/privacy_preserving_circuit.bin b/artifacts/program_methods/privacy_preserving_circuit.bin index 16c5a34b..5b52b624 100644 Binary files a/artifacts/program_methods/privacy_preserving_circuit.bin and b/artifacts/program_methods/privacy_preserving_circuit.bin differ diff --git a/artifacts/program_methods/token.bin b/artifacts/program_methods/token.bin index d7e11257..6a904824 100644 Binary files a/artifacts/program_methods/token.bin and b/artifacts/program_methods/token.bin differ diff --git a/artifacts/program_methods/vault.bin b/artifacts/program_methods/vault.bin index b2cdea20..4c5d875b 100644 Binary files a/artifacts/program_methods/vault.bin and b/artifacts/program_methods/vault.bin differ diff --git a/artifacts/test_program_methods/auth_asserting_noop.bin b/artifacts/test_program_methods/auth_asserting_noop.bin index 7116dbbb..d0b8b80d 100644 Binary files a/artifacts/test_program_methods/auth_asserting_noop.bin and b/artifacts/test_program_methods/auth_asserting_noop.bin differ diff --git a/artifacts/test_program_methods/auth_transfer_proxy.bin b/artifacts/test_program_methods/auth_transfer_proxy.bin index 3dc5a5ec..7d728367 100644 Binary files a/artifacts/test_program_methods/auth_transfer_proxy.bin and b/artifacts/test_program_methods/auth_transfer_proxy.bin differ diff --git a/artifacts/test_program_methods/burner.bin b/artifacts/test_program_methods/burner.bin index 5f8209b0..9228fdc6 100644 Binary files a/artifacts/test_program_methods/burner.bin and b/artifacts/test_program_methods/burner.bin differ diff --git a/artifacts/test_program_methods/chain_caller.bin b/artifacts/test_program_methods/chain_caller.bin index e2164be6..1546eb58 100644 Binary files a/artifacts/test_program_methods/chain_caller.bin and b/artifacts/test_program_methods/chain_caller.bin differ diff --git a/artifacts/test_program_methods/changer_claimer.bin b/artifacts/test_program_methods/changer_claimer.bin index c99ca2c0..a98fa099 100644 Binary files a/artifacts/test_program_methods/changer_claimer.bin and b/artifacts/test_program_methods/changer_claimer.bin differ diff --git a/artifacts/test_program_methods/claimer.bin b/artifacts/test_program_methods/claimer.bin index dc44c14f..42a8ccff 100644 Binary files a/artifacts/test_program_methods/claimer.bin and b/artifacts/test_program_methods/claimer.bin differ diff --git a/artifacts/test_program_methods/clock_chain_caller.bin b/artifacts/test_program_methods/clock_chain_caller.bin index 19a43bbc..0407dc83 100644 Binary files a/artifacts/test_program_methods/clock_chain_caller.bin and b/artifacts/test_program_methods/clock_chain_caller.bin differ diff --git a/artifacts/test_program_methods/data_changer.bin b/artifacts/test_program_methods/data_changer.bin index 98d3ea85..1b1e4478 100644 Binary files a/artifacts/test_program_methods/data_changer.bin and b/artifacts/test_program_methods/data_changer.bin differ diff --git a/artifacts/test_program_methods/extra_output.bin b/artifacts/test_program_methods/extra_output.bin index fdd80cbd..12ca3db5 100644 Binary files a/artifacts/test_program_methods/extra_output.bin and b/artifacts/test_program_methods/extra_output.bin differ diff --git a/artifacts/test_program_methods/faucet_chain_caller.bin b/artifacts/test_program_methods/faucet_chain_caller.bin index 656e7ab5..6df3f51c 100644 Binary files a/artifacts/test_program_methods/faucet_chain_caller.bin and b/artifacts/test_program_methods/faucet_chain_caller.bin differ diff --git a/artifacts/test_program_methods/flash_swap_callback.bin b/artifacts/test_program_methods/flash_swap_callback.bin index b4e35f49..24777072 100644 Binary files a/artifacts/test_program_methods/flash_swap_callback.bin and b/artifacts/test_program_methods/flash_swap_callback.bin differ diff --git a/artifacts/test_program_methods/flash_swap_initiator.bin b/artifacts/test_program_methods/flash_swap_initiator.bin index ae9d945f..5c42b8ee 100644 Binary files a/artifacts/test_program_methods/flash_swap_initiator.bin and b/artifacts/test_program_methods/flash_swap_initiator.bin differ diff --git a/artifacts/test_program_methods/malicious_authorization_changer.bin b/artifacts/test_program_methods/malicious_authorization_changer.bin index 828813e3..35417608 100644 Binary files a/artifacts/test_program_methods/malicious_authorization_changer.bin and b/artifacts/test_program_methods/malicious_authorization_changer.bin differ diff --git a/artifacts/test_program_methods/malicious_caller_program_id.bin b/artifacts/test_program_methods/malicious_caller_program_id.bin index bd996ff8..c3be7ddb 100644 Binary files a/artifacts/test_program_methods/malicious_caller_program_id.bin and b/artifacts/test_program_methods/malicious_caller_program_id.bin differ diff --git a/artifacts/test_program_methods/malicious_injector.bin b/artifacts/test_program_methods/malicious_injector.bin index ae65ed93..398c50e3 100644 Binary files a/artifacts/test_program_methods/malicious_injector.bin and b/artifacts/test_program_methods/malicious_injector.bin differ diff --git a/artifacts/test_program_methods/malicious_launderer.bin b/artifacts/test_program_methods/malicious_launderer.bin index 50a20251..ed3260da 100644 Binary files a/artifacts/test_program_methods/malicious_launderer.bin and b/artifacts/test_program_methods/malicious_launderer.bin differ diff --git a/artifacts/test_program_methods/malicious_self_program_id.bin b/artifacts/test_program_methods/malicious_self_program_id.bin index 3cb564f2..68fb156c 100644 Binary files a/artifacts/test_program_methods/malicious_self_program_id.bin and b/artifacts/test_program_methods/malicious_self_program_id.bin differ diff --git a/artifacts/test_program_methods/minter.bin b/artifacts/test_program_methods/minter.bin index d90292f8..df99e3a8 100644 Binary files a/artifacts/test_program_methods/minter.bin and b/artifacts/test_program_methods/minter.bin differ diff --git a/artifacts/test_program_methods/missing_output.bin b/artifacts/test_program_methods/missing_output.bin index dfca513a..7bd623ab 100644 Binary files a/artifacts/test_program_methods/missing_output.bin and b/artifacts/test_program_methods/missing_output.bin differ diff --git a/artifacts/test_program_methods/modified_transfer.bin b/artifacts/test_program_methods/modified_transfer.bin index d4698fdf..9ff09816 100644 Binary files a/artifacts/test_program_methods/modified_transfer.bin and b/artifacts/test_program_methods/modified_transfer.bin differ diff --git a/artifacts/test_program_methods/nonce_changer.bin b/artifacts/test_program_methods/nonce_changer.bin index df524beb..a2e180f8 100644 Binary files a/artifacts/test_program_methods/nonce_changer.bin and b/artifacts/test_program_methods/nonce_changer.bin differ diff --git a/artifacts/test_program_methods/noop.bin b/artifacts/test_program_methods/noop.bin index be0f301b..62644e02 100644 Binary files a/artifacts/test_program_methods/noop.bin and b/artifacts/test_program_methods/noop.bin differ diff --git a/artifacts/test_program_methods/pda_claimer.bin b/artifacts/test_program_methods/pda_claimer.bin index 81a5de3e..405577be 100644 Binary files a/artifacts/test_program_methods/pda_claimer.bin and b/artifacts/test_program_methods/pda_claimer.bin differ diff --git a/artifacts/test_program_methods/pda_spend_proxy.bin b/artifacts/test_program_methods/pda_spend_proxy.bin index 9366e66a..9b9c711d 100644 Binary files a/artifacts/test_program_methods/pda_spend_proxy.bin and b/artifacts/test_program_methods/pda_spend_proxy.bin differ diff --git a/artifacts/test_program_methods/pinata_cooldown.bin b/artifacts/test_program_methods/pinata_cooldown.bin index b65ce430..11f1d9f5 100644 Binary files a/artifacts/test_program_methods/pinata_cooldown.bin and b/artifacts/test_program_methods/pinata_cooldown.bin differ diff --git a/artifacts/test_program_methods/private_pda_delegator.bin b/artifacts/test_program_methods/private_pda_delegator.bin index 8e1857f8..ad5a11d9 100644 Binary files a/artifacts/test_program_methods/private_pda_delegator.bin and b/artifacts/test_program_methods/private_pda_delegator.bin differ diff --git a/artifacts/test_program_methods/program_owner_changer.bin b/artifacts/test_program_methods/program_owner_changer.bin index 0ea6687a..d87c5a42 100644 Binary files a/artifacts/test_program_methods/program_owner_changer.bin and b/artifacts/test_program_methods/program_owner_changer.bin differ diff --git a/artifacts/test_program_methods/simple_balance_transfer.bin b/artifacts/test_program_methods/simple_balance_transfer.bin index 183b8ee2..f64b060a 100644 Binary files a/artifacts/test_program_methods/simple_balance_transfer.bin and b/artifacts/test_program_methods/simple_balance_transfer.bin differ diff --git a/artifacts/test_program_methods/time_locked_transfer.bin b/artifacts/test_program_methods/time_locked_transfer.bin index 02d776f2..87530acb 100644 Binary files a/artifacts/test_program_methods/time_locked_transfer.bin and b/artifacts/test_program_methods/time_locked_transfer.bin differ diff --git a/artifacts/test_program_methods/two_pda_claimer.bin b/artifacts/test_program_methods/two_pda_claimer.bin index 5598072f..e469bfc6 100644 Binary files a/artifacts/test_program_methods/two_pda_claimer.bin and b/artifacts/test_program_methods/two_pda_claimer.bin differ diff --git a/artifacts/test_program_methods/validity_window.bin b/artifacts/test_program_methods/validity_window.bin index 0485135f..53872234 100644 Binary files a/artifacts/test_program_methods/validity_window.bin and b/artifacts/test_program_methods/validity_window.bin differ diff --git a/artifacts/test_program_methods/validity_window_chain_caller.bin b/artifacts/test_program_methods/validity_window_chain_caller.bin index 86d71dfb..2264d04f 100644 Binary files a/artifacts/test_program_methods/validity_window_chain_caller.bin and b/artifacts/test_program_methods/validity_window_chain_caller.bin differ diff --git a/examples/program_deployment/README.md b/examples/program_deployment/README.md index 61e530e3..11952c35 100644 --- a/examples/program_deployment/README.md +++ b/examples/program_deployment/README.md @@ -332,7 +332,7 @@ Unlike the public version, `run_hello_world_private.rs` must: Luckily all that complexity is hidden behind the `wallet_core.send_privacy_preserving_tx` function: ```rust - let accounts = vec![PrivacyPreservingAccount::PrivateOwned(account_id)]; + let accounts = vec![AccountIdentity::PrivateOwned(account_id)]; // Construct and submit the privacy-preserving transaction wallet_core diff --git a/examples/program_deployment/src/bin/run_hello_world_private.rs b/examples/program_deployment/src/bin/run_hello_world_private.rs index 27ac2079..725019f1 100644 --- a/examples/program_deployment/src/bin/run_hello_world_private.rs +++ b/examples/program_deployment/src/bin/run_hello_world_private.rs @@ -1,5 +1,5 @@ use nssa::{AccountId, program::Program}; -use wallet::{PrivacyPreservingAccount, WalletCore}; +use wallet::{AccountIdentity, WalletCore}; // Before running this example, compile the `hello_world.rs` guest program with: // @@ -44,7 +44,7 @@ async fn main() { // Define the desired greeting in ASCII let greeting: Vec = vec![72, 111, 108, 97, 32, 109, 117, 110, 100, 111, 33]; - let accounts = vec![PrivacyPreservingAccount::PrivateOwned(account_id)]; + let accounts = vec![AccountIdentity::PrivateOwned(account_id)]; // Construct and submit the privacy-preserving transaction wallet_core diff --git a/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs b/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs index 4fac3eec..d68e99dc 100644 --- a/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs +++ b/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs @@ -4,7 +4,7 @@ use nssa::{ AccountId, ProgramId, privacy_preserving_transaction::circuit::ProgramWithDependencies, program::Program, }; -use wallet::{PrivacyPreservingAccount, WalletCore}; +use wallet::{AccountIdentity, WalletCore}; // Before running this example, compile the `simple_tail_call.rs` guest program with: // @@ -51,7 +51,7 @@ async fn main() { std::iter::once((hello_world.id(), hello_world)).collect(); let program_with_dependencies = ProgramWithDependencies::new(simple_tail_call, dependencies); - let accounts = vec![PrivacyPreservingAccount::PrivateOwned(account_id)]; + let accounts = vec![AccountIdentity::PrivateOwned(account_id)]; // Construct and submit the privacy-preserving transaction let instruction = (); diff --git a/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs b/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs index a1c2517e..e6f667a6 100644 --- a/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs +++ b/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs @@ -2,7 +2,7 @@ use clap::{Parser, Subcommand}; use common::transaction::NSSATransaction; use nssa::{PublicTransaction, program::Program, public_transaction}; use sequencer_service_rpc::RpcClient as _; -use wallet::{PrivacyPreservingAccount, WalletCore}; +use wallet::{AccountIdentity, WalletCore}; // Before running this example, compile the `hello_world_with_move_function.rs` guest program with: // @@ -99,7 +99,7 @@ async fn main() { } => { let instruction: Instruction = (WRITE_FUNCTION_ID, greeting.into_bytes()); let account_id = account_id.parse().unwrap(); - let accounts = vec![PrivacyPreservingAccount::PrivateOwned(account_id)]; + let accounts = vec![AccountIdentity::PrivateOwned(account_id)]; wallet_core .send_privacy_preserving_tx( @@ -138,8 +138,8 @@ async fn main() { let to = to.parse().unwrap(); let accounts = vec![ - PrivacyPreservingAccount::Public(from), - PrivacyPreservingAccount::PrivateOwned(to), + AccountIdentity::Public(from), + AccountIdentity::PrivateOwned(to), ]; wallet_core diff --git a/integration_tests/tests/private_pda.rs b/integration_tests/tests/private_pda.rs index 84bfcb2f..b0e3336e 100644 --- a/integration_tests/tests/private_pda.rs +++ b/integration_tests/tests/private_pda.rs @@ -32,7 +32,7 @@ use nssa_core::{ use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::{ - PrivacyPreservingAccount, WalletCore, + AccountIdentity, WalletCore, cli::{Command, account::AccountSubcommand}, }; @@ -129,8 +129,8 @@ async fn spend_private_pda( wallet .send_privacy_preserving_tx( vec![ - PrivacyPreservingAccount::PrivatePdaOwned(pda_account_id), - PrivacyPreservingAccount::PrivateForeign { + AccountIdentity::PrivatePdaOwned(pda_account_id), + AccountIdentity::PrivateForeign { npk: recipient_npk, vpk: recipient_vpk, identifier: 0, diff --git a/nssa/core/src/commitment.rs b/nssa/core/src/commitment.rs index 73ccd703..7c81c12c 100644 --- a/nssa/core/src/commitment.rs +++ b/nssa/core/src/commitment.rs @@ -7,8 +7,9 @@ use crate::account::{Account, AccountId}; /// A commitment to all zero data. /// ```python /// from hashlib import sha256 +/// prefix = b"/LEE/v0.3/Commitment/\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" /// hasher = sha256() -/// hasher.update(bytes([0] * 32 + [0] * 32 + [0] * 16 + [0] * 16 + list(sha256().digest()))) +/// hasher.update(prefix + bytes([0] * 32 + [0] * 32 + [0] * 16 + [0] * 16 + list(sha256().digest()))) /// DUMMY_COMMITMENT = hasher.digest() /// ``` pub const DUMMY_COMMITMENT: Commitment = Commitment([ diff --git a/nssa/src/error.rs b/nssa/src/error.rs index 65079d25..31f78461 100644 --- a/nssa/src/error.rs +++ b/nssa/src/error.rs @@ -96,6 +96,9 @@ pub enum InvalidProgramBehaviorError { #[error("Unauthorized account marked as authorized")] InvalidAccountAuthorization { account_id: AccountId }, + #[error("Authorized account marked as not authorized")] + AuthorizedAccountMarkedAsNotAuthorized { account_id: AccountId }, + #[error("Program ID mismatch: expected {expected:?}, actual {actual:?}")] MismatchedProgramId { expected: ProgramId, diff --git a/nssa/src/validated_state_diff.rs b/nssa/src/validated_state_diff.rs index 87bde206..bdee3452 100644 --- a/nssa/src/validated_state_diff.rs +++ b/nssa/src/validated_state_diff.rs @@ -173,12 +173,18 @@ impl ValidatedStateDiff { ); // Check that the program output pre_states marked as authorized are indeed - // authorized. + // authorized, and vice-versa. let is_indeed_authorized = is_authorized(&account_id); ensure!( !pre.is_authorized || is_indeed_authorized, InvalidProgramBehaviorError::InvalidAccountAuthorization { account_id } ); + ensure!( + pre.is_authorized || !is_indeed_authorized, + InvalidProgramBehaviorError::AuthorizedAccountMarkedAsNotAuthorized { + account_id + } + ); } // Verify that the program output's self_program_id matches the expected program ID. @@ -269,11 +275,20 @@ impl ValidatedStateDiff { // the loop above already gates program_output's `is_authorized` via the // `!pre.is_authorized || is_indeed_authorized` check, while `chained_call. // pre_states` is caller-controlled and can be forged (audit-issue 91). - let authorized_accounts: HashSet<_> = program_output - .pre_states - .iter() - .filter(|pre| pre.is_authorized) - .map(|pre| pre.account_id) + // + // Union with the caller's authorized set so that authorization is monotonically + // growing: once an account is authorized at any point in the chain it remains + // authorized for all subsequent calls. + let authorized_accounts: HashSet<_> = caller_data + .authorized_accounts + .into_iter() + .chain( + program_output + .pre_states + .iter() + .filter(|pre| pre.is_authorized) + .map(|pre| pre.account_id), + ) .collect(); for new_call in program_output.chained_calls.into_iter().rev() { chained_calls.push_front(( @@ -341,7 +356,13 @@ impl ValidatedStateDiff { // Check there are no duplicate nullifiers in the new_nullifiers list ensure!( - n_unique(&message.new_nullifiers) == message.new_nullifiers.len(), + n_unique( + &message + .new_nullifiers + .iter() + .map(|(n, _)| n) + .collect::>() + ) == message.new_nullifiers.len(), NssaError::InvalidInput("Duplicate nullifiers found in message".into()) ); diff --git a/program_methods/guest/src/bin/privacy_preserving_circuit/output.rs b/program_methods/guest/src/bin/privacy_preserving_circuit/output.rs index 6e302401..eda9bacd 100644 --- a/program_methods/guest/src/bin/privacy_preserving_circuit/output.rs +++ b/program_methods/guest/src/bin/privacy_preserving_circuit/output.rs @@ -62,7 +62,7 @@ pub fn compute_circuit_output( Nullifier::for_account_initialization(&account_id), DUMMY_COMMITMENT_HASH, ); - let new_nonce = pre_state.account.nonce.private_account_nonce_increment(nsk); + let new_nonce = Nonce::private_account_nonce_init(&account_id); emit_private_output( &mut output, diff --git a/test_fixtures/src/setup.rs b/test_fixtures/src/setup.rs index c43590d0..5d7377b1 100644 --- a/test_fixtures/src/setup.rs +++ b/test_fixtures/src/setup.rs @@ -9,9 +9,7 @@ use sequencer_service::{GenesisAction, SequencerHandle}; use sequencer_service_rpc::RpcClient as _; use tempfile::TempDir; use testcontainers::compose::DockerCompose; -use wallet::{ - AccDecodeData::Decode, PrivacyPreservingAccount, WalletCore, config::WalletConfigOverrides, -}; +use wallet::{AccDecodeData::Decode, AccountIdentity, WalletCore, config::WalletConfigOverrides}; use crate::{ BEDROCK_SERVICE_PORT, BEDROCK_SERVICE_WITH_OPEN_PORT, @@ -293,8 +291,8 @@ async fn claim_funds_from_vault_to_private( let (tx_hash, mut secrets) = wallet .send_privacy_preserving_tx( vec![ - PrivacyPreservingAccount::PrivateOwned(owner_id), - PrivacyPreservingAccount::Public(owner_vault_id), + AccountIdentity::PrivateOwned(owner_id), + AccountIdentity::Public(owner_vault_id), ], instruction_data, &program_with_dependencies, diff --git a/wallet/src/privacy_preserving_tx.rs b/wallet/src/account_manager.rs similarity index 91% rename from wallet/src/privacy_preserving_tx.rs rename to wallet/src/account_manager.rs index 865fcdce..5caf2b22 100644 --- a/wallet/src/privacy_preserving_tx.rs +++ b/wallet/src/account_manager.rs @@ -11,8 +11,10 @@ use nssa_core::{ use crate::{ExecutionFailureKind, WalletCore}; #[derive(Clone)] -pub enum PrivacyPreservingAccount { +pub enum AccountIdentity { Public(AccountId), + /// A public account without signing. Would not try to sign, even if account is owned. + PublicNoSign(AccountId), PrivateOwned(AccountId), PrivateForeign { npk: NullifierPublicKey, @@ -50,10 +52,12 @@ pub enum PrivacyPreservingAccount { }, } -impl PrivacyPreservingAccount { +impl AccountIdentity { #[must_use] + /// Note: `PublicNoSign` still counts as public, the variant just suppresses the signing-key + /// lookup. pub const fn is_public(&self) -> bool { - matches!(&self, Self::Public(_)) + matches!(&self, Self::Public(_) | Self::PublicNoSign(_)) } #[must_use] @@ -92,13 +96,13 @@ pub struct AccountManager { impl AccountManager { pub async fn new( wallet: &WalletCore, - accounts: Vec, + accounts: Vec, ) -> Result { let mut states = Vec::with_capacity(accounts.len()); for account in accounts { let state = match account { - PrivacyPreservingAccount::Public(account_id) => { + AccountIdentity::Public(account_id) => { let acc = wallet .get_account_public(account_id) .await @@ -109,12 +113,23 @@ impl AccountManager { State::Public { account, sk } } - PrivacyPreservingAccount::PrivateOwned(account_id) => { + AccountIdentity::PublicNoSign(account_id) => { + let acc = wallet + .get_account_public(account_id) + .await + .map_err(ExecutionFailureKind::SequencerError)?; + + let sk = None; + let account = AccountWithMetadata::new(acc.clone(), sk.is_some(), account_id); + + State::Public { account, sk } + } + AccountIdentity::PrivateOwned(account_id) => { let pre = private_key_tree_acc_preparation(wallet, account_id, false).await?; State::Private(pre) } - PrivacyPreservingAccount::PrivateForeign { + AccountIdentity::PrivateForeign { npk, vpk, identifier, @@ -138,11 +153,11 @@ impl AccountManager { State::Private(pre) } - PrivacyPreservingAccount::PrivatePdaOwned(account_id) => { + AccountIdentity::PrivatePdaOwned(account_id) => { let pre = private_key_tree_acc_preparation(wallet, account_id, true).await?; State::Private(pre) } - PrivacyPreservingAccount::PrivatePdaForeign { + AccountIdentity::PrivatePdaForeign { account_id, npk, vpk, @@ -166,7 +181,7 @@ impl AccountManager { }; State::Private(pre) } - PrivacyPreservingAccount::PrivateShared { + AccountIdentity::PrivateShared { nsk, npk, vpk, @@ -180,7 +195,7 @@ impl AccountManager { State::Private(pre) } - PrivacyPreservingAccount::PrivatePdaShared { + AccountIdentity::PrivatePdaShared { account_id, nsk, npk, @@ -412,7 +427,7 @@ mod tests { #[test] fn private_shared_is_private() { - let acc = PrivacyPreservingAccount::PrivateShared { + let acc = AccountIdentity::PrivateShared { nsk: [0; 32], npk: NullifierPublicKey([1; 32]), vpk: ViewingPublicKey::from_scalar([2; 32]), diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index ccca5f66..85c43806 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -9,6 +9,7 @@ use std::path::PathBuf; +pub use account_manager::AccountIdentity; use anyhow::{Context as _, Result}; use bip39::Mnemonic; use common::{HashType, transaction::NSSATransaction}; @@ -24,7 +25,6 @@ use nssa::{ use nssa_core::{ Commitment, MembershipProof, SharedSecretKey, account::Nonce, program::InstructionData, }; -pub use privacy_preserving_tx::PrivacyPreservingAccount; use sequencer_service_rpc::{RpcClient as _, SequencerClient, SequencerClientBuilder}; use storage::Storage; use tokio::io::AsyncWriteExt as _; @@ -37,11 +37,11 @@ use crate::{ }; pub mod account; +mod account_manager; pub mod cli; pub mod config; pub mod helperfunctions; pub mod poller; -mod privacy_preserving_tx; pub mod program_facades; pub mod signing; pub mod storage; @@ -273,13 +273,10 @@ impl WalletCore { self.storage.key_chain_mut().set_sealing_secret_key(key); } - /// Resolve an `AccountId` to the appropriate `PrivacyPreservingAccount` variant. + /// Resolve an `AccountId` to the appropriate `AccountIdentity` variant. /// Checks the key tree first, then shared private accounts. #[must_use] - pub fn resolve_private_account( - &self, - account_id: nssa::AccountId, - ) -> Option { + pub fn resolve_private_account(&self, account_id: nssa::AccountId) -> Option { // Check key tree first if self .storage @@ -287,7 +284,7 @@ impl WalletCore { .private_account(account_id) .is_some() { - return Some(PrivacyPreservingAccount::PrivateOwned(account_id)); + return Some(AccountIdentity::PrivateOwned(account_id)); } // Check shared private accounts @@ -302,7 +299,7 @@ impl WalletCore { if let (Some(pda_seed), Some(program_id)) = (entry.pda_seed, entry.authority_program_id) { let keys = holder.derive_keys_for_pda(&program_id, &pda_seed); - Some(PrivacyPreservingAccount::PrivatePdaShared { + Some(AccountIdentity::PrivatePdaShared { account_id, nsk: keys.nullifier_secret_key, npk: keys.generate_nullifier_public_key(), @@ -319,7 +316,7 @@ impl WalletCore { result }; let keys = holder.derive_keys_for_shared_account(&derivation_seed); - Some(PrivacyPreservingAccount::PrivateShared { + Some(AccountIdentity::PrivateShared { nsk: keys.nullifier_secret_key, npk: keys.generate_nullifier_public_key(), vpk: keys.generate_viewing_public_key(), @@ -544,7 +541,7 @@ impl WalletCore { pub async fn send_privacy_preserving_tx( &self, - accounts: Vec, + accounts: Vec, instruction_data: InstructionData, program: &ProgramWithDependencies, ) -> Result<(HashType, Vec), ExecutionFailureKind> { @@ -556,12 +553,12 @@ impl WalletCore { pub async fn send_privacy_preserving_tx_with_pre_check( &self, - accounts: Vec, + accounts: Vec, instruction_data: InstructionData, program: &ProgramWithDependencies, tx_pre_check: impl FnOnce(&[&Account]) -> Result<(), ExecutionFailureKind>, ) -> Result<(HashType, Vec), ExecutionFailureKind> { - let acc_manager = privacy_preserving_tx::AccountManager::new(self, accounts).await?; + let acc_manager = account_manager::AccountManager::new(self, accounts).await?; let pre_states = acc_manager.pre_states(); tx_pre_check( @@ -613,6 +610,65 @@ impl WalletCore { )) } + pub async fn send_pub_tx( + &self, + accounts: Vec, + instruction_data: InstructionData, + program: &ProgramWithDependencies, + ) -> Result { + self.send_pub_tx_with_pre_check(accounts, instruction_data, program, |_| Ok(())) + .await + } + + pub async fn send_pub_tx_with_pre_check( + &self, + accounts: Vec, + instruction_data: InstructionData, + program: &ProgramWithDependencies, + tx_pre_check: impl FnOnce(&[&Account]) -> Result<(), ExecutionFailureKind>, + ) -> Result { + // Public transaction, all accounts must be public + if accounts.iter().any(AccountIdentity::is_private) { + return Err(ExecutionFailureKind::TransactionBuildError( + nssa::error::NssaError::InvalidInput( + "Private accounts are not allowed in public transactions".to_owned(), + ), + )); + } + + let acc_manager = account_manager::AccountManager::new(self, accounts).await?; + + let pre_states = acc_manager.pre_states(); + tx_pre_check( + &pre_states + .iter() + .map(|pre| &pre.account) + .collect::>(), + )?; + + let account_ids = acc_manager.public_account_ids(); + let program_id = program.program.id(); + let nonces = acc_manager.public_account_nonces(); + let private_keys = acc_manager.public_account_auth(); + + let message = nssa::public_transaction::Message::new_preserialized( + program_id, + account_ids, + nonces, + instruction_data, + ); + + let witness_set = + nssa::public_transaction::WitnessSet::for_message(&message, &private_keys); + + let tx = nssa::public_transaction::PublicTransaction::new(message, witness_set); + + Ok(self + .sequencer_client + .send_transaction(NSSATransaction::Public(tx)) + .await?) + } + pub async fn sync_to_latest_block(&mut self) -> Result { let latest_block_id = self.sequencer_client.get_last_block_id().await?; println!("Latest block is {latest_block_id}"); diff --git a/wallet/src/program_facades/amm.rs b/wallet/src/program_facades/amm.rs index 2ac2ab79..b84cb5d0 100644 --- a/wallet/src/program_facades/amm.rs +++ b/wallet/src/program_facades/amm.rs @@ -1,10 +1,9 @@ use amm_core::{compute_liquidity_token_pda, compute_pool_pda, compute_vault_pda}; -use common::{HashType, transaction::NSSATransaction}; +use common::HashType; use nssa::{AccountId, program::Program}; -use sequencer_service_rpc::RpcClient as _; use token_core::TokenHolding; -use crate::{ExecutionFailureKind, WalletCore}; +use crate::{AccountIdentity, ExecutionFailureKind, WalletCore}; pub struct Amm<'wallet>(pub &'wallet WalletCore); impl Amm<'_> { @@ -18,12 +17,6 @@ impl Amm<'_> { ) -> Result { let program = Program::amm(); let amm_program_id = Program::amm().id(); - let instruction = amm_core::Instruction::NewDefinition { - token_a_amount: balance_a, - token_b_amount: balance_b, - amm_program_id, - }; - let user_a_acc = self .0 .get_account_public(user_holding_a) @@ -47,78 +40,29 @@ impl Amm<'_> { let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id); let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id); let pool_lp = compute_liquidity_token_pda(amm_program_id, amm_pool); + let instruction = amm_core::Instruction::NewDefinition { + token_a_amount: balance_a, + token_b_amount: balance_b, + amm_program_id, + }; + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); - let account_ids = vec![ - amm_pool, - vault_holding_a, - vault_holding_b, - pool_lp, - user_holding_a, - user_holding_b, - user_holding_lp, - ]; - - let mut nonces = self - .0 - .get_accounts_nonces(vec![user_holding_a, user_holding_b]) + self.0 + .send_pub_tx( + vec![ + AccountIdentity::PublicNoSign(amm_pool), + AccountIdentity::PublicNoSign(vault_holding_a), + AccountIdentity::PublicNoSign(vault_holding_b), + AccountIdentity::PublicNoSign(pool_lp), + AccountIdentity::Public(user_holding_a), + AccountIdentity::Public(user_holding_b), + AccountIdentity::Public(user_holding_lp), + ], + instruction_data, + &program.into(), + ) .await - .map_err(ExecutionFailureKind::SequencerError)?; - - let mut private_keys = Vec::new(); - - let signing_key_a = self - .0 - .storage - .key_chain() - .pub_account_signing_key(user_holding_a) - .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - private_keys.push(signing_key_a); - - let signing_key_b = self - .0 - .storage - .key_chain() - .pub_account_signing_key(user_holding_b) - .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - private_keys.push(signing_key_b); - - if let Some(signing_key_lp) = self - .0 - .storage - .key_chain() - .pub_account_signing_key(user_holding_lp) - { - private_keys.push(signing_key_lp); - let lp_nonces = self - .0 - .get_accounts_nonces(vec![user_holding_lp]) - .await - .map_err(ExecutionFailureKind::SequencerError)?; - nonces.extend(lp_nonces); - } else { - println!( - "Liquidity pool tokens receiver's account ({user_holding_lp}) private key not found in wallet. Proceeding with only liquidity provider's keys." - ); - } - - let message = nssa::public_transaction::Message::try_new( - program.id(), - account_ids, - nonces, - instruction, - ) - .unwrap(); - - let witness_set = - nssa::public_transaction::WitnessSet::for_message(&message, &private_keys); - - let tx = nssa::PublicTransaction::new(message, witness_set); - - Ok(self - .0 - .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) - .await?) } pub async fn send_swap_exact_input( @@ -129,14 +73,8 @@ impl Amm<'_> { min_amount_out: u128, token_definition_id_in: AccountId, ) -> Result { - let instruction = amm_core::Instruction::SwapExactInput { - swap_amount_in, - min_amount_out, - token_definition_id_in, - }; let program = Program::amm(); let amm_program_id = Program::amm().id(); - let user_a_acc = self .0 .get_account_public(user_holding_a) @@ -159,56 +97,47 @@ impl Amm<'_> { compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id); let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id); let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id); + let instruction = amm_core::Instruction::SwapExactInput { + swap_amount_in, + min_amount_out, + token_definition_id_in, + }; + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); - let account_ids = vec![ - amm_pool, - vault_holding_a, - vault_holding_b, - user_holding_a, - user_holding_b, - ]; - - let account_id_auth = if definition_token_a_id == token_definition_id_in { - user_holding_a - } else if definition_token_b_id == token_definition_id_in { - user_holding_b - } else { + if (token_definition_id_in != definition_token_a_id) + && (token_definition_id_in != definition_token_b_id) + { return Err(ExecutionFailureKind::AccountDataError( token_definition_id_in, )); + } + + let user_a_signing_identity = if token_definition_id_in == definition_token_a_id { + AccountIdentity::Public(user_holding_a) + } else { + AccountIdentity::PublicNoSign(user_holding_a) }; - let nonces = self - .0 - .get_accounts_nonces(vec![account_id_auth]) + let user_b_signing_identity = if token_definition_id_in == definition_token_b_id { + AccountIdentity::Public(user_holding_b) + } else { + AccountIdentity::PublicNoSign(user_holding_b) + }; + + self.0 + .send_pub_tx( + vec![ + AccountIdentity::PublicNoSign(amm_pool), + AccountIdentity::PublicNoSign(vault_holding_a), + AccountIdentity::PublicNoSign(vault_holding_b), + user_a_signing_identity, + user_b_signing_identity, + ], + instruction_data, + &program.into(), + ) .await - .map_err(ExecutionFailureKind::SequencerError)?; - - let signing_key = self - .0 - .storage - .key_chain() - .pub_account_signing_key(account_id_auth) - .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - - let message = nssa::public_transaction::Message::try_new( - program.id(), - account_ids, - nonces, - instruction, - ) - .unwrap(); - - let witness_set = - nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]); - - let tx = nssa::PublicTransaction::new(message, witness_set); - - Ok(self - .0 - .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) - .await?) } pub async fn send_swap_exact_output( @@ -219,14 +148,8 @@ impl Amm<'_> { max_amount_in: u128, token_definition_id_in: AccountId, ) -> Result { - let instruction = amm_core::Instruction::SwapExactOutput { - exact_amount_out, - max_amount_in, - token_definition_id_in, - }; let program = Program::amm(); let amm_program_id = Program::amm().id(); - let user_a_acc = self .0 .get_account_public(user_holding_a) @@ -249,56 +172,47 @@ impl Amm<'_> { compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id); let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id); let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id); + let instruction = amm_core::Instruction::SwapExactOutput { + exact_amount_out, + max_amount_in, + token_definition_id_in, + }; + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); - let account_ids = vec![ - amm_pool, - vault_holding_a, - vault_holding_b, - user_holding_a, - user_holding_b, - ]; - - let account_id_auth = if definition_token_a_id == token_definition_id_in { - user_holding_a - } else if definition_token_b_id == token_definition_id_in { - user_holding_b - } else { + if (token_definition_id_in != definition_token_a_id) + && (token_definition_id_in != definition_token_b_id) + { return Err(ExecutionFailureKind::AccountDataError( token_definition_id_in, )); + } + + let user_a_signing_identity = if token_definition_id_in == definition_token_a_id { + AccountIdentity::Public(user_holding_a) + } else { + AccountIdentity::PublicNoSign(user_holding_a) }; - let nonces = self - .0 - .get_accounts_nonces(vec![account_id_auth]) + let user_b_signing_identity = if token_definition_id_in == definition_token_b_id { + AccountIdentity::Public(user_holding_b) + } else { + AccountIdentity::PublicNoSign(user_holding_b) + }; + + self.0 + .send_pub_tx( + vec![ + AccountIdentity::PublicNoSign(amm_pool), + AccountIdentity::PublicNoSign(vault_holding_a), + AccountIdentity::PublicNoSign(vault_holding_b), + user_a_signing_identity, + user_b_signing_identity, + ], + instruction_data, + &program.into(), + ) .await - .map_err(ExecutionFailureKind::SequencerError)?; - - let signing_key = self - .0 - .storage - .key_chain() - .pub_account_signing_key(account_id_auth) - .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - - let message = nssa::public_transaction::Message::try_new( - program.id(), - account_ids, - nonces, - instruction, - ) - .unwrap(); - - let witness_set = - nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]); - - let tx = nssa::PublicTransaction::new(message, witness_set); - - Ok(self - .0 - .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) - .await?) } pub async fn send_add_liquidity( @@ -310,14 +224,8 @@ impl Amm<'_> { max_amount_to_add_token_a: u128, max_amount_to_add_token_b: u128, ) -> Result { - let instruction = amm_core::Instruction::AddLiquidity { - min_amount_liquidity, - max_amount_to_add_token_a, - max_amount_to_add_token_b, - }; let program = Program::amm(); let amm_program_id = Program::amm().id(); - let user_a_acc = self .0 .get_account_public(user_holding_a) @@ -341,57 +249,29 @@ impl Amm<'_> { let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id); let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id); let pool_lp = compute_liquidity_token_pda(amm_program_id, amm_pool); + let instruction = amm_core::Instruction::AddLiquidity { + min_amount_liquidity, + max_amount_to_add_token_a, + max_amount_to_add_token_b, + }; + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); - let account_ids = vec![ - amm_pool, - vault_holding_a, - vault_holding_b, - pool_lp, - user_holding_a, - user_holding_b, - user_holding_lp, - ]; - - let nonces = self - .0 - .get_accounts_nonces(vec![user_holding_a, user_holding_b]) + self.0 + .send_pub_tx( + vec![ + AccountIdentity::PublicNoSign(amm_pool), + AccountIdentity::PublicNoSign(vault_holding_a), + AccountIdentity::PublicNoSign(vault_holding_b), + AccountIdentity::PublicNoSign(pool_lp), + AccountIdentity::Public(user_holding_a), + AccountIdentity::Public(user_holding_b), + AccountIdentity::PublicNoSign(user_holding_lp), + ], + instruction_data, + &program.into(), + ) .await - .map_err(ExecutionFailureKind::SequencerError)?; - - let signing_key_a = self - .0 - .storage - .key_chain() - .pub_account_signing_key(user_holding_a) - .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - - let signing_key_b = self - .0 - .storage - .key_chain() - .pub_account_signing_key(user_holding_b) - .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - - let message = nssa::public_transaction::Message::try_new( - program.id(), - account_ids, - nonces, - instruction, - ) - .unwrap(); - - let witness_set = nssa::public_transaction::WitnessSet::for_message( - &message, - &[signing_key_a, signing_key_b], - ); - - let tx = nssa::PublicTransaction::new(message, witness_set); - - Ok(self - .0 - .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) - .await?) } pub async fn send_remove_liquidity( @@ -403,14 +283,8 @@ impl Amm<'_> { min_amount_to_remove_token_a: u128, min_amount_to_remove_token_b: u128, ) -> Result { - let instruction = amm_core::Instruction::RemoveLiquidity { - remove_liquidity_amount, - min_amount_to_remove_token_a, - min_amount_to_remove_token_b, - }; let program = Program::amm(); let amm_program_id = Program::amm().id(); - let user_a_acc = self .0 .get_account_public(user_holding_a) @@ -434,47 +308,28 @@ impl Amm<'_> { let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id); let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id); let pool_lp = compute_liquidity_token_pda(amm_program_id, amm_pool); + let instruction = amm_core::Instruction::RemoveLiquidity { + remove_liquidity_amount, + min_amount_to_remove_token_a, + min_amount_to_remove_token_b, + }; + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); - let account_ids = vec![ - amm_pool, - vault_holding_a, - vault_holding_b, - pool_lp, - user_holding_a, - user_holding_b, - user_holding_lp, - ]; - - let nonces = self - .0 - .get_accounts_nonces(vec![user_holding_lp]) + self.0 + .send_pub_tx( + vec![ + AccountIdentity::PublicNoSign(amm_pool), + AccountIdentity::PublicNoSign(vault_holding_a), + AccountIdentity::PublicNoSign(vault_holding_b), + AccountIdentity::PublicNoSign(pool_lp), + AccountIdentity::PublicNoSign(user_holding_a), + AccountIdentity::PublicNoSign(user_holding_b), + AccountIdentity::Public(user_holding_lp), + ], + instruction_data, + &program.into(), + ) .await - .map_err(ExecutionFailureKind::SequencerError)?; - - let signing_key_lp = self - .0 - .storage - .key_chain() - .pub_account_signing_key(user_holding_lp) - .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - - let message = nssa::public_transaction::Message::try_new( - program.id(), - account_ids, - nonces, - instruction, - ) - .unwrap(); - - let witness_set = - nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key_lp]); - - let tx = nssa::PublicTransaction::new(message, witness_set); - - Ok(self - .0 - .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) - .await?) } } diff --git a/wallet/src/program_facades/ata.rs b/wallet/src/program_facades/ata.rs index bdb72620..68d45bbe 100644 --- a/wallet/src/program_facades/ata.rs +++ b/wallet/src/program_facades/ata.rs @@ -1,14 +1,13 @@ use std::collections::HashMap; use ata_core::{compute_ata_seed, get_associated_token_account_id}; -use common::{HashType, transaction::NSSATransaction}; +use common::HashType; use nssa::{ AccountId, privacy_preserving_transaction::circuit::ProgramWithDependencies, program::Program, }; use nssa_core::SharedSecretKey; -use sequencer_service_rpc::RpcClient as _; -use crate::{ExecutionFailureKind, PrivacyPreservingAccount, WalletCore}; +use crate::{AccountIdentity, ExecutionFailureKind, WalletCore}; pub struct Ata<'wallet>(pub &'wallet WalletCore); @@ -24,38 +23,21 @@ impl Ata<'_> { &ata_program_id, &compute_ata_seed(owner_id, definition_id), ); - - let account_ids = vec![owner_id, definition_id, ata_id]; - - let nonces = self - .0 - .get_accounts_nonces(vec![owner_id]) - .await - .map_err(ExecutionFailureKind::SequencerError)?; - - let Some(signing_key) = self.0.storage.key_chain().pub_account_signing_key(owner_id) else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - let instruction = ata_core::Instruction::Create { ata_program_id }; + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); - let message = nssa::public_transaction::Message::try_new( - program.id(), - account_ids, - nonces, - instruction, - )?; - - let witness_set = - nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]); - - let tx = nssa::PublicTransaction::new(message, witness_set); - - Ok(self - .0 - .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) - .await?) + self.0 + .send_pub_tx( + vec![ + AccountIdentity::Public(owner_id), + AccountIdentity::PublicNoSign(definition_id), + AccountIdentity::PublicNoSign(ata_id), + ], + instruction_data, + &program.into(), + ) + .await } pub async fn send_transfer( @@ -71,41 +53,24 @@ impl Ata<'_> { &ata_program_id, &compute_ata_seed(owner_id, definition_id), ); - - let account_ids = vec![owner_id, sender_ata_id, recipient_id]; - - let nonces = self - .0 - .get_accounts_nonces(vec![owner_id]) - .await - .map_err(ExecutionFailureKind::SequencerError)?; - - let Some(signing_key) = self.0.storage.key_chain().pub_account_signing_key(owner_id) else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - let instruction = ata_core::Instruction::Transfer { ata_program_id, amount, }; + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); - let message = nssa::public_transaction::Message::try_new( - program.id(), - account_ids, - nonces, - instruction, - )?; - - let witness_set = - nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]); - - let tx = nssa::PublicTransaction::new(message, witness_set); - - Ok(self - .0 - .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) - .await?) + self.0 + .send_pub_tx( + vec![ + AccountIdentity::Public(owner_id), + AccountIdentity::PublicNoSign(sender_ata_id), + AccountIdentity::PublicNoSign(recipient_id), + ], + instruction_data, + &program.into(), + ) + .await } pub async fn send_burn( @@ -120,41 +85,24 @@ impl Ata<'_> { &ata_program_id, &compute_ata_seed(owner_id, definition_id), ); - - let account_ids = vec![owner_id, holder_ata_id, definition_id]; - - let nonces = self - .0 - .get_accounts_nonces(vec![owner_id]) - .await - .map_err(ExecutionFailureKind::SequencerError)?; - - let Some(signing_key) = self.0.storage.key_chain().pub_account_signing_key(owner_id) else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - let instruction = ata_core::Instruction::Burn { ata_program_id, amount, }; + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); - let message = nssa::public_transaction::Message::try_new( - program.id(), - account_ids, - nonces, - instruction, - )?; - - let witness_set = - nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]); - - let tx = nssa::PublicTransaction::new(message, witness_set); - - Ok(self - .0 - .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) - .await?) + self.0 + .send_pub_tx( + vec![ + AccountIdentity::Public(owner_id), + AccountIdentity::PublicNoSign(holder_ata_id), + AccountIdentity::PublicNoSign(definition_id), + ], + instruction_data, + &program.into(), + ) + .await } pub async fn send_create_private_owner( @@ -176,8 +124,8 @@ impl Ata<'_> { self.0 .resolve_private_account(owner_id) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, - PrivacyPreservingAccount::Public(definition_id), - PrivacyPreservingAccount::Public(ata_id), + AccountIdentity::Public(definition_id), + AccountIdentity::Public(ata_id), ]; self.0 @@ -213,8 +161,8 @@ impl Ata<'_> { self.0 .resolve_private_account(owner_id) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, - PrivacyPreservingAccount::Public(sender_ata_id), - PrivacyPreservingAccount::Public(recipient_id), + AccountIdentity::Public(sender_ata_id), + AccountIdentity::Public(recipient_id), ]; self.0 @@ -249,8 +197,8 @@ impl Ata<'_> { self.0 .resolve_private_account(owner_id) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, - PrivacyPreservingAccount::Public(holder_ata_id), - PrivacyPreservingAccount::Public(definition_id), + AccountIdentity::Public(holder_ata_id), + AccountIdentity::Public(definition_id), ]; self.0 diff --git a/wallet/src/program_facades/native_token_transfer/deshielded.rs b/wallet/src/program_facades/native_token_transfer/deshielded.rs index d4bde39f..31374f99 100644 --- a/wallet/src/program_facades/native_token_transfer/deshielded.rs +++ b/wallet/src/program_facades/native_token_transfer/deshielded.rs @@ -2,7 +2,7 @@ use common::HashType; use nssa::AccountId; use super::{NativeTokenTransfer, auth_transfer_preparation}; -use crate::{ExecutionFailureKind, PrivacyPreservingAccount}; +use crate::{AccountIdentity, ExecutionFailureKind}; impl NativeTokenTransfer<'_> { pub async fn send_deshielded_transfer( @@ -19,7 +19,7 @@ impl NativeTokenTransfer<'_> { self.0 .resolve_private_account(from) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, - PrivacyPreservingAccount::Public(to), + AccountIdentity::Public(to), ], instruction_data, &program.into(), diff --git a/wallet/src/program_facades/native_token_transfer/private.rs b/wallet/src/program_facades/native_token_transfer/private.rs index e8438d08..481e4a5f 100644 --- a/wallet/src/program_facades/native_token_transfer/private.rs +++ b/wallet/src/program_facades/native_token_transfer/private.rs @@ -5,7 +5,7 @@ use nssa::{AccountId, program::Program}; use nssa_core::{Identifier, NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; use super::{NativeTokenTransfer, auth_transfer_preparation}; -use crate::{ExecutionFailureKind, PrivacyPreservingAccount}; +use crate::{AccountIdentity, ExecutionFailureKind}; impl NativeTokenTransfer<'_> { pub async fn register_account_private( @@ -49,7 +49,7 @@ impl NativeTokenTransfer<'_> { self.0 .resolve_private_account(from) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, - PrivacyPreservingAccount::PrivateForeign { + AccountIdentity::PrivateForeign { npk: to_npk, vpk: to_vpk, identifier: to_identifier, diff --git a/wallet/src/program_facades/native_token_transfer/shielded.rs b/wallet/src/program_facades/native_token_transfer/shielded.rs index 98dd0081..44916529 100644 --- a/wallet/src/program_facades/native_token_transfer/shielded.rs +++ b/wallet/src/program_facades/native_token_transfer/shielded.rs @@ -3,7 +3,7 @@ use nssa::AccountId; use nssa_core::{Identifier, NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; use super::{NativeTokenTransfer, auth_transfer_preparation}; -use crate::{ExecutionFailureKind, PrivacyPreservingAccount}; +use crate::{AccountIdentity, ExecutionFailureKind}; impl NativeTokenTransfer<'_> { pub async fn send_shielded_transfer( @@ -17,7 +17,7 @@ impl NativeTokenTransfer<'_> { self.0 .send_privacy_preserving_tx_with_pre_check( vec![ - PrivacyPreservingAccount::Public(from), + AccountIdentity::Public(from), self.0 .resolve_private_account(to) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, @@ -49,8 +49,8 @@ impl NativeTokenTransfer<'_> { self.0 .send_privacy_preserving_tx_with_pre_check( vec![ - PrivacyPreservingAccount::Public(from), - PrivacyPreservingAccount::PrivateForeign { + AccountIdentity::Public(from), + AccountIdentity::PrivateForeign { npk: to_npk, vpk: to_vpk, identifier: to_identifier, diff --git a/wallet/src/program_facades/pinata.rs b/wallet/src/program_facades/pinata.rs index 0575455e..2e40e78b 100644 --- a/wallet/src/program_facades/pinata.rs +++ b/wallet/src/program_facades/pinata.rs @@ -1,9 +1,8 @@ -use common::{HashType, transaction::NSSATransaction}; -use nssa::AccountId; +use common::HashType; +use nssa::{AccountId, program::Program}; use nssa_core::{MembershipProof, SharedSecretKey}; -use sequencer_service_rpc::RpcClient as _; -use crate::{ExecutionFailureKind, PrivacyPreservingAccount, WalletCore}; +use crate::{AccountIdentity, ExecutionFailureKind, WalletCore}; pub struct Pinata<'wallet>(pub &'wallet WalletCore); @@ -14,20 +13,21 @@ impl Pinata<'_> { winner_account_id: AccountId, solution: u128, ) -> Result { - let account_ids = vec![pinata_account_id, winner_account_id]; - let program_id = nssa::program::Program::pinata().id(); - let message = - nssa::public_transaction::Message::try_new(program_id, account_ids, vec![], solution) - .unwrap(); + let program = Program::pinata(); + let instruction = solution; + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); - let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]); - let tx = nssa::PublicTransaction::new(message, witness_set); - - Ok(self - .0 - .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) - .await?) + self.0 + .send_pub_tx( + vec![ + AccountIdentity::PublicNoSign(pinata_account_id), + AccountIdentity::PublicNoSign(winner_account_id), + ], + instruction_data, + &program.into(), + ) + .await } /// Claim a pinata reward using a privacy-preserving transaction for an already-initialized @@ -55,7 +55,7 @@ impl Pinata<'_> { self.0 .send_privacy_preserving_tx( vec![ - PrivacyPreservingAccount::Public(pinata_account_id), + AccountIdentity::Public(pinata_account_id), self.0 .resolve_private_account(winner_account_id) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, diff --git a/wallet/src/program_facades/token.rs b/wallet/src/program_facades/token.rs index 7197b1f0..8e9b4f8f 100644 --- a/wallet/src/program_facades/token.rs +++ b/wallet/src/program_facades/token.rs @@ -1,10 +1,9 @@ -use common::{HashType, transaction::NSSATransaction}; +use common::HashType; use nssa::{AccountId, program::Program}; use nssa_core::{Identifier, NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; -use sequencer_service_rpc::RpcClient as _; use token_core::Instruction; -use crate::{ExecutionFailureKind, PrivacyPreservingAccount, WalletCore}; +use crate::{AccountIdentity, ExecutionFailureKind, WalletCore}; pub struct Token<'wallet>(pub &'wallet WalletCore); @@ -16,47 +15,21 @@ impl Token<'_> { name: String, total_supply: u128, ) -> Result { - let account_ids = vec![definition_account_id, supply_account_id]; - let program_id = nssa::program::Program::token().id(); + let program = Program::token(); let instruction = Instruction::NewFungibleDefinition { name, total_supply }; - let nonces = self - .0 - .get_accounts_nonces(account_ids.clone()) + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); + + self.0 + .send_pub_tx( + vec![ + AccountIdentity::Public(definition_account_id), + AccountIdentity::Public(supply_account_id), + ], + instruction_data, + &program.into(), + ) .await - .map_err(ExecutionFailureKind::SequencerError)?; - let message = nssa::public_transaction::Message::try_new( - program_id, - account_ids, - nonces, - instruction, - ) - .unwrap(); - - let def_private_key = self - .0 - .storage - .key_chain() - .pub_account_signing_key(definition_account_id) - .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - let supply_private_key = self - .0 - .storage - .key_chain() - .pub_account_signing_key(supply_account_id) - .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - - let witness_set = nssa::public_transaction::WitnessSet::for_message( - &message, - &[def_private_key, supply_private_key], - ); - - let tx = nssa::PublicTransaction::new(message, witness_set); - - Ok(self - .0 - .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) - .await?) } pub async fn send_new_definition_private_owned_supply( @@ -73,7 +46,7 @@ impl Token<'_> { self.0 .send_privacy_preserving_tx( vec![ - PrivacyPreservingAccount::Public(definition_account_id), + AccountIdentity::Public(definition_account_id), self.0 .resolve_private_account(supply_account_id) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, @@ -108,7 +81,7 @@ impl Token<'_> { self.0 .resolve_private_account(definition_account_id) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, - PrivacyPreservingAccount::Public(supply_account_id), + AccountIdentity::Public(supply_account_id), ], instruction_data, &Program::token().into(), @@ -162,62 +135,23 @@ impl Token<'_> { recipient_account_id: AccountId, amount: u128, ) -> Result { - let account_ids = vec![sender_account_id, recipient_account_id]; - let program_id = nssa::program::Program::token().id(); + let program = Program::token(); let instruction = Instruction::Transfer { amount_to_transfer: amount, }; - let mut nonces = self - .0 - .get_accounts_nonces(vec![sender_account_id]) + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); + + self.0 + .send_pub_tx( + vec![ + AccountIdentity::Public(sender_account_id), + AccountIdentity::Public(recipient_account_id), + ], + instruction_data, + &program.into(), + ) .await - .map_err(ExecutionFailureKind::SequencerError)?; - - let mut private_keys = Vec::new(); - let sender_sk = self - .0 - .storage - .key_chain() - .pub_account_signing_key(sender_account_id) - .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - private_keys.push(sender_sk); - - if let Some(recipient_sk) = self - .0 - .storage - .key_chain() - .pub_account_signing_key(recipient_account_id) - { - private_keys.push(recipient_sk); - let recipient_nonces = self - .0 - .get_accounts_nonces(vec![recipient_account_id]) - .await - .map_err(ExecutionFailureKind::SequencerError)?; - nonces.extend(recipient_nonces); - } else { - println!( - "Receiver's account ({recipient_account_id}) private key not found in wallet. Proceeding with only sender's key." - ); - } - - let message = nssa::public_transaction::Message::try_new( - program_id, - account_ids, - nonces, - instruction, - ) - .unwrap(); - let witness_set = - nssa::public_transaction::WitnessSet::for_message(&message, &private_keys); - - let tx = nssa::PublicTransaction::new(message, witness_set); - - Ok(self - .0 - .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) - .await?) } pub async fn send_transfer_transaction_private_owned_account( @@ -274,7 +208,7 @@ impl Token<'_> { self.0 .resolve_private_account(sender_account_id) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, - PrivacyPreservingAccount::PrivateForeign { + AccountIdentity::PrivateForeign { npk: recipient_npk, vpk: recipient_vpk, identifier: recipient_identifier, @@ -310,7 +244,7 @@ impl Token<'_> { self.0 .resolve_private_account(sender_account_id) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, - PrivacyPreservingAccount::Public(recipient_account_id), + AccountIdentity::Public(recipient_account_id), ], instruction_data, &Program::token().into(), @@ -340,7 +274,7 @@ impl Token<'_> { self.0 .send_privacy_preserving_tx( vec![ - PrivacyPreservingAccount::Public(sender_account_id), + AccountIdentity::Public(sender_account_id), self.0 .resolve_private_account(recipient_account_id) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, @@ -375,8 +309,8 @@ impl Token<'_> { self.0 .send_privacy_preserving_tx( vec![ - PrivacyPreservingAccount::Public(sender_account_id), - PrivacyPreservingAccount::PrivateForeign { + AccountIdentity::Public(sender_account_id), + AccountIdentity::PrivateForeign { npk: recipient_npk, vpk: recipient_vpk, identifier: recipient_identifier, @@ -401,40 +335,23 @@ impl Token<'_> { holder_account_id: AccountId, amount: u128, ) -> Result { - let account_ids = vec![definition_account_id, holder_account_id]; + let program = Program::token(); let instruction = Instruction::Burn { amount_to_burn: amount, }; + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); - let nonces = self - .0 - .get_accounts_nonces(vec![holder_account_id]) + self.0 + .send_pub_tx( + vec![ + AccountIdentity::PublicNoSign(definition_account_id), + AccountIdentity::Public(holder_account_id), + ], + instruction_data, + &program.into(), + ) .await - .map_err(ExecutionFailureKind::SequencerError)?; - let message = nssa::public_transaction::Message::try_new( - Program::token().id(), - account_ids, - nonces, - instruction, - ) - .expect("Instruction should serialize"); - - let signing_key = self - .0 - .storage - .key_chain() - .pub_account_signing_key(holder_account_id) - .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - let witness_set = - nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]); - - let tx = nssa::PublicTransaction::new(message, witness_set); - - Ok(self - .0 - .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) - .await?) } pub async fn send_burn_transaction_private_owned_account( @@ -489,7 +406,7 @@ impl Token<'_> { self.0 .resolve_private_account(definition_account_id) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, - PrivacyPreservingAccount::Public(holder_account_id), + AccountIdentity::Public(holder_account_id), ], instruction_data, &Program::token().into(), @@ -519,7 +436,7 @@ impl Token<'_> { self.0 .send_privacy_preserving_tx( vec![ - PrivacyPreservingAccount::Public(definition_account_id), + AccountIdentity::Public(definition_account_id), self.0 .resolve_private_account(holder_account_id) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, @@ -543,62 +460,23 @@ impl Token<'_> { holder_account_id: AccountId, amount: u128, ) -> Result { - let account_ids = vec![definition_account_id, holder_account_id]; + let program = Program::token(); let instruction = Instruction::Mint { amount_to_mint: amount, }; + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); - let mut nonces = self - .0 - .get_accounts_nonces(vec![definition_account_id]) + self.0 + .send_pub_tx( + vec![ + AccountIdentity::Public(definition_account_id), + AccountIdentity::Public(holder_account_id), + ], + instruction_data, + &program.into(), + ) .await - .map_err(ExecutionFailureKind::SequencerError)?; - - let mut private_keys = Vec::new(); - let definition_sk = self - .0 - .storage - .key_chain() - .pub_account_signing_key(definition_account_id) - .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - private_keys.push(definition_sk); - - if let Some(holder_sk) = self - .0 - .storage - .key_chain() - .pub_account_signing_key(holder_account_id) - { - private_keys.push(holder_sk); - let recipient_nonces = self - .0 - .get_accounts_nonces(vec![holder_account_id]) - .await - .map_err(ExecutionFailureKind::SequencerError)?; - nonces.extend(recipient_nonces); - } else { - println!( - "Holder's account ({holder_account_id}) private key not found in wallet. Proceeding with only definition's key." - ); - } - - let message = nssa::public_transaction::Message::try_new( - Program::token().id(), - account_ids, - nonces, - instruction, - ) - .unwrap(); - let witness_set = - nssa::public_transaction::WitnessSet::for_message(&message, &private_keys); - - let tx = nssa::PublicTransaction::new(message, witness_set); - - Ok(self - .0 - .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) - .await?) } pub async fn send_mint_transaction_private_owned_account( @@ -655,7 +533,7 @@ impl Token<'_> { self.0 .resolve_private_account(definition_account_id) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, - PrivacyPreservingAccount::PrivateForeign { + AccountIdentity::PrivateForeign { npk: holder_npk, vpk: holder_vpk, identifier: holder_identifier, @@ -691,7 +569,7 @@ impl Token<'_> { self.0 .resolve_private_account(definition_account_id) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, - PrivacyPreservingAccount::Public(holder_account_id), + AccountIdentity::Public(holder_account_id), ], instruction_data, &Program::token().into(), @@ -721,7 +599,7 @@ impl Token<'_> { self.0 .send_privacy_preserving_tx( vec![ - PrivacyPreservingAccount::Public(definition_account_id), + AccountIdentity::Public(definition_account_id), self.0 .resolve_private_account(holder_account_id) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, @@ -756,8 +634,8 @@ impl Token<'_> { self.0 .send_privacy_preserving_tx( vec![ - PrivacyPreservingAccount::Public(definition_account_id), - PrivacyPreservingAccount::PrivateForeign { + AccountIdentity::Public(definition_account_id), + AccountIdentity::PrivateForeign { npk: holder_npk, vpk: holder_vpk, identifier: holder_identifier,