diff --git a/Cargo.lock b/Cargo.lock index dad8d4e..8dd06ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -830,18 +830,18 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytemuck" -version = "1.23.1" +version = "1.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.8.1" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" +checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29" dependencies = [ "proc-macro2", "quote", @@ -2200,6 +2200,7 @@ dependencies = [ "env_logger", "hex", "log", + "nssa", "sequencer_core", "sequencer_runner", "tempfile", @@ -4680,6 +4681,7 @@ version = "0.1.0" dependencies = [ "anyhow", "base64 0.22.1", + "bytemuck", "clap", "common", "env_logger", diff --git a/common/src/rpc_primitives/requests.rs b/common/src/rpc_primitives/requests.rs index 7ac271a..616d482 100644 --- a/common/src/rpc_primitives/requests.rs +++ b/common/src/rpc_primitives/requests.rs @@ -49,7 +49,7 @@ pub struct GetAccountsNoncesRequest { } #[derive(Serialize, Deserialize, Debug)] -pub struct GetAccountDataRequest { +pub struct GetAccountRequest { pub address: String, } @@ -68,8 +68,8 @@ parse_request!(GetInitialTestnetAccountsRequest); parse_request!(GetAccountBalanceRequest); parse_request!(GetTransactionByHashRequest); parse_request!(GetAccountsNoncesRequest); -parse_request!(GetAccountDataRequest); parse_request!(GetProofByCommitmentRequest); +parse_request!(GetAccountRequest); #[derive(Serialize, Deserialize, Debug)] pub struct HelloResponse { @@ -118,11 +118,8 @@ pub struct GetTransactionByHashResponse { } #[derive(Serialize, Deserialize, Debug)] -pub struct GetAccountDataResponse { - pub balance: u128, - pub nonce: u128, - pub program_owner: [u32; 8], - pub data: Vec, +pub struct GetAccountResponse { + pub account: nssa::Account, } #[derive(Serialize, Deserialize, Debug)] diff --git a/common/src/sequencer_client/mod.rs b/common/src/sequencer_client/mod.rs index 896e377..88595b7 100644 --- a/common/src/sequencer_client/mod.rs +++ b/common/src/sequencer_client/mod.rs @@ -8,8 +8,9 @@ use reqwest::Client; use serde_json::Value; use crate::rpc_primitives::requests::{ - GetAccountsNoncesRequest, GetAccountsNoncesResponse, GetProofByCommitmentRequest, - GetProofByCommitmentResponse, GetTransactionByHashRequest, GetTransactionByHashResponse, + GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, + GetProofByCommitmentRequest, GetProofByCommitmentResponse, GetTransactionByHashRequest, + GetTransactionByHashResponse, }; use crate::sequencer_client::json::AccountInitialData; use crate::transaction::{EncodedTransaction, NSSATransaction}; @@ -109,6 +110,21 @@ impl SequencerClient { Ok(resp_deser) } + pub async fn get_account( + &self, + address: String, + ) -> Result { + let block_req = GetAccountRequest { address }; + + let req = serde_json::to_value(block_req)?; + + let resp = self.call_method_with_payload("get_account", req).await?; + + let resp_deser = serde_json::from_value(resp)?; + + Ok(resp_deser) + } + ///Get transaction details for `hash`. pub async fn get_transaction_by_hash( &self, diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index 16e1b2e..a01935f 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -29,3 +29,6 @@ path = "../wallet" [dependencies.common] path = "../common" + +[dependencies.nssa] +path = "../nssa" diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index d3994ab..e73b5a1 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -5,6 +5,7 @@ use anyhow::Result; use clap::Parser; use common::sequencer_client::SequencerClient; use log::{info, warn}; +use nssa::program::Program; use sequencer_core::config::SequencerConfig; use sequencer_runner::startup_sequencer; use tempfile::TempDir; @@ -272,6 +273,36 @@ pub async fn test_success_two_transactions() { info!("Second TX Success!"); } +pub async fn test_get_account_wallet_command() { + let command = Command::GetAccount { + addr: ACC_SENDER.to_string(), + }; + + let wallet_config = fetch_config().unwrap(); + + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + + wallet::execute_subcommand(command).await.unwrap(); + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + info!("Checking correct account"); + let account = seq_client + .get_account(ACC_SENDER.to_string()) + .await + .unwrap() + .account; + + assert_eq!( + account.program_owner, + Program::authenticated_transfer_program().id() + ); + assert_eq!(account.balance, 10000); + assert!(account.data.is_empty()); + assert_eq!(account.nonce, 0); +} + macro_rules! test_cleanup_wrap { ($home_dir:ident, $test_func:ident) => {{ let res = pre_test($home_dir.clone()).await.unwrap(); @@ -304,6 +335,9 @@ pub async fn main_tests_runner() -> Result<()> { "test_failure" => { test_cleanup_wrap!(home_dir, test_failure); } + "test_get_account_wallet_command" => { + test_cleanup_wrap!(home_dir, test_get_account_wallet_command); + } "test_success_two_transactions" => { test_cleanup_wrap!(home_dir, test_success_two_transactions); } @@ -312,6 +346,7 @@ pub async fn main_tests_runner() -> Result<()> { test_cleanup_wrap!(home_dir, test_success); test_cleanup_wrap!(home_dir, test_failure); test_cleanup_wrap!(home_dir, test_success_two_transactions); + test_cleanup_wrap!(home_dir, test_get_account_wallet_command); } _ => { anyhow::bail!("Unknown test name"); diff --git a/key_protocol/src/key_management/ephemeral_key_holder.rs b/key_protocol/src/key_management/ephemeral_key_holder.rs index e62d9b6..b4835ff 100644 --- a/key_protocol/src/key_management/ephemeral_key_holder.rs +++ b/key_protocol/src/key_management/ephemeral_key_holder.rs @@ -1,5 +1,3 @@ -use elliptic_curve::PrimeField; -use k256::Scalar; use log::info; use nssa_core::{ NullifierPublicKey, SharedSecretKey, @@ -29,11 +27,11 @@ impl EphemeralKeyHolder { let hash_recepient = hasher.finalize(); let mut hasher = sha2::Sha256::new(); - hasher.update(sender_outgoing_viewing_secret_key.to_bytes()); + hasher.update(sender_outgoing_viewing_secret_key); hasher.update(hash_recepient); Self { - ephemeral_secret_key: Scalar::from_repr(hasher.finalize()).unwrap(), + ephemeral_secret_key: hasher.finalize().into(), } } diff --git a/key_protocol/src/key_management/mod.rs b/key_protocol/src/key_management/mod.rs index bcd3796..5f5f2aa 100644 --- a/key_protocol/src/key_management/mod.rs +++ b/key_protocol/src/key_management/mod.rs @@ -98,8 +98,8 @@ impl KeyChain { #[cfg(test)] mod tests { use aes_gcm::aead::OsRng; - use elliptic_curve::ff::Field; - use k256::{AffinePoint, Scalar}; + use k256::AffinePoint; + use rand::RngCore; use super::*; @@ -117,7 +117,8 @@ mod tests { let address_key_holder = KeyChain::new_os_random(); // Generate a random ephemeral public key sender - let scalar = Scalar::random(&mut OsRng); + let mut scalar = [0; 32]; + OsRng.fill_bytes(&mut scalar); let ephemeral_public_key_sender = EphemeralPublicKey::from_scalar(scalar); // Calculate shared secret diff --git a/key_protocol/src/key_management/secret_holders.rs b/key_protocol/src/key_management/secret_holders.rs index 10d5b42..89da95c 100644 --- a/key_protocol/src/key_management/secret_holders.rs +++ b/key_protocol/src/key_management/secret_holders.rs @@ -1,8 +1,9 @@ use bip39::Mnemonic; use common::TreeHashType; -use elliptic_curve::PrimeField; -use k256::Scalar; -use nssa_core::{NullifierPublicKey, NullifierSecretKey, encryption::IncomingViewingPublicKey}; +use nssa_core::{ + NullifierPublicKey, NullifierSecretKey, + encryption::{IncomingViewingPublicKey, Scalar}, +}; use rand::{RngCore, rngs::OsRng}; use serde::{Deserialize, Serialize}; use sha2::{Digest, digest::FixedOutput}; @@ -79,9 +80,7 @@ impl SecretSpendingKey { hasher.update([2u8]); hasher.update([0u8; 22]); - let hash = ::from(hasher.finalize_fixed()); - - IncomingViewingSecretKey::from_repr(hash.into()).unwrap() + ::from(hasher.finalize_fixed()) } pub fn generate_outgoing_viewing_secret_key(&self) -> OutgoingViewingSecretKey { @@ -92,9 +91,7 @@ impl SecretSpendingKey { hasher.update([3u8]); hasher.update([0u8; 22]); - let hash = ::from(hasher.finalize_fixed()); - - OutgoingViewingSecretKey::from_repr(hash.into()).unwrap() + ::from(hasher.finalize_fixed()) } pub fn produce_private_key_holder(&self) -> PrivateKeyHolder { diff --git a/nssa/core/src/encryption/mod.rs b/nssa/core/src/encryption/mod.rs index 9f66bce..f2dc18e 100644 --- a/nssa/core/src/encryption/mod.rs +++ b/nssa/core/src/encryption/mod.rs @@ -13,6 +13,8 @@ pub use shared_key_derivation::{EphemeralPublicKey, EphemeralSecretKey, Incoming use crate::{Commitment, account::Account}; +pub type Scalar = [u8; 32]; + #[derive(Serialize, Deserialize, Clone)] pub struct SharedSecretKey(pub [u8; 32]); diff --git a/nssa/core/src/encryption/shared_key_derivation.rs b/nssa/core/src/encryption/shared_key_derivation.rs index d20ec12..d40b63e 100644 --- a/nssa/core/src/encryption/shared_key_derivation.rs +++ b/nssa/core/src/encryption/shared_key_derivation.rs @@ -1,14 +1,14 @@ use serde::{Deserialize, Serialize}; use k256::{ - AffinePoint, EncodedPoint, FieldBytes, ProjectivePoint, Scalar, + AffinePoint, EncodedPoint, FieldBytes, ProjectivePoint, elliptic_curve::{ PrimeField, sec1::{FromEncodedPoint, ToEncodedPoint}, }, }; -use crate::SharedSecretKey; +use crate::{SharedSecretKey, encryption::Scalar}; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct Secp256k1Point(pub Vec); @@ -16,7 +16,7 @@ pub struct Secp256k1Point(pub Vec); impl Secp256k1Point { pub fn from_scalar(value: Scalar) -> Secp256k1Point { let x_bytes: FieldBytes = value.into(); - let x = Scalar::from_repr(x_bytes).unwrap(); + let x = k256::Scalar::from_repr(x_bytes).unwrap(); let p = ProjectivePoint::GENERATOR * x; let q = AffinePoint::from(p); @@ -37,6 +37,7 @@ impl From<&EphemeralSecretKey> for EphemeralPublicKey { impl SharedSecretKey { pub fn new(scalar: &Scalar, point: &Secp256k1Point) -> Self { + let scalar = k256::Scalar::from_repr((*scalar).into()).unwrap(); let point: [u8; 33] = point.0.clone().try_into().unwrap(); let encoded = EncodedPoint::from_bytes(point).unwrap(); diff --git a/nssa/src/lib.rs b/nssa/src/lib.rs index b9c0a1d..bdda8f6 100644 --- a/nssa/src/lib.rs +++ b/nssa/src/lib.rs @@ -9,6 +9,7 @@ mod signature; mod state; pub use address::Address; +pub use nssa_core::account::Account; pub use privacy_preserving_transaction::{ PrivacyPreservingTransaction, circuit::execute_and_prove, }; diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index f350ccf..fef44bc 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -88,7 +88,6 @@ impl Proof { #[cfg(test)] mod tests { - use k256::{Scalar, elliptic_curve::PrimeField}; use nssa_core::{ Commitment, EncryptionScheme, Nullifier, account::{Account, AccountWithMetadata}, @@ -140,7 +139,7 @@ mod tests { let expected_sender_pre = sender.clone(); let recipient_keys = test_private_account_keys_1(); - let esk = Scalar::from_repr([3; 32].into()).unwrap(); + let esk = [3; 32]; let shared_secret = SharedSecretKey::new(&esk, &recipient_keys.ivk()); let (output, proof) = execute_and_prove( @@ -221,10 +220,10 @@ mod tests { Commitment::new(&recipient_keys.npk(), &expected_private_account_2), ]; - let esk_1 = Scalar::from_repr([3; 32].into()).unwrap(); + let esk_1 = [3; 32].into(); let shared_secret_1 = SharedSecretKey::new(&esk_1, &sender_keys.ivk()); - let esk_2 = Scalar::from_repr([5; 32].into()).unwrap(); + let esk_2 = [5; 32]; let shared_secret_2 = SharedSecretKey::new(&esk_2, &recipient_keys.ivk()); let (output, proof) = execute_and_prove( diff --git a/nssa/src/privacy_preserving_transaction/message.rs b/nssa/src/privacy_preserving_transaction/message.rs index 9023e52..a769c72 100644 --- a/nssa/src/privacy_preserving_transaction/message.rs +++ b/nssa/src/privacy_preserving_transaction/message.rs @@ -90,7 +90,6 @@ impl Message { #[cfg(test)] pub mod tests { - use k256::{Scalar, elliptic_curve::PrimeField}; use std::io::Cursor; use nssa_core::{ @@ -152,10 +151,10 @@ pub mod tests { #[test] fn test_encrypted_account_data_constructor() { let npk = NullifierPublicKey::from(&[1; 32]); - let ivk = IncomingViewingPublicKey::from(&Scalar::from_repr([2; 32].into()).unwrap()); + let ivk = IncomingViewingPublicKey::from_scalar([2; 32]); let account = Account::default(); let commitment = Commitment::new(&npk, &account); - let esk = Scalar::from_repr([3; 32].into()).unwrap(); + let esk = [3; 32]; let shared_secret = SharedSecretKey::new(&esk, &ivk); let epk = EphemeralPublicKey::from_scalar(esk); let ciphertext = EncryptionScheme::encrypt(&account, &shared_secret, &commitment, 2); diff --git a/nssa/src/state.rs b/nssa/src/state.rs index 71e5f5e..7922bad 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -227,11 +227,10 @@ pub mod tests { signature::PrivateKey, }; - use k256::{Scalar, elliptic_curve::PrimeField}; use nssa_core::{ Commitment, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey, account::{Account, AccountWithMetadata, Nonce}, - encryption::{EphemeralPublicKey, IncomingViewingPublicKey}, + encryption::{EphemeralPublicKey, IncomingViewingPublicKey, Scalar}, }; fn transfer_transaction( @@ -760,14 +759,14 @@ pub mod tests { pub fn test_private_account_keys_1() -> TestPrivateKeys { TestPrivateKeys { nsk: [13; 32], - isk: Scalar::from_repr([31; 32].into()).unwrap(), + isk: [31; 32], } } pub fn test_private_account_keys_2() -> TestPrivateKeys { TestPrivateKeys { nsk: [38; 32], - isk: Scalar::from_repr([83; 32].into()).unwrap(), + isk: [83; 32], } } @@ -789,7 +788,7 @@ pub mod tests { is_authorized: false, }; - let esk = Scalar::from_repr([3; 32].into()).unwrap(); + let esk = [3; 32]; let shared_secret = SharedSecretKey::new(&esk, &recipient_keys.ivk()); let epk = EphemeralPublicKey::from_scalar(esk); @@ -835,11 +834,11 @@ pub mod tests { is_authorized: false, }; - let esk_1 = Scalar::from_repr([3; 32].into()).unwrap(); + let esk_1 = [3; 32]; let shared_secret_1 = SharedSecretKey::new(&esk_1, &sender_keys.ivk()); let epk_1 = EphemeralPublicKey::from_scalar(esk_1); - let esk_2 = Scalar::from_repr([3; 32].into()).unwrap(); + let esk_2 = [3; 32]; let shared_secret_2 = SharedSecretKey::new(&esk_2, &recipient_keys.ivk()); let epk_2 = EphemeralPublicKey::from_scalar(esk_2); @@ -895,7 +894,7 @@ pub mod tests { is_authorized: false, }; - let esk = Scalar::from_repr([3; 32].into()).unwrap(); + let esk = [3; 32]; let shared_secret = SharedSecretKey::new(&esk, &sender_keys.ivk()); let epk = EphemeralPublicKey::from_scalar(esk); diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index c2e2952..6a9494f 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -12,8 +12,8 @@ use common::{ message::{Message, Request}, parser::RpcRequest, requests::{ - GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountDataRequest, - GetAccountDataResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, + GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountRequest, + GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, GetInitialTestnetAccountsRequest, GetProofByCommitmentRequest, GetProofByCommitmentResponse, GetTransactionByHashRequest, GetTransactionByHashResponse, @@ -38,7 +38,7 @@ pub const GET_LAST_BLOCK: &str = "get_last_block"; pub const GET_ACCOUNT_BALANCE: &str = "get_account_balance"; pub const GET_TRANSACTION_BY_HASH: &str = "get_transaction_by_hash"; pub const GET_ACCOUNTS_NONCES: &str = "get_accounts_nonces"; -pub const GET_ACCOUNT_DATA: &str = "get_account_data"; +pub const GET_ACCOUNT: &str = "get_account"; pub const GET_PROOF_FOR_COMMITMENT: &str = "get_proof_for_commitment"; pub const HELLO_FROM_SEQUENCER: &str = "HELLO_FROM_SEQUENCER"; @@ -206,10 +206,10 @@ impl JsonHandler { respond(helperstruct) } - ///Returns account struct for give address. + /// Returns account struct for given address. /// Address must be a valid hex string of the correct length. - async fn process_get_account_data(&self, request: Request) -> Result { - let get_account_nonces_req = GetAccountDataRequest::parse(Some(request.params))?; + async fn process_get_account(&self, request: Request) -> Result { + let get_account_nonces_req = GetAccountRequest::parse(Some(request.params))?; let address = get_account_nonces_req .address @@ -222,12 +222,7 @@ impl JsonHandler { state.store.state.get_account_by_address(&address) }; - let helperstruct = GetAccountDataResponse { - balance: account.balance, - nonce: account.nonce, - program_owner: account.program_owner, - data: account.data, - }; + let helperstruct = GetAccountResponse { account }; respond(helperstruct) } @@ -282,7 +277,7 @@ impl JsonHandler { GET_INITIAL_TESTNET_ACCOUNTS => self.get_initial_testnet_accounts(request).await, GET_ACCOUNT_BALANCE => self.process_get_account_balance(request).await, GET_ACCOUNTS_NONCES => self.process_get_accounts_nonces(request).await, - GET_ACCOUNT_DATA => self.process_get_account_data(request).await, + GET_ACCOUNT => self.process_get_account(request).await, GET_TRANSACTION_BY_HASH => self.process_get_transaction_by_hash(request).await, GET_PROOF_FOR_COMMITMENT => self.process_get_proof_by_commitment(request).await, _ => Err(RpcErr(RpcError::method_not_found(request.method))), @@ -552,7 +547,7 @@ mod tests { let (json_handler, _, _) = components_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", - "method": "get_account_data", + "method": "get_account", "params": { "address": "efac".repeat(16) }, "id": 1 }); @@ -560,10 +555,12 @@ mod tests { "id": 1, "jsonrpc": "2.0", "result": { - "balance": 0, - "nonce": 0, - "program_owner": [ 0, 0, 0, 0, 0, 0, 0, 0], - "data": [], + "account": { + "balance": 0, + "nonce": 0, + "program_owner": [ 0, 0, 0, 0, 0, 0, 0, 0], + "data": [], + } } }); diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 8cabdda..c579719 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -15,6 +15,7 @@ clap.workspace = true nssa-core = { path = "../nssa/core" } base64.workspace = true k256 = { version = "0.13.3" } +bytemuck = "1.23.2" [dependencies.key_protocol] path = "../key_protocol" diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index f7a319f..b46fe19 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -1,8 +1,10 @@ +use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; use std::{fs::File, io::BufReader, path::PathBuf, str::FromStr}; use anyhow::Result; use key_protocol::key_protocol_core::NSSAUserData; -use nssa::Address; +use nssa::{Account, Address}; +use serde::Serialize; use crate::{ HOME_DIR_ENV_VAR, @@ -12,12 +14,12 @@ use crate::{ }, }; -///Get home dir for wallet. Env var `NSSA_WALLET_HOME_DIR` must be set before execution to succeed. +/// Get home dir for wallet. Env var `NSSA_WALLET_HOME_DIR` must be set before execution to succeed. pub fn get_home() -> Result { Ok(PathBuf::from_str(&std::env::var(HOME_DIR_ENV_VAR)?)?) } -///Fetch config from `NSSA_WALLET_HOME_DIR` +/// Fetch config from `NSSA_WALLET_HOME_DIR` pub fn fetch_config() -> Result { let config_home = get_home()?; let file = File::open(config_home.join("wallet_config.json"))?; @@ -26,12 +28,12 @@ pub fn fetch_config() -> Result { Ok(serde_json::from_reader(reader)?) } -//ToDo: Replace with structures conversion in future +// ToDo: Replace with structures conversion in future pub fn produce_account_addr_from_hex(hex_str: String) -> Result
{ Ok(hex_str.parse()?) } -///Fetch list of accounts stored at `NSSA_WALLET_HOME_DIR/curr_accounts.json` +/// Fetch list of accounts stored at `NSSA_WALLET_HOME_DIR/curr_accounts.json` /// /// If file not present, it is considered as empty list of persistent accounts pub fn fetch_persistent_accounts() -> Result> { @@ -52,7 +54,7 @@ pub fn fetch_persistent_accounts() -> Result> { } } -///Produces a list of accounts for storage +/// Produces a list of accounts for storage pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec { let mut vec_for_storage = vec![]; @@ -80,6 +82,28 @@ pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec for HumanReadableAccount { + fn from(account: Account) -> Self { + let program_owner_b64 = BASE64.encode(bytemuck::cast_slice(&account.program_owner)); + let data_b64 = BASE64.encode(account.data); + Self { + balance: account.balance, + program_owner_b64, + data_b64, + nonce: account.nonce, + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 14af09c..dc7559e 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -1,6 +1,6 @@ use std::{fs::File, io::Write, path::PathBuf, str::FromStr, sync::Arc}; -use base64::Engine; +use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; use common::{ sequencer_client::SequencerClient, transaction::{EncodedTransaction, NSSATransaction}, @@ -10,14 +10,14 @@ use anyhow::Result; use chain_storage::WalletChainStore; use config::WalletConfig; use log::info; -use nssa::Address; +use nssa::{Account, Address}; use clap::{Parser, Subcommand}; use crate::{ helperfunctions::{ - fetch_config, fetch_persistent_accounts, get_home, produce_account_addr_from_hex, - produce_data_for_storage, + HumanReadableAccount, fetch_config, fetch_persistent_accounts, get_home, + produce_account_addr_from_hex, produce_data_for_storage, }, poller::TxPoller, }; @@ -101,11 +101,16 @@ impl WalletCore { .nonces) } + ///Get account + pub async fn get_account(&self, addr: Address) -> Result { + let response = self.sequencer_client.get_account(addr.to_string()).await?; + Ok(response.account) + } + ///Poll transactions pub async fn poll_native_token_transfer(&self, hash: String) -> Result { let transaction_encoded = self.poller.poll_tx(hash).await?; - let tx_base64_decode = - base64::engine::general_purpose::STANDARD.decode(transaction_encoded)?; + let tx_base64_decode = BASE64.decode(transaction_encoded)?; let pub_tx = EncodedTransaction::from_bytes(tx_base64_decode); Ok(NSSATransaction::try_from(&pub_tx)?) @@ -163,6 +168,11 @@ pub enum Command { #[arg(short, long)] addr: String, }, + ///Get account at address `addr` + GetAccount { + #[arg(short, long)] + addr: String, + }, } ///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config @@ -187,11 +197,11 @@ pub async fn execute_subcommand(command: Command) -> Result<()> { .send_public_native_token_transfer(from, to, amount) .await?; - info!("Results of tx send is {res:#?}"); + println!("Results of tx send is {res:#?}"); let transfer_tx = wallet_core.poll_native_token_transfer(res.tx_hash).await?; - info!("Transaction data is {transfer_tx:?}"); + println!("Transaction data is {transfer_tx:?}"); } Command::SendNativeTokenTransferPrivate { from, to, amount } => { let from = produce_account_addr_from_hex(from)?; @@ -201,22 +211,16 @@ pub async fn execute_subcommand(command: Command) -> Result<()> { .send_private_native_token_transfer(from, to, amount) .await?; - info!("Results of tx send is {res:#?}"); + println!("Results of tx send is {res:#?}"); let transfer_tx = wallet_core.poll_native_token_transfer(res.tx_hash).await?; - info!("Transaction data is {transfer_tx:?}"); + println!("Transaction data is {transfer_tx:?}"); } Command::RegisterAccountPublic {} => { let addr = wallet_core.create_new_account_public(); - let key = wallet_core - .storage - .user_data - .get_pub_account_signing_key(&addr); - - info!("Generated new account with addr {addr:#?}"); - info!("With key {key:#?}"); + println!("Generated new account with addr {addr}"); } Command::RegisterAccountPrivate {} => { let addr = wallet_core.create_new_account_private(); @@ -227,9 +231,9 @@ pub async fn execute_subcommand(command: Command) -> Result<()> { .get_private_account(&addr) .unwrap(); - info!("Generated new account with addr {addr:#?}"); - info!("With key {key:#?}"); - info!("With account {account:#?}"); + println!("Generated new account with addr {addr:#?}"); + println!("With key {key:#?}"); + println!("With account {account:#?}"); } Command::FetchTx { tx_hash } => { let tx_obj = wallet_core @@ -237,23 +241,30 @@ pub async fn execute_subcommand(command: Command) -> Result<()> { .get_transaction_by_hash(tx_hash) .await?; - info!("Transaction object {tx_obj:#?}"); + println!("Transaction object {tx_obj:#?}"); } Command::GetAccountBalance { addr } => { let addr = Address::from_str(&addr)?; let balance = wallet_core.get_account_balance(addr).await?; - info!("Accounts {addr:#?} balance is {balance}"); + println!("Accounts {addr} balance is {balance}"); } Command::GetAccountNonce { addr } => { let addr = Address::from_str(&addr)?; let nonce = wallet_core.get_accounts_nonces(vec![addr]).await?[0]; - info!("Accounts {addr:#?} nonce is {nonce}"); + println!("Accounts {addr} nonce is {nonce}"); + } + Command::GetAccount { addr } => { + let addr: Address = addr.parse()?; + let account: HumanReadableAccount = wallet_core.get_account(addr).await?.into(); + println!("{}", serde_json::to_string(&account).unwrap()); } } - wallet_core.store_persistent_accounts()?; + let path = wallet_core.store_persistent_accounts()?; + + println!("Stored persistent accounts at {path:#?}"); Ok(()) }