mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-07 15:53:14 +00:00
Merge branch 'Pravdyvy/key-protocol-update-private' into Pravdyvy/wallet-privacy-preserving-transactions
This commit is contained in:
commit
9336a6c130
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -830,18 +830,18 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.23.1"
|
version = "1.23.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422"
|
checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck_derive",
|
"bytemuck_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck_derive"
|
name = "bytemuck_derive"
|
||||||
version = "1.8.1"
|
version = "1.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a"
|
checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -2200,6 +2200,7 @@ dependencies = [
|
|||||||
"env_logger",
|
"env_logger",
|
||||||
"hex",
|
"hex",
|
||||||
"log",
|
"log",
|
||||||
|
"nssa",
|
||||||
"sequencer_core",
|
"sequencer_core",
|
||||||
"sequencer_runner",
|
"sequencer_runner",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
@ -4680,6 +4681,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
|
"bytemuck",
|
||||||
"clap",
|
"clap",
|
||||||
"common",
|
"common",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
|||||||
@ -49,7 +49,7 @@ pub struct GetAccountsNoncesRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct GetAccountDataRequest {
|
pub struct GetAccountRequest {
|
||||||
pub address: String,
|
pub address: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,8 +68,8 @@ parse_request!(GetInitialTestnetAccountsRequest);
|
|||||||
parse_request!(GetAccountBalanceRequest);
|
parse_request!(GetAccountBalanceRequest);
|
||||||
parse_request!(GetTransactionByHashRequest);
|
parse_request!(GetTransactionByHashRequest);
|
||||||
parse_request!(GetAccountsNoncesRequest);
|
parse_request!(GetAccountsNoncesRequest);
|
||||||
parse_request!(GetAccountDataRequest);
|
|
||||||
parse_request!(GetProofByCommitmentRequest);
|
parse_request!(GetProofByCommitmentRequest);
|
||||||
|
parse_request!(GetAccountRequest);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct HelloResponse {
|
pub struct HelloResponse {
|
||||||
@ -118,11 +118,8 @@ pub struct GetTransactionByHashResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct GetAccountDataResponse {
|
pub struct GetAccountResponse {
|
||||||
pub balance: u128,
|
pub account: nssa::Account,
|
||||||
pub nonce: u128,
|
|
||||||
pub program_owner: [u32; 8],
|
|
||||||
pub data: Vec<u8>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
|||||||
@ -8,8 +8,9 @@ use reqwest::Client;
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::rpc_primitives::requests::{
|
use crate::rpc_primitives::requests::{
|
||||||
GetAccountsNoncesRequest, GetAccountsNoncesResponse, GetProofByCommitmentRequest,
|
GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse,
|
||||||
GetProofByCommitmentResponse, GetTransactionByHashRequest, GetTransactionByHashResponse,
|
GetProofByCommitmentRequest, GetProofByCommitmentResponse, GetTransactionByHashRequest,
|
||||||
|
GetTransactionByHashResponse,
|
||||||
};
|
};
|
||||||
use crate::sequencer_client::json::AccountInitialData;
|
use crate::sequencer_client::json::AccountInitialData;
|
||||||
use crate::transaction::{EncodedTransaction, NSSATransaction};
|
use crate::transaction::{EncodedTransaction, NSSATransaction};
|
||||||
@ -109,6 +110,21 @@ impl SequencerClient {
|
|||||||
Ok(resp_deser)
|
Ok(resp_deser)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_account(
|
||||||
|
&self,
|
||||||
|
address: String,
|
||||||
|
) -> Result<GetAccountResponse, SequencerClientError> {
|
||||||
|
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`.
|
///Get transaction details for `hash`.
|
||||||
pub async fn get_transaction_by_hash(
|
pub async fn get_transaction_by_hash(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@ -29,3 +29,6 @@ path = "../wallet"
|
|||||||
|
|
||||||
[dependencies.common]
|
[dependencies.common]
|
||||||
path = "../common"
|
path = "../common"
|
||||||
|
|
||||||
|
[dependencies.nssa]
|
||||||
|
path = "../nssa"
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use anyhow::Result;
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use common::sequencer_client::SequencerClient;
|
use common::sequencer_client::SequencerClient;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
use nssa::program::Program;
|
||||||
use sequencer_core::config::SequencerConfig;
|
use sequencer_core::config::SequencerConfig;
|
||||||
use sequencer_runner::startup_sequencer;
|
use sequencer_runner::startup_sequencer;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
@ -272,6 +273,36 @@ pub async fn test_success_two_transactions() {
|
|||||||
info!("Second TX Success!");
|
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 {
|
macro_rules! test_cleanup_wrap {
|
||||||
($home_dir:ident, $test_func:ident) => {{
|
($home_dir:ident, $test_func:ident) => {{
|
||||||
let res = pre_test($home_dir.clone()).await.unwrap();
|
let res = pre_test($home_dir.clone()).await.unwrap();
|
||||||
@ -304,6 +335,9 @@ pub async fn main_tests_runner() -> Result<()> {
|
|||||||
"test_failure" => {
|
"test_failure" => {
|
||||||
test_cleanup_wrap!(home_dir, 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_success_two_transactions" => {
|
||||||
test_cleanup_wrap!(home_dir, 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_success);
|
||||||
test_cleanup_wrap!(home_dir, test_failure);
|
test_cleanup_wrap!(home_dir, test_failure);
|
||||||
test_cleanup_wrap!(home_dir, test_success_two_transactions);
|
test_cleanup_wrap!(home_dir, test_success_two_transactions);
|
||||||
|
test_cleanup_wrap!(home_dir, test_get_account_wallet_command);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
anyhow::bail!("Unknown test name");
|
anyhow::bail!("Unknown test name");
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
use elliptic_curve::PrimeField;
|
|
||||||
use k256::Scalar;
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
NullifierPublicKey, SharedSecretKey,
|
NullifierPublicKey, SharedSecretKey,
|
||||||
@ -29,11 +27,11 @@ impl EphemeralKeyHolder {
|
|||||||
let hash_recepient = hasher.finalize();
|
let hash_recepient = hasher.finalize();
|
||||||
|
|
||||||
let mut hasher = sha2::Sha256::new();
|
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);
|
hasher.update(hash_recepient);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
ephemeral_secret_key: Scalar::from_repr(hasher.finalize()).unwrap(),
|
ephemeral_secret_key: hasher.finalize().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -98,8 +98,8 @@ impl KeyChain {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use aes_gcm::aead::OsRng;
|
use aes_gcm::aead::OsRng;
|
||||||
use elliptic_curve::ff::Field;
|
use k256::AffinePoint;
|
||||||
use k256::{AffinePoint, Scalar};
|
use rand::RngCore;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -117,7 +117,8 @@ mod tests {
|
|||||||
let address_key_holder = KeyChain::new_os_random();
|
let address_key_holder = KeyChain::new_os_random();
|
||||||
|
|
||||||
// Generate a random ephemeral public key sender
|
// 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);
|
let ephemeral_public_key_sender = EphemeralPublicKey::from_scalar(scalar);
|
||||||
|
|
||||||
// Calculate shared secret
|
// Calculate shared secret
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
use bip39::Mnemonic;
|
use bip39::Mnemonic;
|
||||||
use common::TreeHashType;
|
use common::TreeHashType;
|
||||||
use elliptic_curve::PrimeField;
|
use nssa_core::{
|
||||||
use k256::Scalar;
|
NullifierPublicKey, NullifierSecretKey,
|
||||||
use nssa_core::{NullifierPublicKey, NullifierSecretKey, encryption::IncomingViewingPublicKey};
|
encryption::{IncomingViewingPublicKey, Scalar},
|
||||||
|
};
|
||||||
use rand::{RngCore, rngs::OsRng};
|
use rand::{RngCore, rngs::OsRng};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sha2::{Digest, digest::FixedOutput};
|
use sha2::{Digest, digest::FixedOutput};
|
||||||
@ -79,9 +80,7 @@ impl SecretSpendingKey {
|
|||||||
hasher.update([2u8]);
|
hasher.update([2u8]);
|
||||||
hasher.update([0u8; 22]);
|
hasher.update([0u8; 22]);
|
||||||
|
|
||||||
let hash = <TreeHashType>::from(hasher.finalize_fixed());
|
<TreeHashType>::from(hasher.finalize_fixed())
|
||||||
|
|
||||||
IncomingViewingSecretKey::from_repr(hash.into()).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_outgoing_viewing_secret_key(&self) -> OutgoingViewingSecretKey {
|
pub fn generate_outgoing_viewing_secret_key(&self) -> OutgoingViewingSecretKey {
|
||||||
@ -92,9 +91,7 @@ impl SecretSpendingKey {
|
|||||||
hasher.update([3u8]);
|
hasher.update([3u8]);
|
||||||
hasher.update([0u8; 22]);
|
hasher.update([0u8; 22]);
|
||||||
|
|
||||||
let hash = <TreeHashType>::from(hasher.finalize_fixed());
|
<TreeHashType>::from(hasher.finalize_fixed())
|
||||||
|
|
||||||
OutgoingViewingSecretKey::from_repr(hash.into()).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn produce_private_key_holder(&self) -> PrivateKeyHolder {
|
pub fn produce_private_key_holder(&self) -> PrivateKeyHolder {
|
||||||
|
|||||||
@ -13,6 +13,8 @@ pub use shared_key_derivation::{EphemeralPublicKey, EphemeralSecretKey, Incoming
|
|||||||
|
|
||||||
use crate::{Commitment, account::Account};
|
use crate::{Commitment, account::Account};
|
||||||
|
|
||||||
|
pub type Scalar = [u8; 32];
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct SharedSecretKey(pub [u8; 32]);
|
pub struct SharedSecretKey(pub [u8; 32]);
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use k256::{
|
use k256::{
|
||||||
AffinePoint, EncodedPoint, FieldBytes, ProjectivePoint, Scalar,
|
AffinePoint, EncodedPoint, FieldBytes, ProjectivePoint,
|
||||||
elliptic_curve::{
|
elliptic_curve::{
|
||||||
PrimeField,
|
PrimeField,
|
||||||
sec1::{FromEncodedPoint, ToEncodedPoint},
|
sec1::{FromEncodedPoint, ToEncodedPoint},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::SharedSecretKey;
|
use crate::{SharedSecretKey, encryption::Scalar};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
pub struct Secp256k1Point(pub Vec<u8>);
|
pub struct Secp256k1Point(pub Vec<u8>);
|
||||||
@ -16,7 +16,7 @@ pub struct Secp256k1Point(pub Vec<u8>);
|
|||||||
impl Secp256k1Point {
|
impl Secp256k1Point {
|
||||||
pub fn from_scalar(value: Scalar) -> Secp256k1Point {
|
pub fn from_scalar(value: Scalar) -> Secp256k1Point {
|
||||||
let x_bytes: FieldBytes = value.into();
|
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 p = ProjectivePoint::GENERATOR * x;
|
||||||
let q = AffinePoint::from(p);
|
let q = AffinePoint::from(p);
|
||||||
@ -37,6 +37,7 @@ impl From<&EphemeralSecretKey> for EphemeralPublicKey {
|
|||||||
|
|
||||||
impl SharedSecretKey {
|
impl SharedSecretKey {
|
||||||
pub fn new(scalar: &Scalar, point: &Secp256k1Point) -> Self {
|
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 point: [u8; 33] = point.0.clone().try_into().unwrap();
|
||||||
|
|
||||||
let encoded = EncodedPoint::from_bytes(point).unwrap();
|
let encoded = EncodedPoint::from_bytes(point).unwrap();
|
||||||
|
|||||||
@ -9,6 +9,7 @@ mod signature;
|
|||||||
mod state;
|
mod state;
|
||||||
|
|
||||||
pub use address::Address;
|
pub use address::Address;
|
||||||
|
pub use nssa_core::account::Account;
|
||||||
pub use privacy_preserving_transaction::{
|
pub use privacy_preserving_transaction::{
|
||||||
PrivacyPreservingTransaction, circuit::execute_and_prove,
|
PrivacyPreservingTransaction, circuit::execute_and_prove,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -88,7 +88,6 @@ impl Proof {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use k256::{Scalar, elliptic_curve::PrimeField};
|
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
Commitment, EncryptionScheme, Nullifier,
|
Commitment, EncryptionScheme, Nullifier,
|
||||||
account::{Account, AccountWithMetadata},
|
account::{Account, AccountWithMetadata},
|
||||||
@ -140,7 +139,7 @@ mod tests {
|
|||||||
let expected_sender_pre = sender.clone();
|
let expected_sender_pre = sender.clone();
|
||||||
let recipient_keys = test_private_account_keys_1();
|
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 shared_secret = SharedSecretKey::new(&esk, &recipient_keys.ivk());
|
||||||
|
|
||||||
let (output, proof) = execute_and_prove(
|
let (output, proof) = execute_and_prove(
|
||||||
@ -221,10 +220,10 @@ mod tests {
|
|||||||
Commitment::new(&recipient_keys.npk(), &expected_private_account_2),
|
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 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 shared_secret_2 = SharedSecretKey::new(&esk_2, &recipient_keys.ivk());
|
||||||
|
|
||||||
let (output, proof) = execute_and_prove(
|
let (output, proof) = execute_and_prove(
|
||||||
|
|||||||
@ -90,7 +90,6 @@ impl Message {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use k256::{Scalar, elliptic_curve::PrimeField};
|
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
@ -152,10 +151,10 @@ pub mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_encrypted_account_data_constructor() {
|
fn test_encrypted_account_data_constructor() {
|
||||||
let npk = NullifierPublicKey::from(&[1; 32]);
|
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 account = Account::default();
|
||||||
let commitment = Commitment::new(&npk, &account);
|
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 shared_secret = SharedSecretKey::new(&esk, &ivk);
|
||||||
let epk = EphemeralPublicKey::from_scalar(esk);
|
let epk = EphemeralPublicKey::from_scalar(esk);
|
||||||
let ciphertext = EncryptionScheme::encrypt(&account, &shared_secret, &commitment, 2);
|
let ciphertext = EncryptionScheme::encrypt(&account, &shared_secret, &commitment, 2);
|
||||||
|
|||||||
@ -227,11 +227,10 @@ pub mod tests {
|
|||||||
signature::PrivateKey,
|
signature::PrivateKey,
|
||||||
};
|
};
|
||||||
|
|
||||||
use k256::{Scalar, elliptic_curve::PrimeField};
|
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
Commitment, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey,
|
Commitment, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey,
|
||||||
account::{Account, AccountWithMetadata, Nonce},
|
account::{Account, AccountWithMetadata, Nonce},
|
||||||
encryption::{EphemeralPublicKey, IncomingViewingPublicKey},
|
encryption::{EphemeralPublicKey, IncomingViewingPublicKey, Scalar},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn transfer_transaction(
|
fn transfer_transaction(
|
||||||
@ -760,14 +759,14 @@ pub mod tests {
|
|||||||
pub fn test_private_account_keys_1() -> TestPrivateKeys {
|
pub fn test_private_account_keys_1() -> TestPrivateKeys {
|
||||||
TestPrivateKeys {
|
TestPrivateKeys {
|
||||||
nsk: [13; 32],
|
nsk: [13; 32],
|
||||||
isk: Scalar::from_repr([31; 32].into()).unwrap(),
|
isk: [31; 32],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_private_account_keys_2() -> TestPrivateKeys {
|
pub fn test_private_account_keys_2() -> TestPrivateKeys {
|
||||||
TestPrivateKeys {
|
TestPrivateKeys {
|
||||||
nsk: [38; 32],
|
nsk: [38; 32],
|
||||||
isk: Scalar::from_repr([83; 32].into()).unwrap(),
|
isk: [83; 32],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -789,7 +788,7 @@ pub mod tests {
|
|||||||
is_authorized: false,
|
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 shared_secret = SharedSecretKey::new(&esk, &recipient_keys.ivk());
|
||||||
let epk = EphemeralPublicKey::from_scalar(esk);
|
let epk = EphemeralPublicKey::from_scalar(esk);
|
||||||
|
|
||||||
@ -835,11 +834,11 @@ pub mod tests {
|
|||||||
is_authorized: false,
|
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 shared_secret_1 = SharedSecretKey::new(&esk_1, &sender_keys.ivk());
|
||||||
let epk_1 = EphemeralPublicKey::from_scalar(esk_1);
|
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 shared_secret_2 = SharedSecretKey::new(&esk_2, &recipient_keys.ivk());
|
||||||
let epk_2 = EphemeralPublicKey::from_scalar(esk_2);
|
let epk_2 = EphemeralPublicKey::from_scalar(esk_2);
|
||||||
|
|
||||||
@ -895,7 +894,7 @@ pub mod tests {
|
|||||||
is_authorized: false,
|
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 shared_secret = SharedSecretKey::new(&esk, &sender_keys.ivk());
|
||||||
let epk = EphemeralPublicKey::from_scalar(esk);
|
let epk = EphemeralPublicKey::from_scalar(esk);
|
||||||
|
|
||||||
|
|||||||
@ -12,8 +12,8 @@ use common::{
|
|||||||
message::{Message, Request},
|
message::{Message, Request},
|
||||||
parser::RpcRequest,
|
parser::RpcRequest,
|
||||||
requests::{
|
requests::{
|
||||||
GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountDataRequest,
|
GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountRequest,
|
||||||
GetAccountDataResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse,
|
GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse,
|
||||||
GetInitialTestnetAccountsRequest, GetProofByCommitmentRequest,
|
GetInitialTestnetAccountsRequest, GetProofByCommitmentRequest,
|
||||||
GetProofByCommitmentResponse, GetTransactionByHashRequest,
|
GetProofByCommitmentResponse, GetTransactionByHashRequest,
|
||||||
GetTransactionByHashResponse,
|
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_ACCOUNT_BALANCE: &str = "get_account_balance";
|
||||||
pub const GET_TRANSACTION_BY_HASH: &str = "get_transaction_by_hash";
|
pub const GET_TRANSACTION_BY_HASH: &str = "get_transaction_by_hash";
|
||||||
pub const GET_ACCOUNTS_NONCES: &str = "get_accounts_nonces";
|
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 GET_PROOF_FOR_COMMITMENT: &str = "get_proof_for_commitment";
|
||||||
|
|
||||||
pub const HELLO_FROM_SEQUENCER: &str = "HELLO_FROM_SEQUENCER";
|
pub const HELLO_FROM_SEQUENCER: &str = "HELLO_FROM_SEQUENCER";
|
||||||
@ -206,10 +206,10 @@ impl JsonHandler {
|
|||||||
respond(helperstruct)
|
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.
|
/// Address must be a valid hex string of the correct length.
|
||||||
async fn process_get_account_data(&self, request: Request) -> Result<Value, RpcErr> {
|
async fn process_get_account(&self, request: Request) -> Result<Value, RpcErr> {
|
||||||
let get_account_nonces_req = GetAccountDataRequest::parse(Some(request.params))?;
|
let get_account_nonces_req = GetAccountRequest::parse(Some(request.params))?;
|
||||||
|
|
||||||
let address = get_account_nonces_req
|
let address = get_account_nonces_req
|
||||||
.address
|
.address
|
||||||
@ -222,12 +222,7 @@ impl JsonHandler {
|
|||||||
state.store.state.get_account_by_address(&address)
|
state.store.state.get_account_by_address(&address)
|
||||||
};
|
};
|
||||||
|
|
||||||
let helperstruct = GetAccountDataResponse {
|
let helperstruct = GetAccountResponse { account };
|
||||||
balance: account.balance,
|
|
||||||
nonce: account.nonce,
|
|
||||||
program_owner: account.program_owner,
|
|
||||||
data: account.data,
|
|
||||||
};
|
|
||||||
|
|
||||||
respond(helperstruct)
|
respond(helperstruct)
|
||||||
}
|
}
|
||||||
@ -282,7 +277,7 @@ impl JsonHandler {
|
|||||||
GET_INITIAL_TESTNET_ACCOUNTS => self.get_initial_testnet_accounts(request).await,
|
GET_INITIAL_TESTNET_ACCOUNTS => self.get_initial_testnet_accounts(request).await,
|
||||||
GET_ACCOUNT_BALANCE => self.process_get_account_balance(request).await,
|
GET_ACCOUNT_BALANCE => self.process_get_account_balance(request).await,
|
||||||
GET_ACCOUNTS_NONCES => self.process_get_accounts_nonces(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_TRANSACTION_BY_HASH => self.process_get_transaction_by_hash(request).await,
|
||||||
GET_PROOF_FOR_COMMITMENT => self.process_get_proof_by_commitment(request).await,
|
GET_PROOF_FOR_COMMITMENT => self.process_get_proof_by_commitment(request).await,
|
||||||
_ => Err(RpcErr(RpcError::method_not_found(request.method))),
|
_ => Err(RpcErr(RpcError::method_not_found(request.method))),
|
||||||
@ -552,7 +547,7 @@ mod tests {
|
|||||||
let (json_handler, _, _) = components_for_tests();
|
let (json_handler, _, _) = components_for_tests();
|
||||||
let request = serde_json::json!({
|
let request = serde_json::json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "get_account_data",
|
"method": "get_account",
|
||||||
"params": { "address": "efac".repeat(16) },
|
"params": { "address": "efac".repeat(16) },
|
||||||
"id": 1
|
"id": 1
|
||||||
});
|
});
|
||||||
@ -560,10 +555,12 @@ mod tests {
|
|||||||
"id": 1,
|
"id": 1,
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"result": {
|
"result": {
|
||||||
"balance": 0,
|
"account": {
|
||||||
"nonce": 0,
|
"balance": 0,
|
||||||
"program_owner": [ 0, 0, 0, 0, 0, 0, 0, 0],
|
"nonce": 0,
|
||||||
"data": [],
|
"program_owner": [ 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"data": [],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ clap.workspace = true
|
|||||||
nssa-core = { path = "../nssa/core" }
|
nssa-core = { path = "../nssa/core" }
|
||||||
base64.workspace = true
|
base64.workspace = true
|
||||||
k256 = { version = "0.13.3" }
|
k256 = { version = "0.13.3" }
|
||||||
|
bytemuck = "1.23.2"
|
||||||
|
|
||||||
[dependencies.key_protocol]
|
[dependencies.key_protocol]
|
||||||
path = "../key_protocol"
|
path = "../key_protocol"
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
|
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
||||||
use std::{fs::File, io::BufReader, path::PathBuf, str::FromStr};
|
use std::{fs::File, io::BufReader, path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use key_protocol::key_protocol_core::NSSAUserData;
|
use key_protocol::key_protocol_core::NSSAUserData;
|
||||||
use nssa::Address;
|
use nssa::{Account, Address};
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
HOME_DIR_ENV_VAR,
|
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<PathBuf> {
|
pub fn get_home() -> Result<PathBuf> {
|
||||||
Ok(PathBuf::from_str(&std::env::var(HOME_DIR_ENV_VAR)?)?)
|
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<WalletConfig> {
|
pub fn fetch_config() -> Result<WalletConfig> {
|
||||||
let config_home = get_home()?;
|
let config_home = get_home()?;
|
||||||
let file = File::open(config_home.join("wallet_config.json"))?;
|
let file = File::open(config_home.join("wallet_config.json"))?;
|
||||||
@ -26,12 +28,12 @@ pub fn fetch_config() -> Result<WalletConfig> {
|
|||||||
Ok(serde_json::from_reader(reader)?)
|
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<Address> {
|
pub fn produce_account_addr_from_hex(hex_str: String) -> Result<Address> {
|
||||||
Ok(hex_str.parse()?)
|
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
|
/// If file not present, it is considered as empty list of persistent accounts
|
||||||
pub fn fetch_persistent_accounts() -> Result<Vec<PersistentAccountData>> {
|
pub fn fetch_persistent_accounts() -> Result<Vec<PersistentAccountData>> {
|
||||||
@ -52,7 +54,7 @@ pub fn fetch_persistent_accounts() -> Result<Vec<PersistentAccountData>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///Produces a list of accounts for storage
|
/// Produces a list of accounts for storage
|
||||||
pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec<PersistentAccountData> {
|
pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec<PersistentAccountData> {
|
||||||
let mut vec_for_storage = vec![];
|
let mut vec_for_storage = vec![];
|
||||||
|
|
||||||
@ -80,6 +82,28 @@ pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec<PersistentAccou
|
|||||||
vec_for_storage
|
vec_for_storage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Human-readable representation of an account.
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub(crate) struct HumanReadableAccount {
|
||||||
|
balance: u128,
|
||||||
|
program_owner_b64: String,
|
||||||
|
data_b64: String,
|
||||||
|
nonce: u128,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Account> 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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use std::{fs::File, io::Write, path::PathBuf, str::FromStr, sync::Arc};
|
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::{
|
use common::{
|
||||||
sequencer_client::SequencerClient,
|
sequencer_client::SequencerClient,
|
||||||
transaction::{EncodedTransaction, NSSATransaction},
|
transaction::{EncodedTransaction, NSSATransaction},
|
||||||
@ -10,14 +10,14 @@ use anyhow::Result;
|
|||||||
use chain_storage::WalletChainStore;
|
use chain_storage::WalletChainStore;
|
||||||
use config::WalletConfig;
|
use config::WalletConfig;
|
||||||
use log::info;
|
use log::info;
|
||||||
use nssa::Address;
|
use nssa::{Account, Address};
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
helperfunctions::{
|
helperfunctions::{
|
||||||
fetch_config, fetch_persistent_accounts, get_home, produce_account_addr_from_hex,
|
HumanReadableAccount, fetch_config, fetch_persistent_accounts, get_home,
|
||||||
produce_data_for_storage,
|
produce_account_addr_from_hex, produce_data_for_storage,
|
||||||
},
|
},
|
||||||
poller::TxPoller,
|
poller::TxPoller,
|
||||||
};
|
};
|
||||||
@ -101,11 +101,16 @@ impl WalletCore {
|
|||||||
.nonces)
|
.nonces)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///Get account
|
||||||
|
pub async fn get_account(&self, addr: Address) -> Result<Account> {
|
||||||
|
let response = self.sequencer_client.get_account(addr.to_string()).await?;
|
||||||
|
Ok(response.account)
|
||||||
|
}
|
||||||
|
|
||||||
///Poll transactions
|
///Poll transactions
|
||||||
pub async fn poll_native_token_transfer(&self, hash: String) -> Result<NSSATransaction> {
|
pub async fn poll_native_token_transfer(&self, hash: String) -> Result<NSSATransaction> {
|
||||||
let transaction_encoded = self.poller.poll_tx(hash).await?;
|
let transaction_encoded = self.poller.poll_tx(hash).await?;
|
||||||
let tx_base64_decode =
|
let tx_base64_decode = BASE64.decode(transaction_encoded)?;
|
||||||
base64::engine::general_purpose::STANDARD.decode(transaction_encoded)?;
|
|
||||||
let pub_tx = EncodedTransaction::from_bytes(tx_base64_decode);
|
let pub_tx = EncodedTransaction::from_bytes(tx_base64_decode);
|
||||||
|
|
||||||
Ok(NSSATransaction::try_from(&pub_tx)?)
|
Ok(NSSATransaction::try_from(&pub_tx)?)
|
||||||
@ -163,6 +168,11 @@ pub enum Command {
|
|||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
addr: String,
|
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
|
///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)
|
.send_public_native_token_transfer(from, to, amount)
|
||||||
.await?;
|
.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?;
|
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 } => {
|
Command::SendNativeTokenTransferPrivate { from, to, amount } => {
|
||||||
let from = produce_account_addr_from_hex(from)?;
|
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)
|
.send_private_native_token_transfer(from, to, amount)
|
||||||
.await?;
|
.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?;
|
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 {} => {
|
Command::RegisterAccountPublic {} => {
|
||||||
let addr = wallet_core.create_new_account_public();
|
let addr = wallet_core.create_new_account_public();
|
||||||
|
|
||||||
let key = wallet_core
|
println!("Generated new account with addr {addr}");
|
||||||
.storage
|
|
||||||
.user_data
|
|
||||||
.get_pub_account_signing_key(&addr);
|
|
||||||
|
|
||||||
info!("Generated new account with addr {addr:#?}");
|
|
||||||
info!("With key {key:#?}");
|
|
||||||
}
|
}
|
||||||
Command::RegisterAccountPrivate {} => {
|
Command::RegisterAccountPrivate {} => {
|
||||||
let addr = wallet_core.create_new_account_private();
|
let addr = wallet_core.create_new_account_private();
|
||||||
@ -227,9 +231,9 @@ pub async fn execute_subcommand(command: Command) -> Result<()> {
|
|||||||
.get_private_account(&addr)
|
.get_private_account(&addr)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
info!("Generated new account with addr {addr:#?}");
|
println!("Generated new account with addr {addr:#?}");
|
||||||
info!("With key {key:#?}");
|
println!("With key {key:#?}");
|
||||||
info!("With account {account:#?}");
|
println!("With account {account:#?}");
|
||||||
}
|
}
|
||||||
Command::FetchTx { tx_hash } => {
|
Command::FetchTx { tx_hash } => {
|
||||||
let tx_obj = wallet_core
|
let tx_obj = wallet_core
|
||||||
@ -237,23 +241,30 @@ pub async fn execute_subcommand(command: Command) -> Result<()> {
|
|||||||
.get_transaction_by_hash(tx_hash)
|
.get_transaction_by_hash(tx_hash)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
info!("Transaction object {tx_obj:#?}");
|
println!("Transaction object {tx_obj:#?}");
|
||||||
}
|
}
|
||||||
Command::GetAccountBalance { addr } => {
|
Command::GetAccountBalance { addr } => {
|
||||||
let addr = Address::from_str(&addr)?;
|
let addr = Address::from_str(&addr)?;
|
||||||
|
|
||||||
let balance = wallet_core.get_account_balance(addr).await?;
|
let balance = wallet_core.get_account_balance(addr).await?;
|
||||||
info!("Accounts {addr:#?} balance is {balance}");
|
println!("Accounts {addr} balance is {balance}");
|
||||||
}
|
}
|
||||||
Command::GetAccountNonce { addr } => {
|
Command::GetAccountNonce { addr } => {
|
||||||
let addr = Address::from_str(&addr)?;
|
let addr = Address::from_str(&addr)?;
|
||||||
|
|
||||||
let nonce = wallet_core.get_accounts_nonces(vec![addr]).await?[0];
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user