From 4e36ae46792750816f6a3ae6d921320f20e6dc3c Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Thu, 23 Oct 2025 17:33:25 +0300 Subject: [PATCH 01/10] fix; first refactor --- Cargo.toml | 1 + common/Cargo.toml | 3 +- common/src/transaction.rs | 9 +- integration_tests/src/test_suite_map.rs | 128 ++++++++++++------------ key_protocol/Cargo.toml | 3 +- key_protocol/src/key_management/mod.rs | 3 +- nssa/core/Cargo.toml | 5 +- nssa/core/src/address.rs | 15 ++- sequencer_core/Cargo.toml | 2 +- sequencer_core/src/lib.rs | 97 +++++++++++++----- sequencer_rpc/Cargo.toml | 3 +- sequencer_rpc/src/process.rs | 16 +-- wallet/Cargo.toml | 3 +- wallet/src/cli/account.rs | 21 ++-- wallet/src/cli/chain.rs | 12 +-- wallet/src/lib.rs | 16 +-- 16 files changed, 202 insertions(+), 135 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2019628..9ceb790 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ bip39 = "2.2.0" hmac-sha512 = "1.1.7" chrono = "0.4.41" borsh = "1.5.7" +base58 = "0.2.0" rocksdb = { version = "0.21.0", default-features = false, features = [ "snappy", diff --git a/common/Cargo.toml b/common/Cargo.toml index d0d145f..95d1c02 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -15,7 +15,8 @@ rs_merkle.workspace = true sha2.workspace = true log.workspace = true elliptic-curve.workspace = true -hex.workspace = true +base58.workspace = true +hex = "0.4.3" nssa-core = { path = "../nssa/core", features = ["host"] } borsh.workspace = true diff --git a/common/src/transaction.rs b/common/src/transaction.rs index c99cf31..65c55c9 100644 --- a/common/src/transaction.rs +++ b/common/src/transaction.rs @@ -1,3 +1,4 @@ +use base58::ToBase58; use borsh::{BorshDeserialize, BorshSerialize}; use k256::ecdsa::{Signature, SigningKey, VerifyingKey}; use log::info; @@ -125,7 +126,7 @@ impl From for OwnedUTXOForPublication { fn from(value: OwnedUTXO) -> Self { Self { hash: hex::encode(value.hash), - owner: hex::encode(value.owner), + owner: value.owner.to_base58(), amount: value.amount, } } @@ -150,7 +151,7 @@ impl ActionData { ActionData::MintMoneyPublicTx(action) => { format!( "Account {:?} minted {:?} balance", - hex::encode(action.acc), + action.acc.to_base58(), action.amount ) } @@ -160,14 +161,14 @@ impl ActionData { action .receiver_data .into_iter() - .map(|(amount, rec)| (amount, hex::encode(rec))) + .map(|(amount, rec)| (amount, rec.to_base58())) .collect::>() ) } ActionData::SendMoneyShieldedTx(action) => { format!( "Shielded send from {:?} for {:?} balance", - hex::encode(action.acc_sender), + action.acc_sender.to_base58(), action.amount ) } diff --git a/integration_tests/src/test_suite_map.rs b/integration_tests/src/test_suite_map.rs index 99a1371..80bf894 100644 --- a/integration_tests/src/test_suite_map.rs +++ b/integration_tests/src/test_suite_map.rs @@ -7,7 +7,7 @@ use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1 use wallet::{ Command, SubcommandReturnValue, WalletCore, cli::{ - account::{AccountSubcommand, FetchSubcommand, RegisterSubcommand}, + account::{AccountSubcommand, FetchSubcommand, NewSubcommand}, native_token_transfer_program::{ NativeTokenTransferProgramSubcommand, NativeTokenTransferProgramSubcommandPrivate, NativeTokenTransferProgramSubcommandShielded, @@ -40,7 +40,7 @@ pub fn prepare_function_map() -> HashMap { #[test_suite_fn] pub async fn test_success() { info!("test_success"); - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { + let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public { from: ACC_SENDER.to_string(), to: ACC_RECEIVER.to_string(), amount: 100, @@ -77,7 +77,7 @@ pub fn prepare_function_map() -> HashMap { #[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 command = Command::Account(AccountSubcommand::New(NewSubcommand::Public {})); let wallet_config = fetch_config().await.unwrap(); @@ -101,7 +101,7 @@ pub fn prepare_function_map() -> HashMap { panic!("Failed to produce new account, not present in persistent accounts"); } - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { + let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public { from: ACC_SENDER.to_string(), to: new_persistent_account_addr.clone(), amount: 100, @@ -134,7 +134,7 @@ pub fn prepare_function_map() -> HashMap { #[test_suite_fn] pub async fn test_failure() { info!("test_failure"); - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { + let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public { from: ACC_SENDER.to_string(), to: ACC_RECEIVER.to_string(), amount: 1000000, @@ -173,7 +173,7 @@ pub fn prepare_function_map() -> HashMap { #[test_suite_fn] pub async fn test_success_two_transactions() { info!("test_success_two_transactions"); - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { + let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public { from: ACC_SENDER.to_string(), to: ACC_RECEIVER.to_string(), amount: 100, @@ -206,7 +206,7 @@ pub fn prepare_function_map() -> HashMap { info!("First TX Success!"); - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Public { + let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public { from: ACC_SENDER.to_string(), to: ACC_RECEIVER.to_string(), amount: 100, @@ -264,20 +264,20 @@ pub fn prepare_function_map() -> HashMap { let wallet_config = fetch_config().await.unwrap(); // Create new account for the token definition - wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, + wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Public {}, ))) .await .unwrap(); // Create new account for the token supply holder - wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, + wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Public {}, ))) .await .unwrap(); // Create new account for receiving a token transaction - wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, + wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Public {}, ))) .await .unwrap(); @@ -311,7 +311,7 @@ pub fn prepare_function_map() -> HashMap { name: "A NAME".to_string(), total_supply: 37, }); - wallet::execute_subcommand(Command::TokenProgram(subcommand)) + wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); info!("Waiting for next block creation"); @@ -365,7 +365,7 @@ pub fn prepare_function_map() -> HashMap { recipient_addr: recipient_addr.to_string(), balance_to_move: 7, }); - wallet::execute_subcommand(Command::TokenProgram(subcommand)) + wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); info!("Waiting for next block creation"); @@ -416,8 +416,8 @@ pub fn prepare_function_map() -> HashMap { // Create new account for the token definition (public) let SubcommandReturnValue::RegisterAccount { addr: definition_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Public {}, ))) .await .unwrap() @@ -426,8 +426,8 @@ pub fn prepare_function_map() -> HashMap { }; // Create new account for the token supply holder (private) let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = - wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Private {}, + wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Private {}, ))) .await .unwrap() @@ -437,8 +437,8 @@ pub fn prepare_function_map() -> HashMap { // Create new account for receiving a token transaction let SubcommandReturnValue::RegisterAccount { addr: recipient_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Private {}, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Private {}, ))) .await .unwrap() @@ -456,7 +456,7 @@ pub fn prepare_function_map() -> HashMap { }, ); - wallet::execute_subcommand(Command::TokenProgram(subcommand)) + wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); @@ -501,7 +501,7 @@ pub fn prepare_function_map() -> HashMap { }, ); - wallet::execute_subcommand(Command::TokenProgram(subcommand)) + wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); @@ -532,7 +532,7 @@ pub fn prepare_function_map() -> HashMap { }, ); - wallet::execute_subcommand(Command::TokenProgram(subcommand)) + wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); @@ -564,8 +564,8 @@ pub fn prepare_function_map() -> HashMap { // Create new account for the token definition (public) let SubcommandReturnValue::RegisterAccount { addr: definition_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Public {}, ))) .await .unwrap() @@ -574,8 +574,8 @@ pub fn prepare_function_map() -> HashMap { }; // Create new account for the token supply holder (private) let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = - wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Private {}, + wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Private {}, ))) .await .unwrap() @@ -585,8 +585,8 @@ pub fn prepare_function_map() -> HashMap { // Create new account for receiving a token transaction let SubcommandReturnValue::RegisterAccount { addr: recipient_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Private {}, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Private {}, ))) .await .unwrap() @@ -604,7 +604,7 @@ pub fn prepare_function_map() -> HashMap { }, ); - wallet::execute_subcommand(Command::TokenProgram(subcommand)) + wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); @@ -657,7 +657,7 @@ pub fn prepare_function_map() -> HashMap { ); let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = - wallet::execute_subcommand(Command::TokenProgram(subcommand)) + wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap() else { @@ -700,8 +700,8 @@ pub fn prepare_function_map() -> HashMap { // Create new account for the token definition (public) let SubcommandReturnValue::RegisterAccount { addr: definition_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Public {}, ))) .await .unwrap() @@ -710,8 +710,8 @@ pub fn prepare_function_map() -> HashMap { }; // Create new account for the token supply holder (public) let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = - wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, + wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Public {}, ))) .await .unwrap() @@ -721,8 +721,8 @@ pub fn prepare_function_map() -> HashMap { // Create new account for receiving a token transaction let SubcommandReturnValue::RegisterAccount { addr: recipient_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Private {}, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Private {}, ))) .await .unwrap() @@ -739,7 +739,7 @@ pub fn prepare_function_map() -> HashMap { total_supply: 37, }); - wallet::execute_subcommand(Command::TokenProgram(subcommand)) + wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); @@ -774,7 +774,7 @@ pub fn prepare_function_map() -> HashMap { }, ); - wallet::execute_subcommand(Command::TokenProgram(subcommand)) + wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); @@ -800,7 +800,7 @@ pub fn prepare_function_map() -> HashMap { }, ); - wallet::execute_subcommand(Command::TokenProgram(subcommand)) + wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); @@ -827,8 +827,8 @@ pub fn prepare_function_map() -> HashMap { // Create new account for the token definition (public) let SubcommandReturnValue::RegisterAccount { addr: definition_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Public {}, ))) .await .unwrap() @@ -837,8 +837,8 @@ pub fn prepare_function_map() -> HashMap { }; // Create new account for the token supply holder (private) let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = - wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Private {}, + wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Private {}, ))) .await .unwrap() @@ -848,8 +848,8 @@ pub fn prepare_function_map() -> HashMap { // Create new account for receiving a token transaction let SubcommandReturnValue::RegisterAccount { addr: recipient_addr, - } = wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Public {}, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Public {}, ))) .await .unwrap() @@ -867,7 +867,7 @@ pub fn prepare_function_map() -> HashMap { }, ); - wallet::execute_subcommand(Command::TokenProgram(subcommand)) + wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); @@ -912,7 +912,7 @@ pub fn prepare_function_map() -> HashMap { }, ); - wallet::execute_subcommand(Command::TokenProgram(subcommand)) + wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); @@ -938,7 +938,7 @@ pub fn prepare_function_map() -> HashMap { }, ); - wallet::execute_subcommand(Command::TokenProgram(subcommand)) + wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); @@ -962,7 +962,7 @@ pub fn prepare_function_map() -> HashMap { let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap(); - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Private( + let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private( NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { from: from.to_string(), to: to.to_string(), @@ -1000,7 +1000,7 @@ pub fn prepare_function_map() -> HashMap { let to_npk_string = hex::encode(to_npk.0); let to_ipk = Secp256k1Point::from_scalar(to_npk.0); - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Private( + let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private( NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { from: from.to_string(), to_npk: to_npk_string, @@ -1044,7 +1044,7 @@ pub fn prepare_function_map() -> HashMap { 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 command = Command::Account(AccountSubcommand::New(NewSubcommand::Private {})); let sub_ret = wallet::execute_subcommand(command).await.unwrap(); let SubcommandReturnValue::RegisterAccount { addr: to_addr } = sub_ret else { @@ -1065,7 +1065,7 @@ pub fn prepare_function_map() -> HashMap { .cloned() .unwrap(); - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Private( + let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private( NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { from: from.to_string(), to_npk: hex::encode(to_keys.nullifer_public_key.0), @@ -1115,7 +1115,7 @@ pub fn prepare_function_map() -> HashMap { let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); - let command = Command::Account(AccountSubcommand::Register(RegisterSubcommand::Private {})); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private {})); let sub_ret = wallet::execute_subcommand(command).await.unwrap(); let SubcommandReturnValue::RegisterAccount { addr: to_addr } = sub_ret else { @@ -1136,7 +1136,7 @@ pub fn prepare_function_map() -> HashMap { .cloned() .unwrap(); - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Private( + let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private( NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { from: from.to_string(), to_npk: hex::encode(to_keys.nullifer_public_key.0), @@ -1184,7 +1184,7 @@ pub fn prepare_function_map() -> HashMap { info!("test_success_deshielded_transfer_to_another_account"); let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); let to: Address = ACC_RECEIVER.parse().unwrap(); - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Deshielded { + let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Deshielded { from: from.to_string(), to: to.to_string(), amount: 100, @@ -1230,7 +1230,7 @@ pub fn prepare_function_map() -> HashMap { info!("test_success_shielded_transfer_to_another_owned_account"); let from: Address = ACC_SENDER.parse().unwrap(); let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap(); - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Shielded( + let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Shielded( NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { from: from.to_string(), to: to.to_string(), @@ -1274,7 +1274,7 @@ pub fn prepare_function_map() -> HashMap { let to_ipk = Secp256k1Point::from_scalar(to_npk.0); let from: Address = ACC_SENDER.parse().unwrap(); - let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Shielded( + let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Shielded( NativeTokenTransferProgramSubcommandShielded::ShieldedForeign { from: from.to_string(), to_npk: to_npk_string, @@ -1318,7 +1318,7 @@ pub fn prepare_function_map() -> HashMap { let pinata_addr = "cafe".repeat(16); let pinata_prize = 150; let solution = 989106; - let command = Command::PinataProgram(PinataProgramSubcommand::Public( + let command = Command::Pinata(PinataProgramSubcommand::Public( PinataProgramSubcommandPublic::Claim { pinata_addr: pinata_addr.clone(), winner_addr: ACC_SENDER.to_string(), @@ -1446,7 +1446,7 @@ pub fn prepare_function_map() -> HashMap { let pinata_prize = 150; let solution = 989106; - let command = Command::PinataProgram(PinataProgramSubcommand::Private( + let command = Command::Pinata(PinataProgramSubcommand::Private( PinataProgramSubcommandPrivate::ClaimPrivateOwned { pinata_addr: pinata_addr.clone(), winner_addr: ACC_SENDER_PRIVATE.to_string(), @@ -1512,8 +1512,8 @@ pub fn prepare_function_map() -> HashMap { // Create new account for the token supply holder (private) let SubcommandReturnValue::RegisterAccount { addr: winner_addr } = - wallet::execute_subcommand(Command::Account(AccountSubcommand::Register( - RegisterSubcommand::Private {}, + wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Private {}, ))) .await .unwrap() @@ -1521,7 +1521,7 @@ pub fn prepare_function_map() -> HashMap { panic!("invalid subcommand return value"); }; - let command = Command::PinataProgram(PinataProgramSubcommand::Private( + let command = Command::Pinata(PinataProgramSubcommand::Private( PinataProgramSubcommandPrivate::ClaimPrivateOwned { pinata_addr: pinata_addr.clone(), winner_addr: winner_addr.to_string(), diff --git a/key_protocol/Cargo.toml b/key_protocol/Cargo.toml index 544a2f8..b0708b4 100644 --- a/key_protocol/Cargo.toml +++ b/key_protocol/Cargo.toml @@ -9,7 +9,8 @@ serde.workspace = true k256.workspace = true sha2.workspace = true rand.workspace = true -hex.workspace = true +base58.workspace = true +hex = "0.4.3" aes-gcm.workspace = true bip39.workspace = true hmac-sha512.workspace = true diff --git a/key_protocol/src/key_management/mod.rs b/key_protocol/src/key_management/mod.rs index 5650fd5..f22a99f 100644 --- a/key_protocol/src/key_management/mod.rs +++ b/key_protocol/src/key_management/mod.rs @@ -55,6 +55,7 @@ impl KeyChain { #[cfg(test)] mod tests { use aes_gcm::aead::OsRng; + use base58::ToBase58; use k256::AffinePoint; use k256::elliptic_curve::group::GroupEncoding; use rand::RngCore; @@ -119,7 +120,7 @@ mod tests { println!("======Public data======"); println!(); - println!("Address{:?}", hex::encode(address.value())); + println!("Address{:?}", address.value().to_base58()); println!( "Nulifier public key {:?}", hex::encode(nullifer_public_key.to_byte_array()) diff --git a/nssa/core/Cargo.toml b/nssa/core/Cargo.toml index e1951c4..5712eaf 100644 --- a/nssa/core/Cargo.toml +++ b/nssa/core/Cargo.toml @@ -10,8 +10,9 @@ thiserror = { version = "2.0.12", optional = true } bytemuck = { version = "1.13", optional = true } chacha20 = { version = "0.9", default-features = false } k256 = { version = "0.13.3", optional = true } -hex = { version = "0.4.3", optional = true } +base58 = { version = "0.2.0", optional = true } +anyhow = { version = "1.0.98", optional = true } [features] default = [] -host = ["thiserror", "bytemuck", "k256", "hex"] +host = ["thiserror", "bytemuck", "k256", "base58", "anyhow"] diff --git a/nssa/core/src/address.rs b/nssa/core/src/address.rs index 2627368..774145e 100644 --- a/nssa/core/src/address.rs +++ b/nssa/core/src/address.rs @@ -3,6 +3,9 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "host")] use std::{fmt::Display, str::FromStr}; +#[cfg(feature = "host")] +use base58::{FromBase58, ToBase58}; + #[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] #[cfg_attr( any(feature = "host", test), @@ -31,8 +34,8 @@ impl AsRef<[u8]> for Address { #[cfg(feature = "host")] #[derive(Debug, thiserror::Error)] pub enum AddressError { - #[error("invalid hex")] - InvalidHex(#[from] hex::FromHexError), + #[error("invalid base58")] + InvalidBase58(#[from] anyhow::Error), #[error("invalid length: expected 32 bytes, got {0}")] InvalidLength(usize), } @@ -41,7 +44,9 @@ pub enum AddressError { impl FromStr for Address { type Err = AddressError; fn from_str(s: &str) -> Result { - let bytes = hex::decode(s)?; + let bytes = s + .from_base58() + .map_err(|err| anyhow::anyhow!("Invalid base58 err {err:?}"))?; if bytes.len() != 32 { return Err(AddressError::InvalidLength(bytes.len())); } @@ -54,7 +59,7 @@ impl FromStr for Address { #[cfg(feature = "host")] impl Display for Address { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", hex::encode(self.value)) + write!(f, "{}", self.value.to_base58()) } } @@ -74,7 +79,7 @@ mod tests { fn parse_invalid_hex() { let hex_str = "zz".repeat(32); // invalid hex chars let result = hex_str.parse::
().unwrap_err(); - assert!(matches!(result, AddressError::InvalidHex(_))); + assert!(matches!(result, AddressError::InvalidBase58(_))); } #[test] diff --git a/sequencer_core/Cargo.toml b/sequencer_core/Cargo.toml index 72a8cc4..6e9979c 100644 --- a/sequencer_core/Cargo.toml +++ b/sequencer_core/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] -hex.workspace = true +base58.workspace = true anyhow.workspace = true serde.workspace = true rand.workspace = true diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 92d53e7..98ff16d 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -204,6 +204,7 @@ impl SequencerCore { #[cfg(test)] mod tests { + use base58::{FromBase58, ToBase58}; use common::test_utils::sequencer_sign_key_for_testing; use crate::config::AccountInitialData; @@ -237,23 +238,23 @@ mod tests { } fn setup_sequencer_config() -> SequencerConfig { - let acc1_addr = vec![ + let acc1_addr: Vec = vec![ 208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9, 115, 84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68, ]; - let acc2_addr = vec![ + let acc2_addr: Vec = vec![ 231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57, 141, 98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188, ]; let initial_acc1 = AccountInitialData { - addr: hex::encode(acc1_addr), + addr: acc1_addr.to_base58(), balance: 10000, }; let initial_acc2 = AccountInitialData { - addr: hex::encode(acc2_addr), + addr: acc2_addr.to_base58(), balance: 20000, }; @@ -288,11 +289,17 @@ mod tests { assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10); assert_eq!(sequencer.sequencer_config.port, 8080); - let acc1_addr = hex::decode(config.initial_accounts[0].addr.clone()) + let acc1_addr = config.initial_accounts[0] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); - let acc2_addr = hex::decode(config.initial_accounts[1].addr.clone()) + let acc2_addr = config.initial_accounts[1] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); @@ -314,23 +321,23 @@ mod tests { #[test] fn test_start_different_intial_accounts_balances() { - let acc1_addr = vec![ + let acc1_addr: Vec = vec![ 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143, ]; - let acc2_addr = vec![ + let acc2_addr: Vec = vec![ 77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234, 216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102, ]; let initial_acc1 = AccountInitialData { - addr: hex::encode(acc1_addr), + addr: acc1_addr.to_base58(), balance: 10000, }; let initial_acc2 = AccountInitialData { - addr: hex::encode(acc2_addr), + addr: acc2_addr.to_base58(), balance: 20000, }; @@ -339,11 +346,17 @@ mod tests { let config = setup_sequencer_config_variable_initial_accounts(initial_accounts); let sequencer = SequencerCore::start_from_config(config.clone()); - let acc1_addr = hex::decode(config.initial_accounts[0].addr.clone()) + let acc1_addr = config.initial_accounts[0] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); - let acc2_addr = hex::decode(config.initial_accounts[1].addr.clone()) + let acc2_addr = config.initial_accounts[1] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); @@ -386,11 +399,17 @@ mod tests { common_setup(&mut sequencer); - let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone()) + let acc1 = sequencer.sequencer_config.initial_accounts[0] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); - let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone()) + let acc2 = sequencer.sequencer_config.initial_accounts[1] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); @@ -412,11 +431,17 @@ mod tests { common_setup(&mut sequencer); - let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone()) + let acc1 = sequencer.sequencer_config.initial_accounts[0] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); - let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone()) + let acc2 = sequencer.sequencer_config.initial_accounts[1] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); @@ -448,11 +473,17 @@ mod tests { common_setup(&mut sequencer); - let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone()) + let acc1 = sequencer.sequencer_config.initial_accounts[0] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); - let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone()) + let acc2 = sequencer.sequencer_config.initial_accounts[1] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); @@ -484,11 +515,17 @@ mod tests { common_setup(&mut sequencer); - let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone()) + let acc1 = sequencer.sequencer_config.initial_accounts[0] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); - let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone()) + let acc2 = sequencer.sequencer_config.initial_accounts[1] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); @@ -576,11 +613,17 @@ mod tests { common_setup(&mut sequencer); - let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone()) + let acc1 = sequencer.sequencer_config.initial_accounts[0] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); - let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone()) + let acc2 = sequencer.sequencer_config.initial_accounts[1] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); @@ -618,11 +661,17 @@ mod tests { common_setup(&mut sequencer); - let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone()) + let acc1 = sequencer.sequencer_config.initial_accounts[0] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); - let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone()) + let acc2 = sequencer.sequencer_config.initial_accounts[1] + .addr + .clone() + .from_base58() .unwrap() .try_into() .unwrap(); diff --git a/sequencer_rpc/Cargo.toml b/sequencer_rpc/Cargo.toml index af7e011..557ce6a 100644 --- a/sequencer_rpc/Cargo.toml +++ b/sequencer_rpc/Cargo.toml @@ -10,7 +10,8 @@ log.workspace = true serde.workspace = true actix-cors.workspace = true futures.workspace = true -hex.workspace = true +base58.workspace = true +hex = "0.4.3" tempfile.workspace = true base64.workspace = true diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index cb49d58..faf71ef 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use actix_web::Error as HttpError; +use base58::FromBase58; use base64::{Engine, engine::general_purpose}; use nssa::{self, program::Program}; use sequencer_core::config::AccountInitialData; @@ -163,8 +164,10 @@ impl JsonHandler { /// The address must be a valid hex string of the correct length. async fn process_get_account_balance(&self, request: Request) -> Result { let get_account_req = GetAccountBalanceRequest::parse(Some(request.params))?; - let address_bytes = hex::decode(get_account_req.address) - .map_err(|_| RpcError::invalid_params("invalid hex".to_string()))?; + let address_bytes = get_account_req + .address + .from_base58() + .map_err(|_| RpcError::invalid_params("invalid base58".to_string()))?; let address = nssa::Address::new( address_bytes .try_into() @@ -312,6 +315,7 @@ mod tests { use std::sync::Arc; use crate::{JsonHandler, rpc_handler}; + use base58::ToBase58; use base64::{Engine, engine::general_purpose}; use common::{ rpc_primitives::RpcPollingConfig, test_utils::sequencer_sign_key_for_testing, @@ -329,23 +333,23 @@ mod tests { fn sequencer_config_for_tests() -> SequencerConfig { let tempdir = tempdir().unwrap(); let home = tempdir.path().to_path_buf(); - let acc1_addr = vec![ + let acc1_addr: Vec = vec![ 208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9, 115, 84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68, ]; - let acc2_addr = vec![ + let acc2_addr: Vec = vec![ 231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57, 141, 98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188, ]; let initial_acc1 = AccountInitialData { - addr: hex::encode(acc1_addr), + addr: acc1_addr.to_base58(), balance: 10000, }; let initial_acc2 = AccountInitialData { - addr: hex::encode(acc2_addr), + addr: acc2_addr.to_base58(), balance: 20000, }; diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 48d79e2..b04d67e 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -16,7 +16,8 @@ nssa-core = { path = "../nssa/core" } base64.workspace = true bytemuck = "1.23.2" borsh.workspace = true -hex.workspace = true +base58.workspace = true +hex = "0.4.3" rand.workspace = true [dependencies.key_protocol] diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index 9ec4b20..f801e30 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -1,6 +1,7 @@ use std::str::FromStr; use anyhow::Result; +use base58::ToBase58; use clap::Subcommand; use common::transaction::NSSATransaction; use nssa::Address; @@ -18,9 +19,9 @@ pub enum AccountSubcommand { ///Fetch #[command(subcommand)] Fetch(FetchSubcommand), - ///Register + ///New #[command(subcommand)] - Register(RegisterSubcommand), + New(NewSubcommand), } ///Represents generic getter CLI subcommand @@ -72,7 +73,7 @@ pub enum FetchSubcommand { ///Represents generic register CLI subcommand #[derive(Subcommand, Debug, Clone)] -pub enum RegisterSubcommand { +pub enum NewSubcommand { ///Register new public account Public {}, ///Register new private account @@ -190,13 +191,13 @@ impl WalletSubcommand for FetchSubcommand { } } -impl WalletSubcommand for RegisterSubcommand { +impl WalletSubcommand for NewSubcommand { async fn handle_subcommand( self, wallet_core: &mut WalletCore, ) -> Result { match self { - RegisterSubcommand::Public {} => { + NewSubcommand::Public {} => { let addr = wallet_core.create_new_account_public(); println!("Generated new account with addr {addr}"); @@ -207,7 +208,7 @@ impl WalletSubcommand for RegisterSubcommand { Ok(SubcommandReturnValue::RegisterAccount { addr }) } - RegisterSubcommand::Private {} => { + NewSubcommand::Private {} => { let addr = wallet_core.create_new_account_private(); let (key, _) = wallet_core @@ -216,8 +217,8 @@ impl WalletSubcommand for RegisterSubcommand { .get_private_account(&addr) .unwrap(); - println!("Generated new account with addr {addr}"); - println!("With npk {}", hex::encode(&key.nullifer_public_key)); + println!("Generated new account with addr {}", addr.to_bytes().to_base58()); + println!("With npk {}", hex::encode(&key.nullifer_public_key.0)); println!( "With ipk {}", hex::encode(key.incoming_viewing_public_key.to_bytes()) @@ -245,8 +246,8 @@ impl WalletSubcommand for AccountSubcommand { AccountSubcommand::Fetch(fetch_subcommand) => { fetch_subcommand.handle_subcommand(wallet_core).await } - AccountSubcommand::Register(register_subcommand) => { - register_subcommand.handle_subcommand(wallet_core).await + AccountSubcommand::New(new_subcommand) => { + new_subcommand.handle_subcommand(wallet_core).await } } } diff --git a/wallet/src/cli/chain.rs b/wallet/src/cli/chain.rs index 4db18fc..aec2c9a 100644 --- a/wallet/src/cli/chain.rs +++ b/wallet/src/cli/chain.rs @@ -6,12 +6,12 @@ use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand}; ///Represents generic chain CLI subcommand #[derive(Subcommand, Debug, Clone)] pub enum ChainSubcommand { - GetLatestBlockId {}, - GetBlockAtId { + CurrentBlockId {}, + Block { #[arg(short, long)] id: u64, }, - GetTransactionAtHash { + Transaction { #[arg(short, long)] hash: String, }, @@ -23,17 +23,17 @@ impl WalletSubcommand for ChainSubcommand { wallet_core: &mut WalletCore, ) -> Result { match self { - ChainSubcommand::GetLatestBlockId {} => { + ChainSubcommand::CurrentBlockId {} => { let latest_block_res = wallet_core.sequencer_client.get_last_block().await?; println!("Last block id is {}", latest_block_res.last_block); } - ChainSubcommand::GetBlockAtId { id } => { + ChainSubcommand::Block { id } => { let block_res = wallet_core.sequencer_client.get_block(id).await?; println!("Last block id is {:#?}", block_res.block); } - ChainSubcommand::GetTransactionAtHash { hash } => { + ChainSubcommand::Transaction { hash } => { let tx_res = wallet_core .sequencer_client .get_transaction_by_hash(hash) diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 833422f..5de7f5d 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -193,19 +193,19 @@ impl WalletCore { pub enum Command { ///Transfer command #[command(subcommand)] - Transfer(NativeTokenTransferProgramSubcommand), + AuthTransfer(NativeTokenTransferProgramSubcommand), ///Chain command #[command(subcommand)] - Chain(ChainSubcommand), + ChainInfo(ChainSubcommand), ///Chain command #[command(subcommand)] Account(AccountSubcommand), ///Pinata command #[command(subcommand)] - PinataProgram(PinataProgramSubcommand), + Pinata(PinataProgramSubcommand), ///Token command #[command(subcommand)] - TokenProgram(TokenProgramSubcommand), + Token(TokenProgramSubcommand), AuthenticatedTransferInitializePublicAccount {}, // Check the wallet can connect to the node and builtin local programs // match the remote versions @@ -237,12 +237,12 @@ pub async fn execute_subcommand(command: Command) -> Result { + Command::AuthTransfer(transfer_subcommand) => { transfer_subcommand .handle_subcommand(&mut wallet_core) .await? } - Command::Chain(chain_subcommand) => { + Command::ChainInfo(chain_subcommand) => { chain_subcommand.handle_subcommand(&mut wallet_core).await? } Command::Account(account_subcommand) => { @@ -250,7 +250,7 @@ pub async fn execute_subcommand(command: Command) -> Result { + Command::Pinata(pinata_subcommand) => { pinata_subcommand .handle_subcommand(&mut wallet_core) .await? @@ -304,7 +304,7 @@ pub async fn execute_subcommand(command: Command) -> Result { + Command::Token(token_subcommand) => { token_subcommand.handle_subcommand(&mut wallet_core).await? } }; From 0384efc38f9296e0a7af4406a0a392a5976e79d3 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Fri, 24 Oct 2025 11:12:32 +0300 Subject: [PATCH 02/10] fix: base58 adoption fixes --- .../debug/sequencer/sequencer_config.json | 126 +-- .../configs/debug/wallet/wallet_config.json | 858 +++++++++--------- integration_tests/src/lib.rs | 10 +- integration_tests/src/test_suite_map.rs | 28 +- key_protocol/src/key_protocol_core/mod.rs | 5 + nssa/core/src/address.rs | 18 +- sequencer_core/src/sequencer_store/mod.rs | 4 +- sequencer_rpc/src/process.rs | 12 +- wallet/src/chain_storage/mod.rs | 88 +- wallet/src/cli/account.rs | 5 +- 10 files changed, 618 insertions(+), 536 deletions(-) diff --git a/integration_tests/configs/debug/sequencer/sequencer_config.json b/integration_tests/configs/debug/sequencer/sequencer_config.json index 2a2037d..beb39cb 100644 --- a/integration_tests/configs/debug/sequencer/sequencer_config.json +++ b/integration_tests/configs/debug/sequencer/sequencer_config.json @@ -8,49 +8,49 @@ "port": 3040, "initial_accounts": [ { - "addr": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44", + "addr": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", "balance": 10000 }, { - "addr": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc", + "addr": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", "balance": 20000 } ], "initial_commitments": [ { "npk": [ - 193, - 209, - 150, - 113, - 47, - 241, - 48, - 145, - 250, - 79, - 235, - 51, - 119, - 40, - 184, - 232, - 5, + 63, + 202, + 178, + 231, + 183, + 82, + 237, + 212, + 216, 221, - 36, - 21, - 201, - 106, - 90, - 210, - 129, - 106, - 71, - 99, - 208, + 215, + 255, 153, - 75, - 215 + 101, + 177, + 161, + 254, + 210, + 128, + 122, + 54, + 190, + 230, + 151, + 183, + 64, + 225, + 229, + 113, + 1, + 228, + 97 ], "account": { "program_owner": [ @@ -70,38 +70,38 @@ }, { "npk": [ - 27, - 250, + 192, + 251, + 166, + 243, + 167, + 236, + 84, + 249, + 35, 136, - 142, - 88, - 128, - 138, - 21, - 49, - 183, - 118, - 160, - 117, - 114, - 110, - 47, - 136, - 87, - 60, - 70, - 59, - 60, - 18, - 223, - 23, - 147, - 241, - 5, - 184, - 103, + 130, + 172, + 219, 225, - 105 + 161, + 139, + 229, + 89, + 243, + 125, + 194, + 213, + 209, + 30, + 23, + 174, + 100, + 244, + 124, + 74, + 140, + 47 ], "account": { "program_owner": [ @@ -154,4 +154,4 @@ 37, 37 ] -} +} \ No newline at end of file diff --git a/integration_tests/configs/debug/wallet/wallet_config.json b/integration_tests/configs/debug/wallet/wallet_config.json index 0081da6..95c95e9 100644 --- a/integration_tests/configs/debug/wallet/wallet_config.json +++ b/integration_tests/configs/debug/wallet/wallet_config.json @@ -9,85 +9,85 @@ "initial_accounts": [ { "Public": { - "address": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44", + "address": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", "pub_sign_key": [ - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1 + 16, + 162, + 106, + 154, + 236, + 125, + 52, + 184, + 35, + 100, + 238, + 174, + 69, + 197, + 41, + 77, + 187, + 10, + 118, + 75, + 0, + 11, + 148, + 238, + 185, + 181, + 133, + 17, + 220, + 72, + 124, + 77 ] } }, { "Public": { - "address": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc", + "address": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", "pub_sign_key": [ - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2 + 113, + 121, + 64, + 177, + 204, + 85, + 229, + 214, + 178, + 6, + 109, + 191, + 29, + 154, + 63, + 38, + 242, + 18, + 244, + 219, + 8, + 208, + 35, + 136, + 23, + 127, + 207, + 237, + 216, + 169, + 190, + 27 ] } }, { "Private": { - "address": "d360d6b5763f71ac6af56253687fd7d556d5c6c64312e53c0b92ef039a4375df", + "address": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw", "account": { "program_owner": [ 0, @@ -105,218 +105,218 @@ }, "key_chain": { "secret_spending_key": [ - 10, - 125, - 171, - 38, - 201, - 35, - 164, - 43, - 7, - 80, - 7, - 215, - 97, - 42, - 48, - 229, - 101, - 216, - 140, - 21, - 170, - 214, + 251, 82, - 53, + 235, + 1, + 146, + 96, + 30, + 81, + 162, + 234, + 33, + 15, + 123, + 129, 116, - 22, - 62, - 79, - 61, - 76, - 71, - 79 + 0, + 84, + 136, + 176, + 70, + 190, + 224, + 161, + 54, + 134, + 142, + 154, + 1, + 18, + 251, + 242, + 189 ], "private_key_holder": { "nullifier_secret_key": [ - 228, - 136, - 4, + 29, + 250, + 10, + 187, + 35, + 123, + 180, + 250, + 246, + 97, + 216, + 153, + 44, 156, - 33, - 40, - 194, - 172, - 95, - 168, - 201, - 33, - 24, - 30, - 126, - 197, - 156, - 113, - 64, - 162, - 131, - 210, - 110, - 60, - 24, - 154, - 86, - 59, - 184, - 95, - 245, - 176 + 16, + 93, + 241, + 26, + 174, + 219, + 72, + 84, + 34, + 247, + 112, + 101, + 217, + 243, + 189, + 173, + 75, + 20 ], "incoming_viewing_secret_key": [ - 197, - 33, - 51, - 200, - 1, - 121, - 60, - 52, - 233, - 234, - 12, - 166, - 196, - 227, - 187, - 1, - 10, - 101, - 183, - 105, - 140, - 28, - 152, + 251, + 201, + 22, + 154, + 100, + 165, + 218, + 108, + 163, + 190, + 135, + 91, + 145, + 84, + 69, + 241, + 46, + 117, 217, - 109, - 220, - 112, - 103, - 253, 110, - 98, - 6 + 197, + 248, + 91, + 193, + 14, + 104, + 88, + 103, + 67, + 153, + 182, + 158 ], "outgoing_viewing_secret_key": [ - 147, - 34, - 193, - 29, - 39, - 173, - 222, + 25, + 67, + 121, + 76, + 175, + 100, 30, - 118, - 199, - 44, - 204, - 43, - 232, - 107, - 223, - 249, - 207, - 245, - 183, - 63, - 209, - 129, - 48, - 254, - 66, - 22, - 199, - 81, - 145, - 126, - 92 + 198, + 105, + 123, + 49, + 169, + 75, + 178, + 75, + 210, + 100, + 143, + 210, + 243, + 228, + 243, + 21, + 18, + 36, + 84, + 164, + 186, + 139, + 113, + 214, + 12 ] }, "nullifer_public_key": [ - 193, - 209, - 150, - 113, - 47, - 241, - 48, - 145, - 250, - 79, - 235, - 51, - 119, - 40, - 184, - 232, - 5, + 63, + 202, + 178, + 231, + 183, + 82, + 237, + 212, + 216, 221, - 36, - 21, - 201, - 106, - 90, - 210, - 129, - 106, - 71, - 99, - 208, + 215, + 255, 153, - 75, - 215 + 101, + 177, + 161, + 254, + 210, + 128, + 122, + 54, + 190, + 230, + 151, + 183, + 64, + 225, + 229, + 113, + 1, + 228, + 97 ], "incoming_viewing_public_key": [ 3, - 78, + 235, + 139, + 131, + 237, 177, - 87, - 193, - 219, - 230, - 160, - 222, - 38, - 182, - 100, - 101, - 223, - 204, - 223, - 198, - 140, - 253, - 94, - 16, - 98, - 77, - 79, - 114, - 30, - 158, - 104, - 34, - 152, + 122, 189, - 31, - 95 + 6, + 177, + 167, + 178, + 202, + 117, + 246, + 58, + 28, + 65, + 132, + 79, + 220, + 139, + 119, + 243, + 187, + 160, + 212, + 121, + 61, + 247, + 116, + 72, + 205 ] } } }, { "Private": { - "address": "f27087ffc29b99035303697dcf6c8e323b1847d4261e6afd49e0d71c6dfa31ea", + "address": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX", "account": { "program_owner": [ 0, @@ -334,214 +334,214 @@ }, "key_chain": { "secret_spending_key": [ - 153, - 109, - 202, - 226, - 97, - 212, - 77, - 147, - 75, - 107, - 153, - 106, - 89, - 167, - 49, - 230, - 122, + 238, + 171, + 241, + 69, + 111, + 217, + 85, + 64, + 19, + 82, + 18, + 189, + 32, + 91, 78, - 167, - 146, - 14, - 180, - 206, + 175, 107, - 96, - 193, - 255, - 122, - 207, - 30, - 142, - 99 + 7, + 109, + 60, + 52, + 44, + 243, + 230, + 72, + 244, + 192, + 92, + 137, + 33, + 118, + 254 ], "private_key_holder": { "nullifier_secret_key": [ - 128, + 25, + 211, 215, - 147, - 175, 119, - 16, - 140, - 219, - 155, - 134, - 27, - 81, - 64, - 40, - 196, - 240, - 61, - 144, - 232, - 164, - 181, 57, - 139, - 96, - 137, - 121, - 140, + 223, + 247, + 37, + 245, + 144, + 122, 29, - 169, - 68, - 187, - 65 + 118, + 245, + 83, + 228, + 23, + 9, + 101, + 120, + 88, + 33, + 238, + 207, + 128, + 61, + 110, + 2, + 89, + 62, + 164, + 13 ], "incoming_viewing_secret_key": [ - 185, - 121, - 146, - 213, - 13, - 3, - 93, - 206, - 25, - 127, - 155, - 21, - 155, - 115, + 193, + 181, + 14, + 196, + 142, + 84, + 15, + 65, + 128, + 101, + 70, + 196, + 241, + 47, 130, - 27, - 57, - 5, - 116, - 80, - 62, - 214, - 67, - 228, - 147, - 189, - 28, - 200, - 62, - 152, - 178, - 103 + 221, + 23, + 146, + 161, + 237, + 221, + 40, + 19, + 126, + 59, + 15, + 169, + 236, + 25, + 105, + 104, + 231 ], "outgoing_viewing_secret_key": [ - 163, - 58, - 118, - 160, + 20, + 170, + 220, + 108, + 41, + 23, + 155, + 217, + 247, + 190, 175, - 86, - 72, + 168, + 247, + 34, + 105, + 134, + 114, + 74, + 104, 91, - 81, - 69, - 150, - 154, - 113, 211, - 118, - 110, - 25, - 156, - 250, - 67, - 212, - 198, - 147, - 231, - 213, - 136, - 212, - 198, - 192, - 255, + 62, 126, - 122 + 13, + 130, + 100, + 241, + 214, + 250, + 236, + 38, + 150 ] }, "nullifer_public_key": [ - 27, - 250, + 192, + 251, + 166, + 243, + 167, + 236, + 84, + 249, + 35, 136, - 142, - 88, - 128, - 138, - 21, - 49, - 183, - 118, - 160, - 117, - 114, - 110, - 47, - 136, - 87, - 60, - 70, - 59, - 60, - 18, - 223, - 23, - 147, - 241, - 5, - 184, - 103, + 130, + 172, + 219, 225, - 105 + 161, + 139, + 229, + 89, + 243, + 125, + 194, + 213, + 209, + 30, + 23, + 174, + 100, + 244, + 124, + 74, + 140, + 47 ], "incoming_viewing_public_key": [ 2, - 56, - 160, - 1, - 22, - 197, - 187, - 214, - 204, - 221, - 84, - 87, - 12, - 204, - 0, - 119, - 116, - 176, - 6, - 149, - 145, - 100, - 211, - 162, - 19, - 158, - 197, - 112, - 142, - 172, - 1, + 181, 98, - 226 + 93, + 216, + 241, + 241, + 110, + 58, + 198, + 119, + 174, + 250, + 184, + 1, + 204, + 200, + 173, + 44, + 238, + 37, + 247, + 170, + 156, + 100, + 254, + 116, + 242, + 28, + 183, + 187, + 77, + 255 ] } } } ] -} +} \ No newline at end of file diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index bbd5066..5b21057 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -32,13 +32,11 @@ struct Args { test_name: String, } -pub const ACC_SENDER: &str = "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44"; -pub const ACC_RECEIVER: &str = "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc"; +pub const ACC_SENDER: &str = "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy"; +pub const ACC_RECEIVER: &str = "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw"; -pub const ACC_SENDER_PRIVATE: &str = - "d360d6b5763f71ac6af56253687fd7d556d5c6c64312e53c0b92ef039a4375df"; -pub const ACC_RECEIVER_PRIVATE: &str = - "f27087ffc29b99035303697dcf6c8e323b1847d4261e6afd49e0d71c6dfa31ea"; +pub const ACC_SENDER_PRIVATE: &str = "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw"; +pub const ACC_RECEIVER_PRIVATE: &str = "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX"; pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12; diff --git a/integration_tests/src/test_suite_map.rs b/integration_tests/src/test_suite_map.rs index 80bf894..67d78e8 100644 --- a/integration_tests/src/test_suite_map.rs +++ b/integration_tests/src/test_suite_map.rs @@ -25,6 +25,8 @@ use wallet::{ helperfunctions::{fetch_config, fetch_persistent_accounts}, }; +use sequencer_core::sequencer_store::PINATA_BASE58; + use crate::{ ACC_RECEIVER, ACC_RECEIVER_PRIVATE, ACC_SENDER, ACC_SENDER_PRIVATE, NSSA_PROGRAM_FOR_TEST_DATA_CHANGER, TIME_TO_WAIT_FOR_BLOCK_SECONDS, @@ -1315,12 +1317,12 @@ pub fn prepare_function_map() -> HashMap { #[test_suite_fn] pub async fn test_pinata() { info!("test_pinata"); - let pinata_addr = "cafe".repeat(16); + let pinata_addr = PINATA_BASE58; let pinata_prize = 150; let solution = 989106; let command = Command::Pinata(PinataProgramSubcommand::Public( PinataProgramSubcommandPublic::Claim { - pinata_addr: pinata_addr.clone(), + pinata_addr: pinata_addr.to_string(), winner_addr: ACC_SENDER.to_string(), solution, }, @@ -1331,7 +1333,7 @@ pub fn prepare_function_map() -> HashMap { let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); let pinata_balance_pre = seq_client - .get_account_balance(pinata_addr.clone()) + .get_account_balance(pinata_addr.to_string()) .await .unwrap() .balance; @@ -1343,7 +1345,7 @@ pub fn prepare_function_map() -> HashMap { info!("Checking correct balance move"); let pinata_balance_post = seq_client - .get_account_balance(pinata_addr.clone()) + .get_account_balance(pinata_addr.to_string()) .await .unwrap() .balance; @@ -1379,7 +1381,7 @@ pub fn prepare_function_map() -> HashMap { // 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 address: Address = "11".repeat(16).parse().unwrap(); let message = nssa::public_transaction::Message::try_new( data_changer.id(), vec![address], @@ -1442,13 +1444,13 @@ pub fn prepare_function_map() -> HashMap { #[test_suite_fn] pub async fn test_pinata_private_receiver() { info!("test_pinata_private_receiver"); - let pinata_addr = "cafe".repeat(16); + let pinata_addr = PINATA_BASE58; let pinata_prize = 150; let solution = 989106; let command = Command::Pinata(PinataProgramSubcommand::Private( PinataProgramSubcommandPrivate::ClaimPrivateOwned { - pinata_addr: pinata_addr.clone(), + pinata_addr: pinata_addr.to_string(), winner_addr: ACC_SENDER_PRIVATE.to_string(), solution, }, @@ -1459,7 +1461,7 @@ pub fn prepare_function_map() -> HashMap { let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); let pinata_balance_pre = seq_client - .get_account_balance(pinata_addr.clone()) + .get_account_balance(pinata_addr.to_string()) .await .unwrap() .balance; @@ -1475,7 +1477,7 @@ pub fn prepare_function_map() -> HashMap { info!("Checking correct balance move"); let pinata_balance_post = seq_client - .get_account_balance(pinata_addr.clone()) + .get_account_balance(pinata_addr.to_string()) .await .unwrap() .balance; @@ -1506,7 +1508,7 @@ pub fn prepare_function_map() -> HashMap { #[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_addr = PINATA_BASE58; let pinata_prize = 150; let solution = 989106; @@ -1523,7 +1525,7 @@ pub fn prepare_function_map() -> HashMap { let command = Command::Pinata(PinataProgramSubcommand::Private( PinataProgramSubcommandPrivate::ClaimPrivateOwned { - pinata_addr: pinata_addr.clone(), + pinata_addr: pinata_addr.to_string(), winner_addr: winner_addr.to_string(), solution, }, @@ -1534,7 +1536,7 @@ pub fn prepare_function_map() -> HashMap { let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); let pinata_balance_pre = seq_client - .get_account_balance(pinata_addr.clone()) + .get_account_balance(pinata_addr.to_string()) .await .unwrap() .balance; @@ -1546,7 +1548,7 @@ pub fn prepare_function_map() -> HashMap { info!("Checking correct balance move"); let pinata_balance_post = seq_client - .get_account_balance(pinata_addr.clone()) + .get_account_balance(pinata_addr.to_string()) .await .unwrap() .balance; diff --git a/key_protocol/src/key_protocol_core/mod.rs b/key_protocol/src/key_protocol_core/mod.rs index df5502e..b1ebe71 100644 --- a/key_protocol/src/key_protocol_core/mod.rs +++ b/key_protocol/src/key_protocol_core/mod.rs @@ -142,5 +142,10 @@ mod tests { let is_key_chain_generated = user_data.get_private_account(&addr_private).is_some(); assert!(is_key_chain_generated); + + let addr_private_str = addr_private.to_string(); + println!("{addr_private_str:#?}"); + let key_chain = &user_data.get_private_account(&addr_private).unwrap().0; + println!("{key_chain:#?}"); } } diff --git a/nssa/core/src/address.rs b/nssa/core/src/address.rs index 774145e..6355351 100644 --- a/nssa/core/src/address.rs +++ b/nssa/core/src/address.rs @@ -70,29 +70,29 @@ mod tests { #[test] fn parse_valid_address() { - let hex_str = "00".repeat(32); // 64 hex chars = 32 bytes - let addr: Address = hex_str.parse().unwrap(); + let base58_str = "11111111111111111111111111111111"; + let addr: Address = base58_str.parse().unwrap(); assert_eq!(addr.value, [0u8; 32]); } #[test] - fn parse_invalid_hex() { - let hex_str = "zz".repeat(32); // invalid hex chars - let result = hex_str.parse::
().unwrap_err(); + fn parse_invalid_base58() { + let base58_str = "00".repeat(32); // invalid base58 chars + let result = base58_str.parse::
().unwrap_err(); assert!(matches!(result, AddressError::InvalidBase58(_))); } #[test] fn parse_wrong_length_short() { - let hex_str = "00".repeat(31); // 62 chars = 31 bytes - let result = hex_str.parse::
().unwrap_err(); + let base58_str = "11".repeat(31); // 62 chars = 31 bytes + let result = base58_str.parse::
().unwrap_err(); assert!(matches!(result, AddressError::InvalidLength(_))); } #[test] fn parse_wrong_length_long() { - let hex_str = "00".repeat(33); // 66 chars = 33 bytes - let result = hex_str.parse::
().unwrap_err(); + let base58_str = "11".repeat(33); // 66 chars = 33 bytes + let result = base58_str.parse::
().unwrap_err(); assert!(matches!(result, AddressError::InvalidLength(_))); } } diff --git a/sequencer_core/src/sequencer_store/mod.rs b/sequencer_core/src/sequencer_store/mod.rs index 4f18405..186b266 100644 --- a/sequencer_core/src/sequencer_store/mod.rs +++ b/sequencer_core/src/sequencer_store/mod.rs @@ -9,6 +9,8 @@ use crate::config::AccountInitialData; pub mod block_store; +pub const PINATA_BASE58: &str = "EfQhKQAkX2FJiwNii2WFQsGndjvF1Mzd7RuVe7QdPLw7"; + pub struct SequecerChainStore { pub state: nssa::V02State, pub block_store: SequecerBlockStore, @@ -35,7 +37,7 @@ impl SequecerChainStore { let state = { let mut this = nssa::V02State::new_with_genesis_accounts(&init_accs, initial_commitments); - this.add_pinata_program("cafe".repeat(16).parse().unwrap()); + this.add_pinata_program(PINATA_BASE58.parse().unwrap()); this }; diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 0ff1b00..4147e5c 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -434,7 +434,7 @@ mod tests { let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account_balance", - "params": { "address": "efac".repeat(16) }, + "params": { "address": "11".repeat(16) }, "id": 1 }); let expected_response = serde_json::json!({ @@ -451,12 +451,12 @@ mod tests { } #[actix_web::test] - async fn test_get_account_balance_for_invalid_hex() { + async fn test_get_account_balance_for_invalid_base58() { let (json_handler, _, _) = components_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account_balance", - "params": { "address": "not_a_valid_hex" }, + "params": { "address": "not_a_valid_base58" }, "id": 1 }); let expected_response = serde_json::json!({ @@ -465,7 +465,7 @@ mod tests { "error": { "code": -32602, "message": "Invalid params", - "data": "invalid hex" + "data": "invalid base58" } }); let response = call_rpc_handler_with_json(json_handler, request).await; @@ -527,7 +527,7 @@ mod tests { let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_accounts_nonces", - "params": { "addresses": ["efac".repeat(16)] }, + "params": { "addresses": ["11".repeat(16)] }, "id": 1 }); let expected_response = serde_json::json!({ @@ -575,7 +575,7 @@ mod tests { let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account", - "params": { "address": "efac".repeat(16) }, + "params": { "address": "11".repeat(16) }, "id": 1 }); let expected_response = serde_json::json!({ diff --git a/wallet/src/chain_storage/mod.rs b/wallet/src/chain_storage/mod.rs index e07ba8e..8fc8805 100644 --- a/wallet/src/chain_storage/mod.rs +++ b/wallet/src/chain_storage/mod.rs @@ -75,19 +75,91 @@ mod tests { use tempfile::tempdir; fn create_initial_accounts() -> Vec { - let initial_acc1 = serde_json::from_str(r#"{ + let initial_acc1 = serde_json::from_str( + r#"{ "Public": { - "address": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44", - "pub_sign_key": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + "address": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", + "pub_sign_key": [ + 16, + 162, + 106, + 154, + 236, + 125, + 52, + 184, + 35, + 100, + 238, + 174, + 69, + 197, + 41, + 77, + 187, + 10, + 118, + 75, + 0, + 11, + 148, + 238, + 185, + 181, + 133, + 17, + 220, + 72, + 124, + 77 + ] } - }"#).unwrap(); + }"#, + ) + .unwrap(); - let initial_acc2 = serde_json::from_str(r#"{ + let initial_acc2 = serde_json::from_str( + r#"{ "Public": { - "address": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc", - "pub_sign_key": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] + "address": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", + "pub_sign_key": [ + 113, + 121, + 64, + 177, + 204, + 85, + 229, + 214, + 178, + 6, + 109, + 191, + 29, + 154, + 63, + 38, + 242, + 18, + 244, + 219, + 8, + 208, + 35, + 136, + 23, + 127, + 207, + 237, + 216, + 169, + 190, + 27 + ] } - }"#).unwrap(); + }"#, + ) + .unwrap(); let initial_accounts = vec![initial_acc1, initial_acc2]; diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index f801e30..23758d4 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -217,7 +217,10 @@ impl WalletSubcommand for NewSubcommand { .get_private_account(&addr) .unwrap(); - println!("Generated new account with addr {}", addr.to_bytes().to_base58()); + println!( + "Generated new account with addr {}", + addr.to_bytes().to_base58() + ); println!("With npk {}", hex::encode(&key.nullifer_public_key.0)); println!( "With ipk {}", From 66ee0c54494f2a58b21e3018387d1c44fb221b31 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Fri, 24 Oct 2025 15:26:30 +0300 Subject: [PATCH 03/10] fix: account subcommand updated --- wallet/src/cli/account.rs | 237 +++++++++++++++++++++++----------- wallet/src/helperfunctions.rs | 42 +++++- 2 files changed, 202 insertions(+), 77 deletions(-) diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index 23758d4..d7dac7d 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -1,21 +1,81 @@ -use std::str::FromStr; - use anyhow::Result; use base58::ToBase58; use clap::Subcommand; use common::transaction::NSSATransaction; -use nssa::Address; +use nssa::{Address, program::Program}; +use serde::Serialize; use crate::{ - SubcommandReturnValue, WalletCore, cli::WalletSubcommand, helperfunctions::HumanReadableAccount, + SubcommandReturnValue, WalletCore, + cli::WalletSubcommand, + helperfunctions::{AddressPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix}, }; +const TOKEN_DEFINITION_TYPE: u8 = 0; +const TOKEN_DEFINITION_DATA_SIZE: usize = 23; + +const TOKEN_HOLDING_TYPE: u8 = 1; +const TOKEN_HOLDING_DATA_SIZE: usize = 49; + +struct TokenDefinition { + #[allow(unused)] + account_type: u8, + name: [u8; 6], + total_supply: u128, +} + +struct TokenHolding { + #[allow(unused)] + account_type: u8, + definition_id: Address, + balance: u128, +} + +impl TokenDefinition { + fn parse(data: &[u8]) -> Option { + if data.len() != TOKEN_DEFINITION_DATA_SIZE || data[0] != TOKEN_DEFINITION_TYPE { + None + } else { + let account_type = data[0]; + let name = data[1..7].try_into().unwrap(); + let total_supply = u128::from_le_bytes(data[7..].try_into().unwrap()); + + Some(Self { + account_type, + name, + total_supply, + }) + } + } +} + +impl TokenHolding { + fn parse(data: &[u8]) -> Option { + if data.len() != TOKEN_HOLDING_DATA_SIZE || data[0] != TOKEN_HOLDING_TYPE { + None + } else { + let account_type = data[0]; + let definition_id = Address::new(data[1..33].try_into().unwrap()); + let balance = u128::from_le_bytes(data[33..].try_into().unwrap()); + Some(Self { + definition_id, + balance, + account_type, + }) + } + } +} + ///Represents generic chain CLI subcommand #[derive(Subcommand, Debug, Clone)] pub enum AccountSubcommand { ///Get - #[command(subcommand)] - Get(GetSubcommand), + Get { + #[arg(long)] + raw: bool, + #[arg(short, long)] + addr: String, + }, ///Fetch #[command(subcommand)] Fetch(FetchSubcommand), @@ -24,31 +84,6 @@ pub enum AccountSubcommand { New(NewSubcommand), } -///Represents generic getter CLI subcommand -#[derive(Subcommand, Debug, Clone)] -pub enum GetSubcommand { - ///Get account `addr` balance - PublicAccountBalance { - #[arg(short, long)] - addr: String, - }, - ///Get account `addr` nonce - PublicAccountNonce { - #[arg(short, long)] - addr: String, - }, - ///Get account at address `addr` - PublicAccount { - #[arg(short, long)] - addr: String, - }, - ///Get private account with `addr` from storage - PrivateAccount { - #[arg(short, long)] - addr: String, - }, -} - ///Represents generic getter CLI subcommand #[derive(Subcommand, Debug, Clone)] pub enum FetchSubcommand { @@ -80,49 +115,6 @@ pub enum NewSubcommand { Private {}, } -impl WalletSubcommand for GetSubcommand { - async fn handle_subcommand( - self, - wallet_core: &mut WalletCore, - ) -> Result { - match self { - GetSubcommand::PublicAccountBalance { addr } => { - let addr = Address::from_str(&addr)?; - - let balance = wallet_core.get_account_balance(addr).await?; - println!("Accounts {addr} balance is {balance}"); - - Ok(SubcommandReturnValue::Empty) - } - GetSubcommand::PublicAccountNonce { addr } => { - let addr = Address::from_str(&addr)?; - - let nonce = wallet_core.get_accounts_nonces(vec![addr]).await?[0]; - println!("Accounts {addr} nonce is {nonce}"); - - Ok(SubcommandReturnValue::Empty) - } - GetSubcommand::PublicAccount { addr } => { - let addr: Address = addr.parse()?; - let account = wallet_core.get_account_public(addr).await?; - let account_hr: HumanReadableAccount = account.clone().into(); - println!("{}", serde_json::to_string(&account_hr).unwrap()); - - Ok(SubcommandReturnValue::Account(account)) - } - GetSubcommand::PrivateAccount { addr } => { - let addr: Address = addr.parse()?; - if let Some(account) = wallet_core.get_account_private(&addr) { - println!("{}", serde_json::to_string(&account).unwrap()); - } else { - println!("Private account not found."); - } - Ok(SubcommandReturnValue::Empty) - } - } - } -} - impl WalletSubcommand for FetchSubcommand { async fn handle_subcommand( self, @@ -237,14 +229,107 @@ impl WalletSubcommand for NewSubcommand { } } +#[derive(Debug, Serialize)] +pub struct AuthenticatedTransferAccountView { + pub balance: u128, +} + +impl From for AuthenticatedTransferAccountView { + fn from(value: nssa::Account) -> Self { + Self { + balance: value.balance, + } + } +} + +#[derive(Debug, Serialize)] +pub struct TokedDefinitionAccountView { + pub account_type: String, + pub name: String, + pub total_supply: u128, +} + +impl From for TokedDefinitionAccountView { + fn from(value: TokenDefinition) -> Self { + Self { + account_type: "Token definition".to_string(), + name: hex::encode(value.name), + total_supply: value.total_supply, + } + } +} + +#[derive(Debug, Serialize)] +pub struct TokedHoldingAccountView { + pub account_type: String, + pub definition_id: String, + pub balance: u128, +} + +impl From for TokedHoldingAccountView { + fn from(value: TokenHolding) -> Self { + Self { + account_type: "Token holding".to_string(), + definition_id: value.definition_id.to_string(), + balance: value.balance, + } + } +} + impl WalletSubcommand for AccountSubcommand { async fn handle_subcommand( self, wallet_core: &mut WalletCore, ) -> Result { match self { - AccountSubcommand::Get(get_subcommand) => { - get_subcommand.handle_subcommand(wallet_core).await + AccountSubcommand::Get { raw, addr } => { + let (addr, addr_kind) = parse_addr_with_privacy_prefix(&addr)?; + + let account = match addr_kind { + AddressPrivacyKind::Public => wallet_core.get_account_public(addr).await?, + AddressPrivacyKind::Private => wallet_core + .get_account_private(&addr) + .ok_or(anyhow::anyhow!("Private account not found in storage"))?, + }; + + if raw { + let account_hr: HumanReadableAccount = account.clone().into(); + println!("{}", serde_json::to_string(&account_hr).unwrap()); + + return Ok(SubcommandReturnValue::Empty); + } + + let auth_tr_prog_id = Program::authenticated_transfer_program().id(); + let token_prog_id = Program::token().id(); + + let acc_view = match &account.program_owner { + _ if &account.program_owner == &auth_tr_prog_id => { + let acc_view: AuthenticatedTransferAccountView = account.into(); + + serde_json::to_string(&acc_view)? + } + _ if &account.program_owner == &token_prog_id => { + if let Some(token_def) = TokenDefinition::parse(&account.data) { + let acc_view: TokedDefinitionAccountView = token_def.into(); + + serde_json::to_string(&acc_view)? + } else if let Some(token_hold) = TokenHolding::parse(&account.data) { + let acc_view: TokedHoldingAccountView = token_hold.into(); + + serde_json::to_string(&acc_view)? + } else { + anyhow::bail!("Invalid data for account {addr:#?} with token program"); + } + } + _ => { + let account_hr: HumanReadableAccount = account.clone().into(); + serde_json::to_string(&account_hr).unwrap() + } + }; + + println!("{}", acc_view); + + Ok(SubcommandReturnValue::Empty) } AccountSubcommand::Fetch(fetch_subcommand) => { fetch_subcommand.handle_subcommand(wallet_core).await diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index a67b8ec..fcc838b 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -6,7 +6,7 @@ use tokio::io::AsyncReadExt; use anyhow::Result; use key_protocol::key_protocol_core::NSSAUserData; -use nssa::Account; +use nssa::{Account, Address}; use serde::Serialize; use crate::{ @@ -86,6 +86,30 @@ pub(crate) fn produce_random_nonces(size: usize) -> Vec { result.into_iter().map(Nonce::from_le_bytes).collect() } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AddressPrivacyKind { + Public, + Private, +} + +pub(crate) fn parse_addr_with_privacy_prefix( + addr_base58: &str, +) -> Result<(Address, AddressPrivacyKind)> { + if addr_base58.starts_with("Public/") { + Ok(( + addr_base58.strip_prefix("Public/").unwrap().parse()?, + AddressPrivacyKind::Public, + )) + } else if addr_base58.starts_with("Private/") { + Ok(( + addr_base58.strip_prefix("Private/").unwrap().parse()?, + AddressPrivacyKind::Private, + )) + } else { + anyhow::bail!("Unsupported privacy kind, available variants is Public/ and Private/"); + } +} + /// Human-readable representation of an account. #[derive(Serialize)] pub(crate) struct HumanReadableAccount { @@ -126,4 +150,20 @@ mod tests { std::env::remove_var(HOME_DIR_ENV_VAR); } } + + #[test] + fn test_addr_parse_with_privacy() { + let addr_base58 = "Public/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy"; + let (_, addr_kind) = parse_addr_with_privacy_prefix(addr_base58).unwrap(); + + assert_eq!(addr_kind, AddressPrivacyKind::Public); + + let addr_base58 = "Private/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy"; + let (_, addr_kind) = parse_addr_with_privacy_prefix(addr_base58).unwrap(); + + assert_eq!(addr_kind, AddressPrivacyKind::Private); + + let addr_base58 = "asdsada/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy"; + assert!(parse_addr_with_privacy_prefix(addr_base58).is_err()); + } } From 62668161b223129f047de58267be2606d7eff17a Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Mon, 27 Oct 2025 14:32:28 +0200 Subject: [PATCH 04/10] feat: transfers changes --- integration_tests/src/lib.rs | 8 + integration_tests/src/test_suite_map.rs | 351 +++++++++--------- wallet/src/cli/account.rs | 11 +- .../src/cli/native_token_transfer_program.rs | 182 ++++++++- wallet/src/cli/token_program.rs | 182 ++++++++- wallet/src/lib.rs | 9 +- wallet/src/transaction_utils.rs | 49 +++ 7 files changed, 614 insertions(+), 178 deletions(-) diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index 5b21057..f09d808 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -42,6 +42,14 @@ pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12; pub const NSSA_PROGRAM_FOR_TEST_DATA_CHANGER: &[u8] = include_bytes!("data_changer.bin"); +fn make_public_account_input_from_str(addr: &str) -> String { + format!("Public/{addr:?}") +} + +fn make_private_account_input_from_str(addr: &str) -> String { + format!("Private/{addr:?}") +} + #[allow(clippy::type_complexity)] pub async fn pre_test( home_dir: PathBuf, diff --git a/integration_tests/src/test_suite_map.rs b/integration_tests/src/test_suite_map.rs index 67d78e8..7874b5c 100644 --- a/integration_tests/src/test_suite_map.rs +++ b/integration_tests/src/test_suite_map.rs @@ -8,18 +8,11 @@ use wallet::{ Command, SubcommandReturnValue, WalletCore, cli::{ account::{AccountSubcommand, FetchSubcommand, NewSubcommand}, - native_token_transfer_program::{ - NativeTokenTransferProgramSubcommand, NativeTokenTransferProgramSubcommandPrivate, - NativeTokenTransferProgramSubcommandShielded, - }, + native_token_transfer_program::AuthTransferSubcommand, pinata_program::{ PinataProgramSubcommand, PinataProgramSubcommandPrivate, PinataProgramSubcommandPublic, }, - token_program::{ - TokenProgramSubcommand, TokenProgramSubcommandDeshielded, - TokenProgramSubcommandPrivate, TokenProgramSubcommandPublic, - TokenProgramSubcommandShielded, - }, + token_program::TokenProgramAgnosticSubcommand, }, config::PersistentAccountData, helperfunctions::{fetch_config, fetch_persistent_accounts}, @@ -30,7 +23,8 @@ use sequencer_core::sequencer_store::PINATA_BASE58; use crate::{ ACC_RECEIVER, ACC_RECEIVER_PRIVATE, ACC_SENDER, ACC_SENDER_PRIVATE, NSSA_PROGRAM_FOR_TEST_DATA_CHANGER, TIME_TO_WAIT_FOR_BLOCK_SECONDS, - fetch_privacy_preserving_tx, + fetch_privacy_preserving_tx, make_private_account_input_from_str, + make_public_account_input_from_str, }; use crate::{post_test, pre_test, verify_commitment_is_in_state}; @@ -42,9 +36,11 @@ pub fn prepare_function_map() -> HashMap { #[test_suite_fn] pub async fn test_success() { info!("test_success"); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public { - from: ACC_SENDER.to_string(), - to: ACC_RECEIVER.to_string(), + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_public_account_input_from_str(ACC_SENDER), + to: Some(make_public_account_input_from_str(ACC_RECEIVER)), + to_npk: None, + to_ipk: None, amount: 100, }); @@ -103,9 +99,13 @@ pub fn prepare_function_map() -> HashMap { panic!("Failed to produce new account, not present in persistent accounts"); } - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public { - from: ACC_SENDER.to_string(), - to: new_persistent_account_addr.clone(), + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_public_account_input_from_str(ACC_SENDER), + to: Some(make_public_account_input_from_str( + &new_persistent_account_addr, + )), + to_npk: None, + to_ipk: None, amount: 100, }); @@ -136,9 +136,11 @@ pub fn prepare_function_map() -> HashMap { #[test_suite_fn] pub async fn test_failure() { info!("test_failure"); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public { - from: ACC_SENDER.to_string(), - to: ACC_RECEIVER.to_string(), + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_public_account_input_from_str(ACC_SENDER), + to: Some(make_public_account_input_from_str(ACC_RECEIVER)), + to_npk: None, + to_ipk: None, amount: 1000000, }); @@ -175,9 +177,11 @@ pub fn prepare_function_map() -> HashMap { #[test_suite_fn] pub async fn test_success_two_transactions() { info!("test_success_two_transactions"); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public { - from: ACC_SENDER.to_string(), - to: ACC_RECEIVER.to_string(), + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_public_account_input_from_str(ACC_SENDER), + to: Some(make_public_account_input_from_str(ACC_RECEIVER)), + to_npk: None, + to_ipk: None, amount: 100, }); @@ -208,9 +212,11 @@ pub fn prepare_function_map() -> HashMap { info!("First TX Success!"); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public { - from: ACC_SENDER.to_string(), - to: ACC_RECEIVER.to_string(), + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_public_account_input_from_str(ACC_SENDER), + to: Some(make_public_account_input_from_str(ACC_RECEIVER)), + to_npk: None, + to_ipk: None, amount: 100, }); @@ -306,13 +312,12 @@ pub fn prepare_function_map() -> HashMap { .expect("Failed to produce new account, not present in persistent accounts"); // Create new token - let subcommand = - TokenProgramSubcommand::Public(TokenProgramSubcommandPublic::CreateNewToken { - definition_addr: definition_addr.to_string(), - supply_addr: supply_addr.to_string(), - name: "A NAME".to_string(), - total_supply: 37, - }); + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_addr: make_public_account_input_from_str(&definition_addr.to_string()), + supply_addr: make_public_account_input_from_str(&supply_addr.to_string()), + name: "A NAME".to_string(), + total_supply: 37, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); @@ -361,12 +366,16 @@ pub fn prepare_function_map() -> HashMap { ); // Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = - TokenProgramSubcommand::Public(TokenProgramSubcommandPublic::TransferToken { - sender_addr: supply_addr.to_string(), - recipient_addr: recipient_addr.to_string(), - balance_to_move: 7, - }); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_public_account_input_from_str(&supply_addr.to_string()), + to: Some(make_public_account_input_from_str( + &recipient_addr.to_string(), + )), + to_npk: None, + to_ipk: None, + amount: 7, + }; + wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap(); @@ -449,14 +458,12 @@ pub fn prepare_function_map() -> HashMap { }; // Create new token - let subcommand = TokenProgramSubcommand::Private( - TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned { - definition_addr: definition_addr.to_string(), - supply_addr: supply_addr.to_string(), - name: "A NAME".to_string(), - total_supply: 37, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_addr: make_public_account_input_from_str(&definition_addr.to_string()), + supply_addr: make_private_account_input_from_str(&supply_addr.to_string()), + name: "A NAME".to_string(), + total_supply: 37, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -495,13 +502,15 @@ pub fn prepare_function_map() -> HashMap { assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); // Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = TokenProgramSubcommand::Private( - TokenProgramSubcommandPrivate::TransferTokenPrivateOwned { - sender_addr: supply_addr.to_string(), - recipient_addr: recipient_addr.to_string(), - balance_to_move: 7, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_private_account_input_from_str(&supply_addr.to_string()), + to: Some(make_private_account_input_from_str( + &recipient_addr.to_string(), + )), + to_npk: None, + to_ipk: None, + amount: 7, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -526,13 +535,15 @@ pub fn prepare_function_map() -> HashMap { assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); // Transfer additional 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = TokenProgramSubcommand::Private( - TokenProgramSubcommandPrivate::TransferTokenPrivateOwned { - sender_addr: supply_addr.to_string(), - recipient_addr: recipient_addr.to_string(), - balance_to_move: 7, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_private_account_input_from_str(&supply_addr.to_string()), + to: Some(make_private_account_input_from_str( + &recipient_addr.to_string(), + )), + to_npk: None, + to_ipk: None, + amount: 7, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -597,14 +608,12 @@ pub fn prepare_function_map() -> HashMap { }; // Create new token - let subcommand = TokenProgramSubcommand::Private( - TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned { - definition_addr: definition_addr.to_string(), - supply_addr: supply_addr.to_string(), - name: "A NAME".to_string(), - total_supply: 37, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_addr: make_public_account_input_from_str(&definition_addr.to_string()), + supply_addr: make_private_account_input_from_str(&supply_addr.to_string()), + name: "A NAME".to_string(), + total_supply: 37, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -649,14 +658,15 @@ pub fn prepare_function_map() -> HashMap { .unwrap(); // Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = TokenProgramSubcommand::Private( - TokenProgramSubcommandPrivate::TransferTokenPrivateForeign { - sender_addr: supply_addr.to_string(), - recipient_npk: hex::encode(recipient_keys.nullifer_public_key.0), - recipient_ipk: hex::encode(recipient_keys.incoming_viewing_public_key.0.clone()), - balance_to_move: 7, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_private_account_input_from_str(&supply_addr.to_string()), + to: None, + to_npk: Some(hex::encode(recipient_keys.nullifer_public_key.0)), + to_ipk: Some(hex::encode( + recipient_keys.incoming_viewing_public_key.0.clone(), + )), + amount: 7, + }; let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = wallet::execute_subcommand(Command::Token(subcommand)) @@ -733,13 +743,12 @@ pub fn prepare_function_map() -> HashMap { }; // Create new token - let subcommand = - TokenProgramSubcommand::Public(TokenProgramSubcommandPublic::CreateNewToken { - definition_addr: definition_addr.to_string(), - supply_addr: supply_addr.to_string(), - name: "A NAME".to_string(), - total_supply: 37, - }); + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_addr: make_public_account_input_from_str(&definition_addr.to_string()), + supply_addr: make_public_account_input_from_str(&supply_addr.to_string()), + name: "A NAME".to_string(), + total_supply: 37, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -768,13 +777,15 @@ pub fn prepare_function_map() -> HashMap { ); // Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = TokenProgramSubcommand::Shielded( - TokenProgramSubcommandShielded::TransferTokenShieldedOwned { - sender_addr: supply_addr.to_string(), - recipient_addr: recipient_addr.to_string(), - balance_to_move: 7, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_public_account_input_from_str(&supply_addr.to_string()), + to: Some(make_private_account_input_from_str( + &recipient_addr.to_string(), + )), + to_npk: None, + to_ipk: None, + amount: 7, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -794,13 +805,15 @@ pub fn prepare_function_map() -> HashMap { assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); // Transfer additional 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = TokenProgramSubcommand::Shielded( - TokenProgramSubcommandShielded::TransferTokenShieldedOwned { - sender_addr: supply_addr.to_string(), - recipient_addr: recipient_addr.to_string(), - balance_to_move: 7, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_public_account_input_from_str(&supply_addr.to_string()), + to: Some(make_private_account_input_from_str( + &recipient_addr.to_string(), + )), + to_npk: None, + to_ipk: None, + amount: 7, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -860,14 +873,12 @@ pub fn prepare_function_map() -> HashMap { }; // Create new token - let subcommand = TokenProgramSubcommand::Private( - TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned { - definition_addr: definition_addr.to_string(), - supply_addr: supply_addr.to_string(), - name: "A NAME".to_string(), - total_supply: 37, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_addr: make_public_account_input_from_str(&definition_addr.to_string()), + supply_addr: make_private_account_input_from_str(&supply_addr.to_string()), + name: "A NAME".to_string(), + total_supply: 37, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -906,13 +917,15 @@ pub fn prepare_function_map() -> HashMap { assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); // Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = TokenProgramSubcommand::Deshielded( - TokenProgramSubcommandDeshielded::TransferTokenDeshielded { - sender_addr: supply_addr.to_string(), - recipient_addr: recipient_addr.to_string(), - balance_to_move: 7, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_private_account_input_from_str(&supply_addr.to_string()), + to: Some(make_public_account_input_from_str( + &recipient_addr.to_string(), + )), + to_npk: None, + to_ipk: None, + amount: 7, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -932,13 +945,15 @@ pub fn prepare_function_map() -> HashMap { assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); // Transfer additional 7 tokens from `supply_acc` to the account at address `recipient_addr` - let subcommand = TokenProgramSubcommand::Deshielded( - TokenProgramSubcommandDeshielded::TransferTokenDeshielded { - sender_addr: supply_addr.to_string(), - recipient_addr: recipient_addr.to_string(), - balance_to_move: 7, - }, - ); + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: make_private_account_input_from_str(&supply_addr.to_string()), + to: Some(make_public_account_input_from_str( + &recipient_addr.to_string(), + )), + to_npk: None, + to_ipk: None, + amount: 7, + }; wallet::execute_subcommand(Command::Token(subcommand)) .await @@ -964,13 +979,13 @@ pub fn prepare_function_map() -> HashMap { let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap(); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private( - NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { - from: from.to_string(), - to: to.to_string(), - amount: 100, - }, - )); + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_private_account_input_from_str(&from.to_string()), + to: Some(make_private_account_input_from_str(&to.to_string())), + to_npk: None, + to_ipk: None, + amount: 100, + }); wallet::execute_subcommand(command).await.unwrap(); @@ -1002,14 +1017,13 @@ pub fn prepare_function_map() -> HashMap { let to_npk_string = hex::encode(to_npk.0); let to_ipk = Secp256k1Point::from_scalar(to_npk.0); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private( - NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { - from: from.to_string(), - to_npk: to_npk_string, - to_ipk: hex::encode(to_ipk.0), - amount: 100, - }, - )); + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_private_account_input_from_str(&from.to_string()), + to: None, + to_npk: Some(to_npk_string), + to_ipk: Some(hex::encode(to_ipk.0)), + amount: 100, + }); let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = wallet::execute_subcommand(command).await.unwrap() @@ -1067,14 +1081,13 @@ pub fn prepare_function_map() -> HashMap { .cloned() .unwrap(); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private( - NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { - from: from.to_string(), - to_npk: hex::encode(to_keys.nullifer_public_key.0), - to_ipk: hex::encode(to_keys.incoming_viewing_public_key.0), - amount: 100, - }, - )); + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_private_account_input_from_str(&from.to_string()), + to: None, + to_npk: Some(hex::encode(to_keys.nullifer_public_key.0)), + to_ipk: Some(hex::encode(to_keys.incoming_viewing_public_key.0)), + amount: 100, + }); let sub_ret = wallet::execute_subcommand(command).await.unwrap(); let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else { @@ -1138,14 +1151,13 @@ pub fn prepare_function_map() -> HashMap { .cloned() .unwrap(); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private( - NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { - from: from.to_string(), - to_npk: hex::encode(to_keys.nullifer_public_key.0), - to_ipk: hex::encode(to_keys.incoming_viewing_public_key.0), - amount: 100, - }, - )); + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_private_account_input_from_str(&from.to_string()), + to: None, + to_npk: Some(hex::encode(to_keys.nullifer_public_key.0)), + to_ipk: Some(hex::encode(to_keys.incoming_viewing_public_key.0)), + amount: 100, + }); let sub_ret = wallet::execute_subcommand(command).await.unwrap(); let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else { @@ -1186,9 +1198,12 @@ pub fn prepare_function_map() -> HashMap { info!("test_success_deshielded_transfer_to_another_account"); let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); let to: Address = ACC_RECEIVER.parse().unwrap(); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Deshielded { - from: from.to_string(), - to: to.to_string(), + + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_private_account_input_from_str(&from.to_string()), + to: Some(make_public_account_input_from_str(&to.to_string())), + to_npk: None, + to_ipk: None, amount: 100, }); @@ -1232,13 +1247,14 @@ pub fn prepare_function_map() -> HashMap { info!("test_success_shielded_transfer_to_another_owned_account"); let from: Address = ACC_SENDER.parse().unwrap(); let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap(); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Shielded( - NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { - from: from.to_string(), - to: to.to_string(), - amount: 100, - }, - )); + + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_public_account_input_from_str(&from.to_string()), + to: Some(make_private_account_input_from_str(&to.to_string())), + to_npk: None, + to_ipk: None, + amount: 100, + }); let wallet_config = fetch_config().await.unwrap(); let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); @@ -1276,14 +1292,13 @@ pub fn prepare_function_map() -> HashMap { let to_ipk = Secp256k1Point::from_scalar(to_npk.0); let from: Address = ACC_SENDER.parse().unwrap(); - let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Shielded( - NativeTokenTransferProgramSubcommandShielded::ShieldedForeign { - from: from.to_string(), - to_npk: to_npk_string, - to_ipk: hex::encode(to_ipk.0), - amount: 100, - }, - )); + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: make_public_account_input_from_str(&from.to_string()), + to: None, + to_npk: Some(to_npk_string), + to_ipk: Some(hex::encode(to_ipk.0)), + amount: 100, + }); let wallet_config = fetch_config().await.unwrap(); diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index d7dac7d..b902346 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -82,6 +82,8 @@ pub enum AccountSubcommand { ///New #[command(subcommand)] New(NewSubcommand), + ///Sync private accounts + SyncPrivate {}, } ///Represents generic getter CLI subcommand @@ -213,7 +215,7 @@ impl WalletSubcommand for NewSubcommand { "Generated new account with addr {}", addr.to_bytes().to_base58() ); - println!("With npk {}", hex::encode(&key.nullifer_public_key.0)); + println!("With npk {}", hex::encode(key.nullifer_public_key.0)); println!( "With ipk {}", hex::encode(key.incoming_viewing_public_key.to_bytes()) @@ -303,12 +305,12 @@ impl WalletSubcommand for AccountSubcommand { let token_prog_id = Program::token().id(); let acc_view = match &account.program_owner { - _ if &account.program_owner == &auth_tr_prog_id => { + _ if account.program_owner == auth_tr_prog_id => { let acc_view: AuthenticatedTransferAccountView = account.into(); serde_json::to_string(&acc_view)? } - _ if &account.program_owner == &token_prog_id => { + _ if account.program_owner == token_prog_id => { if let Some(token_def) = TokenDefinition::parse(&account.data) { let acc_view: TokedDefinitionAccountView = token_def.into(); @@ -337,6 +339,9 @@ impl WalletSubcommand for AccountSubcommand { AccountSubcommand::New(new_subcommand) => { new_subcommand.handle_subcommand(wallet_core).await } + AccountSubcommand::SyncPrivate {} => { + todo!(); + } } } } diff --git a/wallet/src/cli/native_token_transfer_program.rs b/wallet/src/cli/native_token_transfer_program.rs index b568931..883e850 100644 --- a/wallet/src/cli/native_token_transfer_program.rs +++ b/wallet/src/cli/native_token_transfer_program.rs @@ -3,7 +3,187 @@ use clap::Subcommand; use common::transaction::NSSATransaction; use nssa::Address; -use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand}; +use crate::{ + SubcommandReturnValue, WalletCore, + cli::WalletSubcommand, + helperfunctions::{AddressPrivacyKind, parse_addr_with_privacy_prefix}, +}; + +///Represents generic CLI subcommand for a wallet working with native token transfer program +#[derive(Subcommand, Debug, Clone)] +pub enum AuthTransferSubcommand { + Init { + ///addr - valid 32 byte base58 string + #[arg(long)] + addr: String, + }, + Send { + ///from - valid 32 byte base58 string + #[arg(long)] + from: String, + ///to - valid 32 byte base58 string + #[arg(long)] + to: Option, + ///to_npk - valid 32 byte base58 string + #[arg(long)] + to_npk: Option, + ///to_ipk - valid 33 byte base58 string + #[arg(long)] + to_ipk: Option, + ///amount - amount of balance to move + #[arg(long)] + amount: u128, + }, +} + +impl WalletSubcommand for AuthTransferSubcommand { + async fn handle_subcommand( + self, + wallet_core: &mut WalletCore, + ) -> Result { + match self { + AuthTransferSubcommand::Init { addr } => { + let (addr, addr_privacy) = parse_addr_with_privacy_prefix(&addr)?; + + match addr_privacy { + AddressPrivacyKind::Public => { + let res = wallet_core + .register_account_under_authenticated_transfers_programs(addr) + .await?; + + println!("Results of tx send is {res:#?}"); + + let transfer_tx = + wallet_core.poll_native_token_transfer(res.tx_hash).await?; + + println!("Transaction data is {transfer_tx:?}"); + + let path = wallet_core.store_persistent_accounts().await?; + + println!("Stored persistent accounts at {path:#?}"); + } + AddressPrivacyKind::Private => { + let (res, [secret]) = wallet_core + .register_account_under_authenticated_transfers_programs_private(addr) + .await?; + + println!("Results of tx send is {res:#?}"); + + let tx_hash = res.tx_hash; + let transfer_tx = wallet_core + .poll_native_token_transfer(tx_hash.clone()) + .await?; + + if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + let acc_decode_data = vec![(secret, addr)]; + + wallet_core.decode_insert_privacy_preserving_transaction_results( + tx, + &acc_decode_data, + )?; + } + + let path = wallet_core.store_persistent_accounts().await?; + + println!("Stored persistent accounts at {path:#?}"); + } + } + + Ok(SubcommandReturnValue::Empty) + } + AuthTransferSubcommand::Send { + from, + to, + to_npk, + to_ipk, + amount, + } => { + let underlying_subcommand = match (to, to_npk, to_ipk) { + (None, None, None) => { + anyhow::bail!( + "Provide either account address of receiver or their public keys" + ); + } + (Some(_), Some(_), Some(_)) => { + anyhow::bail!( + "Provide only one variant: either account address of receiver or their public keys" + ); + } + (_, Some(_), None) | (_, None, Some(_)) => { + anyhow::bail!("List of public keys is uncomplete"); + } + (Some(to), None, None) => { + let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?; + let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?; + + match (from_privacy, to_privacy) { + (AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { + NativeTokenTransferProgramSubcommand::Public { + from: from.to_string(), + to: to.to_string(), + amount, + } + } + (AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { + NativeTokenTransferProgramSubcommand::Private( + NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { + from: from.to_string(), + to: to.to_string(), + amount, + }, + ) + } + (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { + NativeTokenTransferProgramSubcommand::Deshielded { + from: from.to_string(), + to: to.to_string(), + amount, + } + } + (AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { + NativeTokenTransferProgramSubcommand::Shielded( + NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { + from: from.to_string(), + to: to.to_string(), + amount, + }, + ) + } + } + } + (None, Some(to_npk), Some(to_ipk)) => { + let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?; + + match from_privacy { + AddressPrivacyKind::Private => { + NativeTokenTransferProgramSubcommand::Private( + NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { + from: from.to_string(), + to_npk, + to_ipk, + amount, + }, + ) + } + AddressPrivacyKind::Public => { + NativeTokenTransferProgramSubcommand::Shielded( + NativeTokenTransferProgramSubcommandShielded::ShieldedForeign { + from: from.to_string(), + to_npk, + to_ipk, + amount, + }, + ) + } + } + } + }; + + underlying_subcommand.handle_subcommand(wallet_core).await + } + } + } +} ///Represents generic CLI subcommand for a wallet working with native token transfer program #[derive(Subcommand, Debug, Clone)] diff --git a/wallet/src/cli/token_program.rs b/wallet/src/cli/token_program.rs index 25de77d..dc269e4 100644 --- a/wallet/src/cli/token_program.rs +++ b/wallet/src/cli/token_program.rs @@ -3,7 +3,187 @@ use clap::Subcommand; use common::transaction::NSSATransaction; use nssa::Address; -use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand}; +use crate::{ + SubcommandReturnValue, WalletCore, + cli::WalletSubcommand, + helperfunctions::{AddressPrivacyKind, parse_addr_with_privacy_prefix}, +}; + +///Represents generic CLI subcommand for a wallet working with token program +#[derive(Subcommand, Debug, Clone)] +pub enum TokenProgramAgnosticSubcommand { + New { + ///addr - valid 32 byte base58 string + #[arg(long)] + definition_addr: String, + ///addr - valid 32 byte base58 string + #[arg(long)] + supply_addr: String, + #[arg(short, long)] + name: String, + #[arg(short, long)] + total_supply: u128, + }, + Send { + ///from - valid 32 byte base58 string + #[arg(long)] + from: String, + ///to - valid 32 byte base58 string + #[arg(long)] + to: Option, + ///to_npk - valid 32 byte hex string + #[arg(long)] + to_npk: Option, + ///to_ipk - valid 33 byte hex string + #[arg(long)] + to_ipk: Option, + ///amount - amount of balance to move + #[arg(long)] + amount: u128, + }, +} + +impl WalletSubcommand for TokenProgramAgnosticSubcommand { + async fn handle_subcommand( + self, + wallet_core: &mut WalletCore, + ) -> Result { + match self { + TokenProgramAgnosticSubcommand::New { + definition_addr, + supply_addr, + name, + total_supply, + } => { + let (definition_addr, definition_addr_privacy) = + parse_addr_with_privacy_prefix(&definition_addr)?; + let (supply_addr, supply_addr_privacy) = + parse_addr_with_privacy_prefix(&supply_addr)?; + + let underlying_subcommand = match (definition_addr_privacy, supply_addr_privacy) { + (AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { + TokenProgramSubcommand::Public( + TokenProgramSubcommandPublic::CreateNewToken { + definition_addr: definition_addr.to_string(), + supply_addr: supply_addr.to_string(), + name, + total_supply, + }, + ) + } + (AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { + TokenProgramSubcommand::Private( + TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned { + definition_addr: definition_addr.to_string(), + supply_addr: supply_addr.to_string(), + name, + total_supply, + }, + ) + } + (AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { + todo!(); + } + (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { + todo!(); + } + }; + + underlying_subcommand.handle_subcommand(wallet_core).await + } + TokenProgramAgnosticSubcommand::Send { + from, + to, + to_npk, + to_ipk, + amount, + } => { + let underlying_subcommand = match (to, to_npk, to_ipk) { + (None, None, None) => { + anyhow::bail!( + "Provide either account address of receiver or their public keys" + ); + } + (Some(_), Some(_), Some(_)) => { + anyhow::bail!( + "Provide only one variant: either account address of receiver or their public keys" + ); + } + (_, Some(_), None) | (_, None, Some(_)) => { + anyhow::bail!("List of public keys is uncomplete"); + } + (Some(to), None, None) => { + let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?; + let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?; + + match (from_privacy, to_privacy) { + (AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { + TokenProgramSubcommand::Public( + TokenProgramSubcommandPublic::TransferToken { + sender_addr: from.to_string(), + recipient_addr: to.to_string(), + balance_to_move: amount, + }, + ) + } + (AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { + TokenProgramSubcommand::Private( + TokenProgramSubcommandPrivate::TransferTokenPrivateOwned { + sender_addr: from.to_string(), + recipient_addr: to.to_string(), + balance_to_move: amount, + }, + ) + } + (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { + TokenProgramSubcommand::Deshielded( + TokenProgramSubcommandDeshielded::TransferTokenDeshielded { + sender_addr: from.to_string(), + recipient_addr: to.to_string(), + balance_to_move: amount, + }, + ) + } + (AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { + TokenProgramSubcommand::Shielded( + TokenProgramSubcommandShielded::TransferTokenShieldedOwned { + sender_addr: from.to_string(), + recipient_addr: to.to_string(), + balance_to_move: amount, + }, + ) + } + } + } + (None, Some(to_npk), Some(to_ipk)) => { + let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?; + + match from_privacy { + AddressPrivacyKind::Private => TokenProgramSubcommand::Private( + TokenProgramSubcommandPrivate::TransferTokenPrivateForeign { + sender_addr: from.to_string(), + recipient_npk: to_npk, + recipient_ipk: to_ipk, + balance_to_move: amount, + }, + ), + AddressPrivacyKind::Public => TokenProgramSubcommand::Shielded( + TokenProgramSubcommandShielded::TransferTokenShieldedForeign { + sender_addr: from.to_string(), + recipient_npk: to_npk, + recipient_ipk: to_ipk, + balance_to_move: amount, + }, + ), + } + } + }; + + underlying_subcommand.handle_subcommand(wallet_core).await + } + } + } +} ///Represents generic CLI subcommand for a wallet working with token_program #[derive(Subcommand, Debug, Clone)] diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 5de7f5d..897b7d5 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -22,11 +22,10 @@ use tokio::io::AsyncWriteExt; use crate::cli::{ WalletSubcommand, account::AccountSubcommand, chain::ChainSubcommand, - native_token_transfer_program::NativeTokenTransferProgramSubcommand, - pinata_program::PinataProgramSubcommand, + native_token_transfer_program::AuthTransferSubcommand, pinata_program::PinataProgramSubcommand, + token_program::TokenProgramAgnosticSubcommand, }; use crate::{ - cli::token_program::TokenProgramSubcommand, helperfunctions::{ fetch_config, fetch_persistent_accounts, get_home, produce_data_for_storage, }, @@ -193,7 +192,7 @@ impl WalletCore { pub enum Command { ///Transfer command #[command(subcommand)] - AuthTransfer(NativeTokenTransferProgramSubcommand), + AuthTransfer(AuthTransferSubcommand), ///Chain command #[command(subcommand)] ChainInfo(ChainSubcommand), @@ -205,7 +204,7 @@ pub enum Command { Pinata(PinataProgramSubcommand), ///Token command #[command(subcommand)] - Token(TokenProgramSubcommand), + Token(TokenProgramAgnosticSubcommand), AuthenticatedTransferInitializePublicAccount {}, // Check the wallet can connect to the node and builtin local programs // match the remote versions diff --git a/wallet/src/transaction_utils.rs b/wallet/src/transaction_utils.rs index 0761fa7..2dd69ca 100644 --- a/wallet/src/transaction_utils.rs +++ b/wallet/src/transaction_utils.rs @@ -537,4 +537,53 @@ impl WalletCore { Ok(self.sequencer_client.send_tx_private(tx).await?) } + + pub async fn register_account_under_authenticated_transfers_programs_private( + &self, + from: Address, + ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { + let AccountPreparedData { + nsk: _, + npk: from_npk, + ipk: from_ipk, + auth_acc: sender_pre, + proof: _, + } = self.private_acc_preparation(from, false, false).await?; + + let eph_holder_from = EphemeralKeyHolder::new(&from_npk); + let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk); + + let instruction: u128 = 0; + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre], + &Program::serialize_instruction(instruction).unwrap(), + &[2], + &produce_random_nonces(1), + &[(from_npk.clone(), shared_secret_from.clone())], + &[], + &Program::authenticated_transfer_program(), + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![], + vec![], + vec![( + from_npk.clone(), + from_ipk.clone(), + eph_holder_from.generate_ephemeral_public_key(), + )], + output, + ) + .unwrap(); + + let witness_set = WitnessSet::for_message(&message, proof, &[]); + let tx = PrivacyPreservingTransaction::new(message, witness_set); + + Ok(( + self.sequencer_client.send_tx_private(tx).await?, + [shared_secret_from], + )) + } } From 27bb5bbb0fd09a29816d6da344e4be48f55bec12 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Tue, 28 Oct 2025 14:40:16 +0200 Subject: [PATCH 05/10] temp: temp changes --- wallet/src/cli/native_token_transfer_program.rs | 2 ++ wallet/src/helperfunctions.rs | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/wallet/src/cli/native_token_transfer_program.rs b/wallet/src/cli/native_token_transfer_program.rs index 883e850..2f97365 100644 --- a/wallet/src/cli/native_token_transfer_program.rs +++ b/wallet/src/cli/native_token_transfer_program.rs @@ -47,6 +47,8 @@ impl WalletSubcommand for AuthTransferSubcommand { match addr_privacy { AddressPrivacyKind::Public => { + let addr = addr.parse()?; + let res = wallet_core .register_account_under_authenticated_transfers_programs(addr) .await?; diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index fcc838b..83eef43 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -6,7 +6,7 @@ use tokio::io::AsyncReadExt; use anyhow::Result; use key_protocol::key_protocol_core::NSSAUserData; -use nssa::{Account, Address}; +use nssa::Account; use serde::Serialize; use crate::{ @@ -94,15 +94,15 @@ pub enum AddressPrivacyKind { pub(crate) fn parse_addr_with_privacy_prefix( addr_base58: &str, -) -> Result<(Address, AddressPrivacyKind)> { +) -> Result<(String, AddressPrivacyKind)> { if addr_base58.starts_with("Public/") { Ok(( - addr_base58.strip_prefix("Public/").unwrap().parse()?, + addr_base58.strip_prefix("Public/").unwrap().to_string(), AddressPrivacyKind::Public, )) } else if addr_base58.starts_with("Private/") { Ok(( - addr_base58.strip_prefix("Private/").unwrap().parse()?, + addr_base58.strip_prefix("Private/").unwrap().to_string(), AddressPrivacyKind::Private, )) } else { From 5840f9b779b937639834e82b1a873680d62739c4 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Tue, 28 Oct 2025 16:02:30 +0200 Subject: [PATCH 06/10] fix: cli full refactor --- common/src/lib.rs | 2 + integration_tests/src/lib.rs | 23 +- integration_tests/src/test_suite_map.rs | 87 +++----- sequencer_core/src/sequencer_store/mod.rs | 4 +- wallet/src/cli/account.rs | 134 +++-------- .../src/cli/native_token_transfer_program.rs | 40 ++-- wallet/src/cli/pinata_program.rs | 56 ++++- wallet/src/cli/token_program.rs | 46 ++-- wallet/src/config.rs | 6 + wallet/src/helperfunctions.rs | 32 ++- wallet/src/lib.rs | 210 +++++++++--------- 11 files changed, 324 insertions(+), 316 deletions(-) diff --git a/common/src/lib.rs b/common/src/lib.rs index c44d03f..7976479 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -8,3 +8,5 @@ pub mod transaction; //TODO: Compile only for tests pub mod test_utils; pub type HashType = [u8; 32]; + +pub const PINATA_BASE58: &str = "EfQhKQAkX2FJiwNii2WFQsGndjvF1Mzd7RuVe7QdPLw7"; diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index f09d808..f718f9d 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -43,11 +43,11 @@ pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12; pub const NSSA_PROGRAM_FOR_TEST_DATA_CHANGER: &[u8] = include_bytes!("data_changer.bin"); fn make_public_account_input_from_str(addr: &str) -> String { - format!("Public/{addr:?}") + format!("Public/{addr}") } fn make_private_account_input_from_str(addr: &str) -> String { - format!("Private/{addr:?}") + format!("Private/{addr}") } #[allow(clippy::type_complexity)] @@ -92,7 +92,7 @@ pub async fn post_test(residual: (ServerHandle, JoinHandle>, TempDir) seq_http_server_handle.stop(true).await; let wallet_home = wallet::helperfunctions::get_home().unwrap(); - let persistent_data_home = wallet_home.join("curr_accounts.json"); + let persistent_data_home = wallet_home.join("storage.json"); //Removing persistent accounts after run to not affect other executions //Not necessary an error, if fails as there is tests for failure scenario @@ -163,3 +163,20 @@ async fn verify_commitment_is_in_state( Ok(Some(_)) ) } + +#[cfg(test)] +mod tests { + use crate::{make_private_account_input_from_str, make_public_account_input_from_str}; + + #[test] + fn correct_addr_from_prefix() { + let addr1 = "cafecafe"; + let addr2 = "deadbeaf"; + + let addr1_pub = make_public_account_input_from_str(addr1); + let addr2_priv = make_private_account_input_from_str(addr2); + + assert_eq!(addr1_pub, "Public/cafecafe".to_string()); + assert_eq!(addr2_priv, "Private/deadbeaf".to_string()); + } +} diff --git a/integration_tests/src/test_suite_map.rs b/integration_tests/src/test_suite_map.rs index ec75a32..0bf8f00 100644 --- a/integration_tests/src/test_suite_map.rs +++ b/integration_tests/src/test_suite_map.rs @@ -1,25 +1,21 @@ use std::{collections::HashMap, path::PathBuf, pin::Pin, time::Duration}; -use common::sequencer_client::SequencerClient; +use common::{PINATA_BASE58, 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, NewSubcommand}, + account::{AccountSubcommand, NewSubcommand}, native_token_transfer_program::AuthTransferSubcommand, - pinata_program::{ - PinataProgramSubcommand, PinataProgramSubcommandPrivate, PinataProgramSubcommandPublic, - }, + pinata_program::PinataProgramAgnosticSubcommand, token_program::TokenProgramAgnosticSubcommand, }, - config::PersistentAccountData, - helperfunctions::{fetch_config, fetch_persistent_accounts}, + config::{PersistentAccountData, PersistentStorage}, + helperfunctions::{fetch_config, fetch_persistent_storage}, }; -use sequencer_core::sequencer_store::PINATA_BASE58; - use crate::{ ACC_RECEIVER, ACC_RECEIVER_PRIVATE, ACC_SENDER, ACC_SENDER_PRIVATE, NSSA_PROGRAM_FOR_TEST_DATA_CHANGER, TIME_TO_WAIT_FOR_BLOCK_SECONDS, @@ -83,7 +79,10 @@ pub fn prepare_function_map() -> HashMap { wallet::execute_subcommand(command).await.unwrap(); - let persistent_accounts = fetch_persistent_accounts().await.unwrap(); + let PersistentStorage { + accounts: persistent_accounts, + last_synced_block: _, + } = fetch_persistent_storage().await.unwrap(); let mut new_persistent_account_addr = String::new(); @@ -290,7 +289,10 @@ pub fn prepare_function_map() -> HashMap { .await .unwrap(); - let persistent_accounts = fetch_persistent_accounts().await.unwrap(); + let PersistentStorage { + accounts: persistent_accounts, + last_synced_block: _, + } = fetch_persistent_storage().await.unwrap(); let mut new_persistent_accounts_addr = Vec::new(); @@ -668,7 +670,7 @@ pub fn prepare_function_map() -> HashMap { amount: 7, }; - let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = + let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash: _ } = wallet::execute_subcommand(Command::Token(subcommand)) .await .unwrap() @@ -679,11 +681,7 @@ pub fn prepare_function_map() -> HashMap { 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, - })); + let command = Command::Account(AccountSubcommand::SyncPrivate {}); wallet::execute_subcommand(command).await.unwrap(); @@ -1096,11 +1094,7 @@ pub fn prepare_function_map() -> HashMap { 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, - })); + let command = Command::Account(AccountSubcommand::SyncPrivate {}); wallet::execute_subcommand(command).await.unwrap(); let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) .await @@ -1335,13 +1329,10 @@ pub fn prepare_function_map() -> HashMap { let pinata_addr = PINATA_BASE58; let pinata_prize = 150; let solution = 989106; - let command = Command::Pinata(PinataProgramSubcommand::Public( - PinataProgramSubcommandPublic::Claim { - pinata_addr: pinata_addr.to_string(), - winner_addr: ACC_SENDER.to_string(), - solution, - }, - )); + let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim { + to_addr: make_public_account_input_from_str(ACC_SENDER), + solution, + }); let wallet_config = fetch_config().await.unwrap(); @@ -1427,14 +1418,18 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_authenticated_transfer_initialize_function() { info!("test initialize account for authenticated transfer"); - let command = Command::AuthenticatedTransferInitializePublicAccount {}; - + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public {})); let SubcommandReturnValue::RegisterAccount { addr } = wallet::execute_subcommand(command).await.unwrap() else { panic!("Error creating account"); }; + let command = Command::AuthTransfer(AuthTransferSubcommand::Init { + addr: addr.to_string(), + }); + wallet::execute_subcommand(command).await.unwrap(); + info!("Checking correct execution"); let wallet_config = fetch_config().await.unwrap(); let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); @@ -1463,13 +1458,10 @@ pub fn prepare_function_map() -> HashMap { let pinata_prize = 150; let solution = 989106; - let command = Command::Pinata(PinataProgramSubcommand::Private( - PinataProgramSubcommandPrivate::ClaimPrivateOwned { - pinata_addr: pinata_addr.to_string(), - winner_addr: ACC_SENDER_PRIVATE.to_string(), - solution, - }, - )); + let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim { + to_addr: make_private_account_input_from_str(ACC_SENDER_PRIVATE), + solution, + }); let wallet_config = fetch_config().await.unwrap(); @@ -1481,7 +1473,7 @@ pub fn prepare_function_map() -> HashMap { .unwrap() .balance; - let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = + let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash: _ } = wallet::execute_subcommand(command).await.unwrap() else { panic!("invalid subcommand return value"); @@ -1497,11 +1489,7 @@ pub fn prepare_function_map() -> HashMap { .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, - })); + let command = Command::Account(AccountSubcommand::SyncPrivate {}); wallet::execute_subcommand(command).await.unwrap(); let wallet_config = fetch_config().await.unwrap(); @@ -1538,13 +1526,10 @@ pub fn prepare_function_map() -> HashMap { panic!("invalid subcommand return value"); }; - let command = Command::Pinata(PinataProgramSubcommand::Private( - PinataProgramSubcommandPrivate::ClaimPrivateOwned { - pinata_addr: pinata_addr.to_string(), - winner_addr: winner_addr.to_string(), - solution, - }, - )); + let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim { + to_addr: make_private_account_input_from_str(&winner_addr.to_string()), + solution, + }); let wallet_config = fetch_config().await.unwrap(); diff --git a/sequencer_core/src/sequencer_store/mod.rs b/sequencer_core/src/sequencer_store/mod.rs index 186b266..dd99639 100644 --- a/sequencer_core/src/sequencer_store/mod.rs +++ b/sequencer_core/src/sequencer_store/mod.rs @@ -9,8 +9,6 @@ use crate::config::AccountInitialData; pub mod block_store; -pub const PINATA_BASE58: &str = "EfQhKQAkX2FJiwNii2WFQsGndjvF1Mzd7RuVe7QdPLw7"; - pub struct SequecerChainStore { pub state: nssa::V02State, pub block_store: SequecerBlockStore, @@ -35,6 +33,8 @@ impl SequecerChainStore { #[cfg(feature = "testnet")] let state = { + use common::PINATA_BASE58; + let mut this = nssa::V02State::new_with_genesis_accounts(&init_accs, initial_commitments); this.add_pinata_program(PINATA_BASE58.parse().unwrap()); diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index b902346..06218fe 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -1,7 +1,6 @@ use anyhow::Result; use base58::ToBase58; use clap::Subcommand; -use common::transaction::NSSATransaction; use nssa::{Address, program::Program}; use serde::Serialize; @@ -9,6 +8,7 @@ use crate::{ SubcommandReturnValue, WalletCore, cli::WalletSubcommand, helperfunctions::{AddressPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix}, + parse_block_range, }; const TOKEN_DEFINITION_TYPE: u8 = 0; @@ -76,9 +76,6 @@ pub enum AccountSubcommand { #[arg(short, long)] addr: String, }, - ///Fetch - #[command(subcommand)] - Fetch(FetchSubcommand), ///New #[command(subcommand)] New(NewSubcommand), @@ -86,28 +83,6 @@ pub enum AccountSubcommand { SyncPrivate {}, } -///Represents generic getter CLI subcommand -#[derive(Subcommand, Debug, Clone)] -pub enum FetchSubcommand { - ///Fetch transaction by `hash` - Tx { - #[arg(short, long)] - tx_hash: String, - }, - ///Claim account `acc_addr` generated in transaction `tx_hash`, using secret `sh_secret` at ciphertext id `ciph_id` - PrivateAccount { - ///tx_hash - valid 32 byte hex string - #[arg(long)] - tx_hash: String, - ///acc_addr - valid 32 byte hex string - #[arg(long)] - acc_addr: String, - ///output_id - id of the output in the transaction - #[arg(long)] - output_id: usize, - }, -} - ///Represents generic register CLI subcommand #[derive(Subcommand, Debug, Clone)] pub enum NewSubcommand { @@ -117,74 +92,6 @@ pub enum NewSubcommand { Private {}, } -impl WalletSubcommand for FetchSubcommand { - async fn handle_subcommand( - self, - wallet_core: &mut WalletCore, - ) -> Result { - match self { - FetchSubcommand::Tx { tx_hash } => { - let tx_obj = wallet_core - .sequencer_client - .get_transaction_by_hash(tx_hash) - .await?; - - println!("Transaction object {tx_obj:#?}"); - - Ok(SubcommandReturnValue::Empty) - } - FetchSubcommand::PrivateAccount { - tx_hash, - acc_addr, - output_id: ciph_id, - } => { - let acc_addr: Address = acc_addr.parse().unwrap(); - - let account_key_chain = wallet_core - .storage - .user_data - .user_private_accounts - .get(&acc_addr); - - let Some((account_key_chain, _)) = account_key_chain else { - anyhow::bail!("Account not found"); - }; - - let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { - let to_ebc = tx.message.encrypted_private_post_states[ciph_id].clone(); - let to_comm = tx.message.new_commitments[ciph_id].clone(); - let shared_secret = - account_key_chain.calculate_shared_secret_receiver(to_ebc.epk); - - let res_acc_to = nssa_core::EncryptionScheme::decrypt( - &to_ebc.ciphertext, - &shared_secret, - &to_comm, - ciph_id as u32, - ) - .unwrap(); - - println!("RES acc to {res_acc_to:#?}"); - - println!("Transaction data is {:?}", tx.message); - - wallet_core - .storage - .insert_private_account_data(acc_addr, res_acc_to); - } - - let path = wallet_core.store_persistent_accounts().await?; - - println!("Stored persistent accounts at {path:#?}"); - - Ok(SubcommandReturnValue::Empty) - } - } - } -} - impl WalletSubcommand for NewSubcommand { async fn handle_subcommand( self, @@ -196,7 +103,7 @@ impl WalletSubcommand for NewSubcommand { println!("Generated new account with addr {addr}"); - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); @@ -221,7 +128,7 @@ impl WalletSubcommand for NewSubcommand { hex::encode(key.incoming_viewing_public_key.to_bytes()) ); - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); @@ -287,6 +194,8 @@ impl WalletSubcommand for AccountSubcommand { AccountSubcommand::Get { raw, addr } => { let (addr, addr_kind) = parse_addr_with_privacy_prefix(&addr)?; + let addr = addr.parse()?; + let account = match addr_kind { AddressPrivacyKind::Public => wallet_core.get_account_public(addr).await?, AddressPrivacyKind::Private => wallet_core @@ -333,14 +242,39 @@ impl WalletSubcommand for AccountSubcommand { Ok(SubcommandReturnValue::Empty) } - AccountSubcommand::Fetch(fetch_subcommand) => { - fetch_subcommand.handle_subcommand(wallet_core).await - } AccountSubcommand::New(new_subcommand) => { new_subcommand.handle_subcommand(wallet_core).await } AccountSubcommand::SyncPrivate {} => { - todo!(); + let last_synced_block = wallet_core.last_synced_block; + let curr_last_block = wallet_core + .sequencer_client + .get_last_block() + .await? + .last_block; + + if !wallet_core + .storage + .user_data + .user_private_accounts + .is_empty() + { + parse_block_range( + last_synced_block, + curr_last_block, + wallet_core.sequencer_client.clone(), + wallet_core, + ) + .await?; + } else { + wallet_core.last_synced_block = curr_last_block; + + let path = wallet_core.store_persistent_data().await?; + + println!("Stored persistent data at {path:#?}"); + } + + Ok(SubcommandReturnValue::SyncedToBlock(curr_last_block)) } } } diff --git a/wallet/src/cli/native_token_transfer_program.rs b/wallet/src/cli/native_token_transfer_program.rs index 2f97365..19e8368 100644 --- a/wallet/src/cli/native_token_transfer_program.rs +++ b/wallet/src/cli/native_token_transfer_program.rs @@ -60,11 +60,13 @@ impl WalletSubcommand for AuthTransferSubcommand { println!("Transaction data is {transfer_tx:?}"); - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); } AddressPrivacyKind::Private => { + let addr = addr.parse()?; + let (res, [secret]) = wallet_core .register_account_under_authenticated_transfers_programs_private(addr) .await?; @@ -85,7 +87,7 @@ impl WalletSubcommand for AuthTransferSubcommand { )?; } - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); } @@ -120,33 +122,29 @@ impl WalletSubcommand for AuthTransferSubcommand { match (from_privacy, to_privacy) { (AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { - NativeTokenTransferProgramSubcommand::Public { - from: from.to_string(), - to: to.to_string(), - amount, - } + NativeTokenTransferProgramSubcommand::Public { from, to, amount } } (AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { NativeTokenTransferProgramSubcommand::Private( NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { - from: from.to_string(), - to: to.to_string(), + from, + to, amount, }, ) } (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { NativeTokenTransferProgramSubcommand::Deshielded { - from: from.to_string(), - to: to.to_string(), + from, + to, amount, } } (AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { NativeTokenTransferProgramSubcommand::Shielded( NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { - from: from.to_string(), - to: to.to_string(), + from, + to, amount, }, ) @@ -160,7 +158,7 @@ impl WalletSubcommand for AuthTransferSubcommand { AddressPrivacyKind::Private => { NativeTokenTransferProgramSubcommand::Private( NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { - from: from.to_string(), + from, to_npk, to_ipk, amount, @@ -170,7 +168,7 @@ impl WalletSubcommand for AuthTransferSubcommand { AddressPrivacyKind::Public => { NativeTokenTransferProgramSubcommand::Shielded( NativeTokenTransferProgramSubcommandShielded::ShieldedForeign { - from: from.to_string(), + from, to_npk, to_ipk, amount, @@ -340,7 +338,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { )?; } - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); @@ -384,7 +382,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { )?; } - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); @@ -434,7 +432,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded { )?; } - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); @@ -467,7 +465,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded { let tx_hash = res.tx_hash; - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); @@ -513,7 +511,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand { )?; } - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); @@ -533,7 +531,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand { println!("Transaction data is {transfer_tx:?}"); - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); diff --git a/wallet/src/cli/pinata_program.rs b/wallet/src/cli/pinata_program.rs index 75d3d6a..6e79362 100644 --- a/wallet/src/cli/pinata_program.rs +++ b/wallet/src/cli/pinata_program.rs @@ -1,9 +1,59 @@ use anyhow::Result; use clap::Subcommand; -use common::transaction::NSSATransaction; +use common::{PINATA_BASE58, transaction::NSSATransaction}; use log::info; -use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand}; +use crate::{ + SubcommandReturnValue, WalletCore, + cli::WalletSubcommand, + helperfunctions::{AddressPrivacyKind, parse_addr_with_privacy_prefix}, +}; + +///Represents generic CLI subcommand for a wallet working with pinata program +#[derive(Subcommand, Debug, Clone)] +pub enum PinataProgramAgnosticSubcommand { + ///Claim + Claim { + ///to_addr - valid 32 byte base58 string + #[arg(long)] + to_addr: String, + ///solution - solution to pinata challenge + #[arg(long)] + solution: u128, + }, +} + +impl WalletSubcommand for PinataProgramAgnosticSubcommand { + async fn handle_subcommand( + self, + wallet_core: &mut WalletCore, + ) -> Result { + let underlying_subcommand = match self { + PinataProgramAgnosticSubcommand::Claim { to_addr, solution } => { + let (to_addr, to_addr_privacy) = parse_addr_with_privacy_prefix(&to_addr)?; + + match to_addr_privacy { + AddressPrivacyKind::Public => { + PinataProgramSubcommand::Public(PinataProgramSubcommandPublic::Claim { + pinata_addr: PINATA_BASE58.to_string(), + winner_addr: to_addr, + solution, + }) + } + AddressPrivacyKind::Private => PinataProgramSubcommand::Private( + PinataProgramSubcommandPrivate::ClaimPrivateOwned { + pinata_addr: PINATA_BASE58.to_string(), + winner_addr: to_addr, + solution, + }, + ), + } + } + }; + + underlying_subcommand.handle_subcommand(wallet_core).await + } +} ///Represents generic CLI subcommand for a wallet working with pinata program #[derive(Subcommand, Debug, Clone)] @@ -131,7 +181,7 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate { )?; } - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); diff --git a/wallet/src/cli/token_program.rs b/wallet/src/cli/token_program.rs index dc269e4..99ebecd 100644 --- a/wallet/src/cli/token_program.rs +++ b/wallet/src/cli/token_program.rs @@ -64,8 +64,8 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { (AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { TokenProgramSubcommand::Public( TokenProgramSubcommandPublic::CreateNewToken { - definition_addr: definition_addr.to_string(), - supply_addr: supply_addr.to_string(), + definition_addr, + supply_addr, name, total_supply, }, @@ -74,18 +74,20 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { (AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { TokenProgramSubcommand::Private( TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned { - definition_addr: definition_addr.to_string(), - supply_addr: supply_addr.to_string(), + definition_addr, + supply_addr, name, total_supply, }, ) } (AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { - todo!(); + //ToDo: maybe implement this one. It is not immediately clear why definition should be private. + anyhow::bail!("Unavailable privacy pairing") } (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { - todo!(); + //Probably valid. If definition is not public, but supply is it is very suspicious. + anyhow::bail!("Unavailable privacy pairing") } }; @@ -120,8 +122,8 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { (AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { TokenProgramSubcommand::Public( TokenProgramSubcommandPublic::TransferToken { - sender_addr: from.to_string(), - recipient_addr: to.to_string(), + sender_addr: from, + recipient_addr: to, balance_to_move: amount, }, ) @@ -129,8 +131,8 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { (AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { TokenProgramSubcommand::Private( TokenProgramSubcommandPrivate::TransferTokenPrivateOwned { - sender_addr: from.to_string(), - recipient_addr: to.to_string(), + sender_addr: from, + recipient_addr: to, balance_to_move: amount, }, ) @@ -138,8 +140,8 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { TokenProgramSubcommand::Deshielded( TokenProgramSubcommandDeshielded::TransferTokenDeshielded { - sender_addr: from.to_string(), - recipient_addr: to.to_string(), + sender_addr: from, + recipient_addr: to, balance_to_move: amount, }, ) @@ -147,8 +149,8 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { (AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { TokenProgramSubcommand::Shielded( TokenProgramSubcommandShielded::TransferTokenShieldedOwned { - sender_addr: from.to_string(), - recipient_addr: to.to_string(), + sender_addr: from, + recipient_addr: to, balance_to_move: amount, }, ) @@ -161,7 +163,7 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { match from_privacy { AddressPrivacyKind::Private => TokenProgramSubcommand::Private( TokenProgramSubcommandPrivate::TransferTokenPrivateForeign { - sender_addr: from.to_string(), + sender_addr: from, recipient_npk: to_npk, recipient_ipk: to_ipk, balance_to_move: amount, @@ -169,7 +171,7 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { ), AddressPrivacyKind::Public => TokenProgramSubcommand::Shielded( TokenProgramSubcommandShielded::TransferTokenShieldedForeign { - sender_addr: from.to_string(), + sender_addr: from, recipient_npk: to_npk, recipient_ipk: to_ipk, balance_to_move: amount, @@ -401,7 +403,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { )?; } - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); @@ -458,7 +460,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { )?; } - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); @@ -508,7 +510,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { )?; } - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); @@ -556,7 +558,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { )?; } - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); @@ -611,7 +613,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { println!("Transaction data is {:?}", tx.message); } - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); @@ -665,7 +667,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { )?; } - let path = wallet_core.store_persistent_accounts().await?; + let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); diff --git a/wallet/src/config.rs b/wallet/src/config.rs index aa9b5ba..af1f493 100644 --- a/wallet/src/config.rs +++ b/wallet/src/config.rs @@ -46,6 +46,12 @@ pub enum PersistentAccountData { Private(PersistentAccountDataPrivate), } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PersistentStorage { + pub accounts: Vec, + pub last_synced_block: u64, +} + impl InitialAccountData { pub fn address(&self) -> nssa::Address { match &self { diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index 83eef43..1d35efb 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -12,8 +12,7 @@ use serde::Serialize; use crate::{ HOME_DIR_ENV_VAR, config::{ - PersistentAccountData, PersistentAccountDataPrivate, PersistentAccountDataPublic, - WalletConfig, + PersistentAccountDataPrivate, PersistentAccountDataPublic, PersistentStorage, WalletConfig, }, }; @@ -30,21 +29,24 @@ pub async fn fetch_config() -> Result { Ok(serde_json::from_slice(&config_contents)?) } -/// Fetch list of accounts stored at `NSSA_WALLET_HOME_DIR/curr_accounts.json` +/// Fetch data stored at `NSSA_WALLET_HOME_DIR/storage.json` /// /// If file not present, it is considered as empty list of persistent accounts -pub async fn fetch_persistent_accounts() -> Result> { +pub async fn fetch_persistent_storage() -> Result { let home = get_home()?; - let accs_path = home.join("curr_accounts.json"); - let mut persistent_accounts_content = vec![]; + let accs_path = home.join("storage.json"); + let mut storage_content = vec![]; match tokio::fs::File::open(accs_path).await { Ok(mut file) => { - file.read_to_end(&mut persistent_accounts_content).await?; - Ok(serde_json::from_slice(&persistent_accounts_content)?) + file.read_to_end(&mut storage_content).await?; + Ok(serde_json::from_slice(&storage_content)?) } Err(err) => match err.kind() { - std::io::ErrorKind::NotFound => Ok(vec![]), + std::io::ErrorKind::NotFound => Ok(PersistentStorage { + accounts: vec![], + last_synced_block: 0, + }), _ => { anyhow::bail!("IO error {err:#?}"); } @@ -52,8 +54,11 @@ pub async fn fetch_persistent_accounts() -> Result> { } } -/// Produces a list of accounts for storage -pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec { +/// Produces data for storage +pub fn produce_data_for_storage( + user_data: &NSSAUserData, + last_synced_block: u64, +) -> PersistentStorage { let mut vec_for_storage = vec![]; for (addr, key) in &user_data.pub_account_signing_keys { @@ -77,7 +82,10 @@ pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec Vec { diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 897b7d5..8b9ec78 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -20,15 +20,18 @@ use clap::{Parser, Subcommand}; use nssa_core::{Commitment, MembershipProof}; use tokio::io::AsyncWriteExt; -use crate::cli::{ - WalletSubcommand, account::AccountSubcommand, chain::ChainSubcommand, - native_token_transfer_program::AuthTransferSubcommand, pinata_program::PinataProgramSubcommand, - token_program::TokenProgramAgnosticSubcommand, +use crate::{ + cli::{ + WalletSubcommand, account::AccountSubcommand, chain::ChainSubcommand, + native_token_transfer_program::AuthTransferSubcommand, + pinata_program::PinataProgramAgnosticSubcommand, + token_program::TokenProgramAgnosticSubcommand, + }, + config::PersistentStorage, + helperfunctions::fetch_persistent_storage, }; use crate::{ - helperfunctions::{ - fetch_config, fetch_persistent_accounts, get_home, produce_data_for_storage, - }, + helperfunctions::{fetch_config, get_home, produce_data_for_storage}, poller::TxPoller, }; @@ -48,6 +51,7 @@ pub struct WalletCore { pub storage: WalletChainStore, pub poller: TxPoller, pub sequencer_client: Arc, + pub last_synced_block: u64, } impl WalletCore { @@ -57,7 +61,10 @@ impl WalletCore { let mut storage = WalletChainStore::new(config)?; - let persistent_accounts = fetch_persistent_accounts().await?; + let PersistentStorage { + accounts: persistent_accounts, + last_synced_block, + } = fetch_persistent_storage().await?; for pers_acc_data in persistent_accounts { storage.insert_account_data(pers_acc_data); } @@ -66,23 +73,24 @@ impl WalletCore { storage, poller: tx_poller, sequencer_client: client.clone(), + last_synced_block, }) } - ///Store persistent accounts at home - pub async fn store_persistent_accounts(&self) -> Result { + ///Store persistent data at home + pub async fn store_persistent_data(&self) -> Result { let home = get_home()?; - let accs_path = home.join("curr_accounts.json"); + let storage_path = home.join("storage.json"); - let data = produce_data_for_storage(&self.storage.user_data); - let accs = serde_json::to_vec_pretty(&data)?; + let data = produce_data_for_storage(&self.storage.user_data, self.last_synced_block); + let storage = serde_json::to_vec_pretty(&data)?; - let mut accs_file = tokio::fs::File::create(accs_path.as_path()).await?; - accs_file.write_all(&accs).await?; + let mut storage_file = tokio::fs::File::create(storage_path.as_path()).await?; + storage_file.write_all(&storage).await?; - info!("Stored accounts data at {accs_path:#?}"); + info!("Stored data at {storage_path:#?}"); - Ok(accs_path) + Ok(storage_path) } pub fn create_new_account_public(&mut self) -> Address { @@ -201,11 +209,10 @@ pub enum Command { Account(AccountSubcommand), ///Pinata command #[command(subcommand)] - Pinata(PinataProgramSubcommand), + Pinata(PinataProgramAgnosticSubcommand), ///Token command #[command(subcommand)] Token(TokenProgramAgnosticSubcommand), - AuthenticatedTransferInitializePublicAccount {}, // Check the wallet can connect to the node and builtin local programs // match the remote versions CheckHealth {}, @@ -229,6 +236,7 @@ pub enum SubcommandReturnValue { RegisterAccount { addr: nssa::Address }, Account(nssa::Account), Empty, + SyncedToBlock(u64), } pub async fn execute_subcommand(command: Command) -> Result { @@ -284,25 +292,6 @@ pub async fn execute_subcommand(command: Command) -> Result { - let addr = wallet_core.create_new_account_public(); - - println!("Generated new account with addr {addr}"); - - let path = wallet_core.store_persistent_accounts().await?; - - println!("Stored persistent accounts at {path:#?}"); - - let res = wallet_core - .register_account_under_authenticated_transfers_programs(addr) - .await?; - - println!("Results of tx send is {res:#?}"); - - let _transfer_tx = wallet_core.poll_native_token_transfer(res.tx_hash).await?; - - SubcommandReturnValue::RegisterAccount { addr } - } Command::Token(token_subcommand) => { token_subcommand.handle_subcommand(&mut wallet_core).await? } @@ -311,6 +300,80 @@ pub async fn execute_subcommand(command: Command) -> Result, + wallet_core: &mut WalletCore, +) -> Result<()> { + for block_id in start..(stop + 1) { + let block = + borsh::from_slice::(&seq_client.get_block(block_id).await?.block)?; + + for tx in block.transactions { + let nssa_tx = NSSATransaction::try_from(&tx)?; + + if let NSSATransaction::PrivacyPreserving(tx) = nssa_tx { + let mut affected_accounts = vec![]; + + for (acc_addr, (key_chain, _)) in + &wallet_core.storage.user_data.user_private_accounts + { + let view_tag = EncryptedAccountData::compute_view_tag( + key_chain.nullifer_public_key.clone(), + key_chain.incoming_viewing_public_key.clone(), + ); + + for (ciph_id, encrypted_data) in tx + .message() + .encrypted_private_post_states + .iter() + .enumerate() + { + if encrypted_data.view_tag == view_tag { + let ciphertext = &encrypted_data.ciphertext; + let commitment = &tx.message.new_commitments[ciph_id]; + let shared_secret = key_chain + .calculate_shared_secret_receiver(encrypted_data.epk.clone()); + + let res_acc = nssa_core::EncryptionScheme::decrypt( + ciphertext, + &shared_secret, + commitment, + ciph_id as u32, + ); + + if let Some(res_acc) = res_acc { + println!( + "Received new account for addr {acc_addr:#?} with account object {res_acc:#?}" + ); + + affected_accounts.push((*acc_addr, res_acc)); + } + } + } + } + + for (affected_addr, new_acc) in affected_accounts { + wallet_core + .storage + .insert_private_account_data(affected_addr, new_acc); + } + } + } + + wallet_core.last_synced_block = block_id; + wallet_core.store_persistent_data().await?; + + println!( + "Block at id {block_id} with timestamp {} parsed", + block.timestamp + ); + } + + Ok(()) +} + pub async fn execute_continious_run() -> Result<()> { let config = fetch_config().await?; let seq_client = Arc::new(SequencerClient::new(config.sequencer_addr.clone())?); @@ -320,70 +383,13 @@ pub async fn execute_continious_run() -> Result<()> { let mut curr_last_block = latest_block_num; loop { - for block_id in curr_last_block..(latest_block_num + 1) { - let block = borsh::from_slice::( - &seq_client.get_block(block_id).await?.block, - )?; - - for tx in block.transactions { - let nssa_tx = NSSATransaction::try_from(&tx)?; - - if let NSSATransaction::PrivacyPreserving(tx) = nssa_tx { - let mut affected_accounts = vec![]; - - for (acc_addr, (key_chain, _)) in - &wallet_core.storage.user_data.user_private_accounts - { - let view_tag = EncryptedAccountData::compute_view_tag( - key_chain.nullifer_public_key.clone(), - key_chain.incoming_viewing_public_key.clone(), - ); - - for (ciph_id, encrypted_data) in tx - .message() - .encrypted_private_post_states - .iter() - .enumerate() - { - if encrypted_data.view_tag == view_tag { - let ciphertext = &encrypted_data.ciphertext; - let commitment = &tx.message.new_commitments[ciph_id]; - let shared_secret = key_chain - .calculate_shared_secret_receiver(encrypted_data.epk.clone()); - - let res_acc = nssa_core::EncryptionScheme::decrypt( - ciphertext, - &shared_secret, - commitment, - ciph_id as u32, - ); - - if let Some(res_acc) = res_acc { - println!( - "Received new account for addr {acc_addr:#?} with account object {res_acc:#?}" - ); - - affected_accounts.push((*acc_addr, res_acc)); - } - } - } - } - - for (affected_addr, new_acc) in affected_accounts { - wallet_core - .storage - .insert_private_account_data(affected_addr, new_acc); - } - } - } - - wallet_core.store_persistent_accounts().await?; - - println!( - "Block at id {block_id} with timestamp {} parsed", - block.timestamp - ); - } + parse_block_range( + curr_last_block, + latest_block_num, + seq_client.clone(), + &mut wallet_core, + ) + .await?; curr_last_block = latest_block_num + 1; From 785ed5f1696e54a57a04b58e05d485e3e5f6fd4e Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Tue, 28 Oct 2025 16:53:39 +0200 Subject: [PATCH 07/10] doc: cli docs added --- wallet/src/cli/account.rs | 10 ++++++---- wallet/src/cli/chain.rs | 4 ++++ .../src/cli/native_token_transfer_program.rs | 16 +++++++++++----- wallet/src/cli/pinata_program.rs | 4 ++-- wallet/src/cli/token_program.rs | 16 ++++++++++++---- wallet/src/lib.rs | 19 ++++++++++++------- 6 files changed, 47 insertions(+), 22 deletions(-) diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index 06218fe..54e383a 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -69,14 +69,16 @@ impl TokenHolding { ///Represents generic chain CLI subcommand #[derive(Subcommand, Debug, Clone)] pub enum AccountSubcommand { - ///Get + ///Get account data Get { - #[arg(long)] + ///Flag to get raw account data + #[arg(short, long)] raw: bool, + ///Valid 32 byte base58 string with privacy prefix #[arg(short, long)] addr: String, }, - ///New + ///Produce new public or private account #[command(subcommand)] New(NewSubcommand), ///Sync private accounts @@ -260,7 +262,7 @@ impl WalletSubcommand for AccountSubcommand { .is_empty() { parse_block_range( - last_synced_block, + last_synced_block + 1, curr_last_block, wallet_core.sequencer_client.clone(), wallet_core, diff --git a/wallet/src/cli/chain.rs b/wallet/src/cli/chain.rs index aec2c9a..a6e7999 100644 --- a/wallet/src/cli/chain.rs +++ b/wallet/src/cli/chain.rs @@ -6,12 +6,16 @@ use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand}; ///Represents generic chain CLI subcommand #[derive(Subcommand, Debug, Clone)] pub enum ChainSubcommand { + ///Get current block id from sequencer CurrentBlockId {}, + ///Get block at id from sequencer Block { #[arg(short, long)] id: u64, }, + ///Get transaction at hash from sequencer Transaction { + ///hash - valid 32 byte hex string #[arg(short, long)] hash: String, }, diff --git a/wallet/src/cli/native_token_transfer_program.rs b/wallet/src/cli/native_token_transfer_program.rs index 19e8368..73243d2 100644 --- a/wallet/src/cli/native_token_transfer_program.rs +++ b/wallet/src/cli/native_token_transfer_program.rs @@ -12,22 +12,28 @@ use crate::{ ///Represents generic CLI subcommand for a wallet working with native token transfer program #[derive(Subcommand, Debug, Clone)] pub enum AuthTransferSubcommand { + ///Initialize account under authenticated transfer program Init { - ///addr - valid 32 byte base58 string + ///addr - valid 32 byte base58 string with privacy prefix #[arg(long)] addr: String, }, + ///Send native tokens from one account to another with variable privacy + /// + ///If receiver is private, then `to` and (`to_npk` , `to_ipk`) is a mutually exclusive patterns. + /// + ///First is used for owned accounts, second otherwise. Send { - ///from - valid 32 byte base58 string + ///from - valid 32 byte base58 string with privacy prefix #[arg(long)] from: String, - ///to - valid 32 byte base58 string + ///to - valid 32 byte base58 string with privacy prefix #[arg(long)] to: Option, - ///to_npk - valid 32 byte base58 string + ///to_npk - valid 32 byte hex string #[arg(long)] to_npk: Option, - ///to_ipk - valid 33 byte base58 string + ///to_ipk - valid 33 byte hex string #[arg(long)] to_ipk: Option, ///amount - amount of balance to move diff --git a/wallet/src/cli/pinata_program.rs b/wallet/src/cli/pinata_program.rs index 6e79362..fafd5f1 100644 --- a/wallet/src/cli/pinata_program.rs +++ b/wallet/src/cli/pinata_program.rs @@ -12,9 +12,9 @@ use crate::{ ///Represents generic CLI subcommand for a wallet working with pinata program #[derive(Subcommand, Debug, Clone)] pub enum PinataProgramAgnosticSubcommand { - ///Claim + ///Claim pinata Claim { - ///to_addr - valid 32 byte base58 string + ///to_addr - valid 32 byte base58 string with privacy prefix #[arg(long)] to_addr: String, ///solution - solution to pinata challenge diff --git a/wallet/src/cli/token_program.rs b/wallet/src/cli/token_program.rs index 99ebecd..e077efb 100644 --- a/wallet/src/cli/token_program.rs +++ b/wallet/src/cli/token_program.rs @@ -12,11 +12,14 @@ use crate::{ ///Represents generic CLI subcommand for a wallet working with token program #[derive(Subcommand, Debug, Clone)] pub enum TokenProgramAgnosticSubcommand { + ///Produce new ERC-20 token + /// + ///Currently the only supported privacy options is for public definition New { - ///addr - valid 32 byte base58 string + ///definition_addr - valid 32 byte base58 string with privacy prefix #[arg(long)] definition_addr: String, - ///addr - valid 32 byte base58 string + ///supply_addr - valid 32 byte base58 string with privacy prefix #[arg(long)] supply_addr: String, #[arg(short, long)] @@ -24,11 +27,16 @@ pub enum TokenProgramAgnosticSubcommand { #[arg(short, long)] total_supply: u128, }, + ///Send tokens from one account to another with variable privacy + /// + ///If receiver is private, then `to` and (`to_npk` , `to_ipk`) is a mutually exclusive patterns. + /// + ///First is used for owned accounts, second otherwise. Send { - ///from - valid 32 byte base58 string + ///from - valid 32 byte base58 string with privacy prefix #[arg(long)] from: String, - ///to - valid 32 byte base58 string + ///to - valid 32 byte base58 string with privacy prefix #[arg(long)] to: Option, ///to_npk - valid 32 byte hex string diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 8b9ec78..dc17292 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -198,27 +198,32 @@ impl WalletCore { #[derive(Subcommand, Debug, Clone)] #[clap(about)] pub enum Command { - ///Transfer command + ///Authenticated transfer subcommand #[command(subcommand)] AuthTransfer(AuthTransferSubcommand), - ///Chain command + ///Generic chain info subcommand #[command(subcommand)] ChainInfo(ChainSubcommand), - ///Chain command + ///Account view and sync subcommand #[command(subcommand)] Account(AccountSubcommand), - ///Pinata command + ///Pinata program interaction subcommand #[command(subcommand)] Pinata(PinataProgramAgnosticSubcommand), - ///Token command + ///Token program interaction subcommand #[command(subcommand)] Token(TokenProgramAgnosticSubcommand), - // Check the wallet can connect to the node and builtin local programs - // match the remote versions + /// Check the wallet can connect to the node and builtin local programs + /// match the remote versions CheckHealth {}, } ///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config +/// +/// All account adresses must be valid 32 byte base58 strings. +/// +/// All account addresses must be provided as {privacy_prefix}/{addr}, +/// where valid options for `privacy_prefix` is `Public` and `Private` #[derive(Parser, Debug)] #[clap(version, about)] pub struct Args { From a903c221db93a8d19c1ff9c42c9a814051977232 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Wed, 29 Oct 2025 12:02:41 +0200 Subject: [PATCH 08/10] fix: tests fix --- integration_tests/src/test_suite_map.rs | 45 +++++++++++-------- .../src/cli/native_token_transfer_program.rs | 4 +- wallet/src/cli/token_program.rs | 6 +-- wallet/src/lib.rs | 4 +- 4 files changed, 34 insertions(+), 25 deletions(-) diff --git a/integration_tests/src/test_suite_map.rs b/integration_tests/src/test_suite_map.rs index 0bf8f00..e0c7f86 100644 --- a/integration_tests/src/test_suite_map.rs +++ b/integration_tests/src/test_suite_map.rs @@ -31,7 +31,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_success() { - info!("test_success"); + info!("########## test_success ##########"); let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: make_public_account_input_from_str(ACC_SENDER), to: Some(make_public_account_input_from_str(ACC_RECEIVER)), @@ -70,7 +70,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_success_move_to_another_account() { - info!("test_success_move_to_another_account"); + info!("########## test_success_move_to_another_account ##########"); let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public {})); let wallet_config = fetch_config().await.unwrap(); @@ -134,7 +134,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_failure() { - info!("test_failure"); + info!("########## test_failure ##########"); let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: make_public_account_input_from_str(ACC_SENDER), to: Some(make_public_account_input_from_str(ACC_RECEIVER)), @@ -175,7 +175,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_success_two_transactions() { - info!("test_success_two_transactions"); + info!("########## test_success_two_transactions ##########"); let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: make_public_account_input_from_str(ACC_SENDER), to: Some(make_public_account_input_from_str(ACC_RECEIVER)), @@ -245,7 +245,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_get_account() { - info!("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(); @@ -268,6 +268,7 @@ pub fn prepare_function_map() -> HashMap { /// token transfer to a new account. #[nssa_integration_test] pub async fn test_success_token_program() { + info!("########## test_success_token_program ##########"); let wallet_config = fetch_config().await.unwrap(); // Create new account for the token definition @@ -424,6 +425,7 @@ pub fn prepare_function_map() -> HashMap { /// private token transfer to a new account. All accounts are owned except definition. #[nssa_integration_test] pub async fn test_success_token_program_private_owned() { + info!("########## test_success_token_program_private_owned ##########"); let wallet_config = fetch_config().await.unwrap(); // Create new account for the token definition (public) @@ -574,6 +576,7 @@ pub fn prepare_function_map() -> HashMap { /// private token transfer to a new account. #[nssa_integration_test] pub async fn test_success_token_program_private_claiming_path() { + info!("########## test_success_token_program_private_claiming_path ##########"); let wallet_config = fetch_config().await.unwrap(); // Create new account for the token definition (public) @@ -705,6 +708,7 @@ pub fn prepare_function_map() -> HashMap { /// shielded token transfer to a new account. All accounts are owned except definition. #[nssa_integration_test] pub async fn test_success_token_program_shielded_owned() { + info!("########## test_success_token_program_shielded_owned ##########"); let wallet_config = fetch_config().await.unwrap(); // Create new account for the token definition (public) @@ -835,6 +839,7 @@ pub fn prepare_function_map() -> HashMap { /// deshielded token transfer to a new account. All accounts are owned except definition. #[nssa_integration_test] pub async fn test_success_token_program_deshielded_owned() { + info!("########## test_success_token_program_deshielded_owned ##########"); let wallet_config = fetch_config().await.unwrap(); // Create new account for the token definition (public) @@ -973,7 +978,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_success_private_transfer_to_another_owned_account() { - info!("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(); @@ -1009,7 +1014,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_success_private_transfer_to_another_foreign_account() { - info!("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); @@ -1055,7 +1060,9 @@ pub fn prepare_function_map() -> HashMap { #[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"); + info!( + "########## test_success_private_transfer_to_another_owned_account_claiming_path ##########" + ); let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private {})); @@ -1119,7 +1126,9 @@ pub fn prepare_function_map() -> HashMap { #[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"); + 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(); @@ -1189,7 +1198,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_success_deshielded_transfer_to_another_account() { - info!("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(); @@ -1238,7 +1247,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_success_shielded_transfer_to_another_owned_account() { - info!("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(); @@ -1280,7 +1289,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_success_shielded_transfer_to_another_foreign_account() { - info!("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); @@ -1325,7 +1334,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_pinata() { - info!("test_pinata"); + info!("########## test_pinata ##########"); let pinata_addr = PINATA_BASE58; let pinata_prize = 150; let solution = 989106; @@ -1370,7 +1379,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_program_deployment() { - info!("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); @@ -1417,7 +1426,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_authenticated_transfer_initialize_function() { - info!("test initialize account for authenticated transfer"); + info!("########## test initialize account for authenticated transfer ##########"); let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public {})); let SubcommandReturnValue::RegisterAccount { addr } = wallet::execute_subcommand(command).await.unwrap() @@ -1426,7 +1435,7 @@ pub fn prepare_function_map() -> HashMap { }; let command = Command::AuthTransfer(AuthTransferSubcommand::Init { - addr: addr.to_string(), + addr: make_public_account_input_from_str(&addr.to_string()), }); wallet::execute_subcommand(command).await.unwrap(); @@ -1453,7 +1462,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_pinata_private_receiver() { - info!("test_pinata_private_receiver"); + info!("########## test_pinata_private_receiver ##########"); let pinata_addr = PINATA_BASE58; let pinata_prize = 150; let solution = 989106; @@ -1510,7 +1519,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_pinata_private_receiver_new_account() { - info!("test_pinata_private_receiver"); + info!("########## test_pinata_private_receiver ##########"); let pinata_addr = PINATA_BASE58; let pinata_prize = 150; let solution = 989106; diff --git a/wallet/src/cli/native_token_transfer_program.rs b/wallet/src/cli/native_token_transfer_program.rs index 73243d2..e286bb9 100644 --- a/wallet/src/cli/native_token_transfer_program.rs +++ b/wallet/src/cli/native_token_transfer_program.rs @@ -19,9 +19,9 @@ pub enum AuthTransferSubcommand { addr: String, }, ///Send native tokens from one account to another with variable privacy - /// + /// ///If receiver is private, then `to` and (`to_npk` , `to_ipk`) is a mutually exclusive patterns. - /// + /// ///First is used for owned accounts, second otherwise. Send { ///from - valid 32 byte base58 string with privacy prefix diff --git a/wallet/src/cli/token_program.rs b/wallet/src/cli/token_program.rs index e077efb..483dee5 100644 --- a/wallet/src/cli/token_program.rs +++ b/wallet/src/cli/token_program.rs @@ -13,7 +13,7 @@ use crate::{ #[derive(Subcommand, Debug, Clone)] pub enum TokenProgramAgnosticSubcommand { ///Produce new ERC-20 token - /// + /// ///Currently the only supported privacy options is for public definition New { ///definition_addr - valid 32 byte base58 string with privacy prefix @@ -28,9 +28,9 @@ pub enum TokenProgramAgnosticSubcommand { total_supply: u128, }, ///Send tokens from one account to another with variable privacy - /// + /// ///If receiver is private, then `to` and (`to_npk` , `to_ipk`) is a mutually exclusive patterns. - /// + /// ///First is used for owned accounts, second otherwise. Send { ///from - valid 32 byte base58 string with privacy prefix diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index dc17292..3beac67 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -219,9 +219,9 @@ pub enum Command { } ///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config -/// +/// /// All account adresses must be valid 32 byte base58 strings. -/// +/// /// All account addresses must be provided as {privacy_prefix}/{addr}, /// where valid options for `privacy_prefix` is `Public` and `Private` #[derive(Parser, Debug)] From c2b8459645878fbd3c6c5e2e230417fd214602e1 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Thu, 30 Oct 2025 15:00:21 +0200 Subject: [PATCH 09/10] fix: suggestions fix 1 --- wallet/src/cli/account.rs | 18 +++++++++++++++--- wallet/src/cli/token_program.rs | 4 ++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index 54e383a..3ff4470 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -1,7 +1,7 @@ use anyhow::Result; use base58::ToBase58; use clap::Subcommand; -use nssa::{Address, program::Program}; +use nssa::{Account, Address, program::Program}; use serde::Serialize; use crate::{ @@ -103,7 +103,7 @@ impl WalletSubcommand for NewSubcommand { NewSubcommand::Public {} => { let addr = wallet_core.create_new_account_public(); - println!("Generated new account with addr {addr}"); + println!("Generated new account with addr Public/{addr}"); let path = wallet_core.store_persistent_data().await?; @@ -121,7 +121,7 @@ impl WalletSubcommand for NewSubcommand { .unwrap(); println!( - "Generated new account with addr {}", + "Generated new account with addr Private/{}", addr.to_bytes().to_base58() ); println!("With npk {}", hex::encode(key.nullifer_public_key.0)); @@ -205,6 +205,12 @@ impl WalletSubcommand for AccountSubcommand { .ok_or(anyhow::anyhow!("Private account not found in storage"))?, }; + if account == Account::default() { + println!("Account is Uninitialized"); + + return Ok(SubcommandReturnValue::Empty); + } + if raw { let account_hr: HumanReadableAccount = account.clone().into(); println!("{}", serde_json::to_string(&account_hr).unwrap()); @@ -219,16 +225,22 @@ impl WalletSubcommand for AccountSubcommand { _ if account.program_owner == auth_tr_prog_id => { let acc_view: AuthenticatedTransferAccountView = account.into(); + println!("Account owned by authenticated transfer program"); + serde_json::to_string(&acc_view)? } _ if account.program_owner == token_prog_id => { if let Some(token_def) = TokenDefinition::parse(&account.data) { let acc_view: TokedDefinitionAccountView = token_def.into(); + println!("Definition account owned by token program"); + serde_json::to_string(&acc_view)? } else if let Some(token_hold) = TokenHolding::parse(&account.data) { let acc_view: TokedHoldingAccountView = token_hold.into(); + println!("Holding account owned by token program"); + serde_json::to_string(&acc_view)? } else { anyhow::bail!("Invalid data for account {addr:#?} with token program"); diff --git a/wallet/src/cli/token_program.rs b/wallet/src/cli/token_program.rs index 483dee5..6ce7dbe 100644 --- a/wallet/src/cli/token_program.rs +++ b/wallet/src/cli/token_program.rs @@ -12,7 +12,7 @@ use crate::{ ///Represents generic CLI subcommand for a wallet working with token program #[derive(Subcommand, Debug, Clone)] pub enum TokenProgramAgnosticSubcommand { - ///Produce new ERC-20 token + ///Produce a new token /// ///Currently the only supported privacy options is for public definition New { @@ -94,7 +94,7 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { anyhow::bail!("Unavailable privacy pairing") } (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { - //Probably valid. If definition is not public, but supply is it is very suspicious. + //ToDo: Probably valid. If definition is not public, but supply is it is very suspicious. anyhow::bail!("Unavailable privacy pairing") } }; From 18dca9407c5b017c8ec677cf93451e518c52a073 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Fri, 31 Oct 2025 10:16:15 +0200 Subject: [PATCH 10/10] fix: config update --- .../configs/debug/sequencer_config.json | 126 +++++++++--------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index 19ff458..acd0caa 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -8,49 +8,49 @@ "port": 3040, "initial_accounts": [ { - "addr": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44", + "addr": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", "balance": 10000 }, { - "addr": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc", + "addr": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", "balance": 20000 } ], "initial_commitments": [ { "npk": [ - 193, - 209, - 150, - 113, - 47, - 241, - 48, - 145, - 250, - 79, - 235, - 51, - 119, - 40, - 184, - 232, - 5, + 63, + 202, + 178, + 231, + 183, + 82, + 237, + 212, + 216, 221, - 36, - 21, - 201, - 106, - 90, - 210, - 129, - 106, - 71, - 99, - 208, + 215, + 255, 153, - 75, - 215 + 101, + 177, + 161, + 254, + 210, + 128, + 122, + 54, + 190, + 230, + 151, + 183, + 64, + 225, + 229, + 113, + 1, + 228, + 97 ], "account": { "program_owner": [ @@ -70,38 +70,38 @@ }, { "npk": [ - 27, - 250, + 192, + 251, + 166, + 243, + 167, + 236, + 84, + 249, + 35, 136, - 142, - 88, - 128, - 138, - 21, - 49, - 183, - 118, - 160, - 117, - 114, - 110, - 47, - 136, - 87, - 60, - 70, - 59, - 60, - 18, - 223, - 23, - 147, - 241, - 5, - 184, - 103, + 130, + 172, + 219, 225, - 105 + 161, + 139, + 229, + 89, + 243, + 125, + 194, + 213, + 209, + 30, + 23, + 174, + 100, + 244, + 124, + 74, + 140, + 47 ], "account": { "program_owner": [ @@ -154,4 +154,4 @@ 37, 37 ] -} +} \ No newline at end of file