feat: cli refactor

This commit is contained in:
Oleksandr Pravdyvyi 2025-10-14 15:29:18 +03:00
parent 4b7319afe9
commit c39c9ad4ca
No known key found for this signature in database
GPG Key ID: 9F8955C63C443871
6 changed files with 966 additions and 644 deletions

View File

@ -19,8 +19,18 @@ use tempfile::TempDir;
use tokio::task::JoinHandle;
use wallet::{
Command, SubcommandReturnValue, WalletCore,
cli::token_program::{
TokenProgramSubcommand, TokenProgramSubcommandPrivate, TokenProgramSubcommandPublic,
cli::{
chain::{ChainSubcommand, FetchSubcommand, RegisterSubcommand},
native_token_transfer_program::{
NativeTokenTransferProgramSubcommand, NativeTokenTransferProgramSubcommandPrivate,
NativeTokenTransferProgramSubcommandShielded,
},
pinata_program::{
PinataProgramSubcommand, PinataProgramSubcommandPrivate, PinataProgramSubcommandPublic,
},
token_program::{
TokenProgramSubcommand, TokenProgramSubcommandPrivate, TokenProgramSubcommandPublic,
},
},
config::PersistentAccountData,
helperfunctions::{fetch_config, fetch_persistent_accounts},
@ -100,11 +110,13 @@ pub async fn post_test(residual: (ServerHandle, JoinHandle<Result<()>>, TempDir)
pub async fn test_success() {
info!("test_success");
let command = Command::SendNativeTokenTransferPublic {
from: ACC_SENDER.to_string(),
to: ACC_RECEIVER.to_string(),
amount: 100,
};
let command = Command::Transfer(
NativeTokenTransferProgramSubcommand::SendNativeTokenTransferPublic {
from: ACC_SENDER.to_string(),
to: ACC_RECEIVER.to_string(),
amount: 100,
},
);
let wallet_config = fetch_config().unwrap();
@ -136,7 +148,9 @@ pub async fn test_success() {
pub async fn test_success_move_to_another_account() {
info!("test_success_move_to_another_account");
let command = Command::RegisterAccountPublic {};
let command = Command::Chain(ChainSubcommand::Register(
RegisterSubcommand::RegisterAccountPublic {},
));
let wallet_config = fetch_config().unwrap();
@ -160,11 +174,13 @@ pub async fn test_success_move_to_another_account() {
panic!("Failed to produce new account, not present in persistent accounts");
}
let command = Command::SendNativeTokenTransferPublic {
from: ACC_SENDER.to_string(),
to: new_persistent_account_addr.clone(),
amount: 100,
};
let command = Command::Transfer(
NativeTokenTransferProgramSubcommand::SendNativeTokenTransferPublic {
from: ACC_SENDER.to_string(),
to: new_persistent_account_addr.clone(),
amount: 100,
},
);
wallet::execute_subcommand(command).await.unwrap();
@ -192,11 +208,13 @@ pub async fn test_success_move_to_another_account() {
pub async fn test_failure() {
info!("test_failure");
let command = Command::SendNativeTokenTransferPublic {
from: ACC_SENDER.to_string(),
to: ACC_RECEIVER.to_string(),
amount: 1000000,
};
let command = Command::Transfer(
NativeTokenTransferProgramSubcommand::SendNativeTokenTransferPublic {
from: ACC_SENDER.to_string(),
to: ACC_RECEIVER.to_string(),
amount: 1000000,
},
);
let wallet_config = fetch_config().unwrap();
@ -230,11 +248,13 @@ pub async fn test_failure() {
pub async fn test_success_two_transactions() {
info!("test_success_two_transactions");
let command = Command::SendNativeTokenTransferPublic {
from: ACC_SENDER.to_string(),
to: ACC_RECEIVER.to_string(),
amount: 100,
};
let command = Command::Transfer(
NativeTokenTransferProgramSubcommand::SendNativeTokenTransferPublic {
from: ACC_SENDER.to_string(),
to: ACC_RECEIVER.to_string(),
amount: 100,
},
);
let wallet_config = fetch_config().unwrap();
@ -263,11 +283,13 @@ pub async fn test_success_two_transactions() {
info!("First TX Success!");
let command = Command::SendNativeTokenTransferPublic {
from: ACC_SENDER.to_string(),
to: ACC_RECEIVER.to_string(),
amount: 100,
};
let command = Command::Transfer(
NativeTokenTransferProgramSubcommand::SendNativeTokenTransferPublic {
from: ACC_SENDER.to_string(),
to: ACC_RECEIVER.to_string(),
amount: 100,
},
);
wallet::execute_subcommand(command).await.unwrap();
@ -319,17 +341,23 @@ pub async fn test_success_token_program() {
let wallet_config = fetch_config().unwrap();
// Create new account for the token definition
wallet::execute_subcommand(Command::RegisterAccountPublic {})
.await
.unwrap();
wallet::execute_subcommand(Command::Chain(ChainSubcommand::Register(
RegisterSubcommand::RegisterAccountPublic {},
)))
.await
.unwrap();
// Create new account for the token supply holder
wallet::execute_subcommand(Command::RegisterAccountPublic {})
.await
.unwrap();
wallet::execute_subcommand(Command::Chain(ChainSubcommand::Register(
RegisterSubcommand::RegisterAccountPublic {},
)))
.await
.unwrap();
// Create new account for receiving a token transaction
wallet::execute_subcommand(Command::RegisterAccountPublic {})
.await
.unwrap();
wallet::execute_subcommand(Command::Chain(ChainSubcommand::Register(
RegisterSubcommand::RegisterAccountPublic {},
)))
.await
.unwrap();
let persistent_accounts = fetch_persistent_accounts().unwrap();
@ -462,26 +490,32 @@ pub async fn test_success_token_program_private_owned() {
// Create new account for the token definition (public)
let SubcommandReturnValue::RegisterAccount {
addr: definition_addr,
} = wallet::execute_subcommand(Command::RegisterAccountPublic {})
.await
.unwrap()
} = wallet::execute_subcommand(Command::Chain(ChainSubcommand::Register(
RegisterSubcommand::RegisterAccountPublic {},
)))
.await
.unwrap()
else {
panic!("invalid subcommand return value");
};
// Create new account for the token supply holder (private)
let SubcommandReturnValue::RegisterAccount { addr: supply_addr } =
wallet::execute_subcommand(Command::RegisterAccountPrivate {})
.await
.unwrap()
wallet::execute_subcommand(Command::Chain(ChainSubcommand::Register(
RegisterSubcommand::RegisterAccountPrivate {},
)))
.await
.unwrap()
else {
panic!("invalid subcommand return value");
};
// Create new account for receiving a token transaction
let SubcommandReturnValue::RegisterAccount {
addr: recipient_addr,
} = wallet::execute_subcommand(Command::RegisterAccountPrivate {})
.await
.unwrap()
} = wallet::execute_subcommand(Command::Chain(ChainSubcommand::Register(
RegisterSubcommand::RegisterAccountPrivate {},
)))
.await
.unwrap()
else {
panic!("invalid subcommand return value");
};
@ -595,26 +629,32 @@ pub async fn test_success_token_program_private_claiming_path() {
// Create new account for the token definition (public)
let SubcommandReturnValue::RegisterAccount {
addr: definition_addr,
} = wallet::execute_subcommand(Command::RegisterAccountPublic {})
.await
.unwrap()
} = wallet::execute_subcommand(Command::Chain(ChainSubcommand::Register(
RegisterSubcommand::RegisterAccountPublic {},
)))
.await
.unwrap()
else {
panic!("invalid subcommand return value");
};
// Create new account for the token supply holder (private)
let SubcommandReturnValue::RegisterAccount { addr: supply_addr } =
wallet::execute_subcommand(Command::RegisterAccountPrivate {})
.await
.unwrap()
wallet::execute_subcommand(Command::Chain(ChainSubcommand::Register(
RegisterSubcommand::RegisterAccountPrivate {},
)))
.await
.unwrap()
else {
panic!("invalid subcommand return value");
};
// Create new account for receiving a token transaction
let SubcommandReturnValue::RegisterAccount {
addr: recipient_addr,
} = wallet::execute_subcommand(Command::RegisterAccountPrivate {})
.await
.unwrap()
} = wallet::execute_subcommand(Command::Chain(ChainSubcommand::Register(
RegisterSubcommand::RegisterAccountPrivate {},
)))
.await
.unwrap()
else {
panic!("invalid subcommand return value");
};
@ -690,11 +730,13 @@ pub async fn test_success_token_program_private_claiming_path() {
info!("Waiting for next block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
let command = Command::FetchPrivateAccount {
tx_hash,
acc_addr: recipient_addr.to_string(),
output_id: 1,
};
let command = Command::Chain(ChainSubcommand::Fetch(
FetchSubcommand::FetchPrivateAccount {
tx_hash,
acc_addr: recipient_addr.to_string(),
output_id: 1,
},
));
wallet::execute_subcommand(command).await.unwrap();
@ -717,11 +759,13 @@ pub async fn test_success_private_transfer_to_another_owned_account() {
let from: Address = ACC_SENDER_PRIVATE.parse().unwrap();
let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap();
let command = Command::SendNativeTokenTransferPrivateOwnedAccount {
from: from.to_string(),
to: to.to_string(),
amount: 100,
};
let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Private(
NativeTokenTransferProgramSubcommandPrivate::SendNativeTokenTransferPrivateOwnedAccount {
from: from.to_string(),
to: to.to_string(),
amount: 100,
},
));
wallet::execute_subcommand(command).await.unwrap();
@ -750,12 +794,14 @@ pub async fn test_success_private_transfer_to_another_foreign_account() {
let to_npk_string = hex::encode(to_npk.0);
let to_ipk = Secp256k1Point::from_scalar(to_npk.0);
let command = Command::SendNativeTokenTransferPrivateForeignAccount {
from: from.to_string(),
to_npk: to_npk_string,
to_ipk: hex::encode(to_ipk.0),
amount: 100,
};
let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Private(
NativeTokenTransferProgramSubcommandPrivate::SendNativeTokenTransferPrivateForeignAccount {
from: from.to_string(),
to_npk: to_npk_string,
to_ipk: hex::encode(to_ipk.0),
amount: 100,
},
));
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } =
wallet::execute_subcommand(command).await.unwrap()
@ -789,7 +835,9 @@ pub async fn test_success_private_transfer_to_another_owned_account_claiming_pat
info!("test_success_private_transfer_to_another_owned_account_claiming_path");
let from: Address = ACC_SENDER_PRIVATE.parse().unwrap();
let command = Command::RegisterAccountPrivate {};
let command = Command::Chain(ChainSubcommand::Register(
RegisterSubcommand::RegisterAccountPrivate {},
));
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
let SubcommandReturnValue::RegisterAccount { addr: to_addr } = sub_ret else {
@ -808,12 +856,14 @@ pub async fn test_success_private_transfer_to_another_owned_account_claiming_pat
.cloned()
.unwrap();
let command = Command::SendNativeTokenTransferPrivateForeignAccount {
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::Transfer(NativeTokenTransferProgramSubcommand::Private(
NativeTokenTransferProgramSubcommandPrivate::SendNativeTokenTransferPrivateForeignAccount {
from: from.to_string(),
to_npk: hex::encode(to_keys.nullifer_public_key.0),
to_ipk: hex::encode(to_keys.incoming_viewing_public_key.0),
amount: 100,
},
));
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else {
@ -822,11 +872,13 @@ pub async fn test_success_private_transfer_to_another_owned_account_claiming_pat
let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await;
let command = Command::FetchPrivateAccount {
tx_hash,
acc_addr: to_addr.to_string(),
output_id: 1,
};
let command = Command::Chain(ChainSubcommand::Fetch(
FetchSubcommand::FetchPrivateAccount {
tx_hash,
acc_addr: to_addr.to_string(),
output_id: 1,
},
));
wallet::execute_subcommand(command).await.unwrap();
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
@ -851,11 +903,13 @@ pub async fn test_success_deshielded_transfer_to_another_account() {
info!("test_success_deshielded_transfer_to_another_account");
let from: Address = ACC_SENDER_PRIVATE.parse().unwrap();
let to: Address = ACC_RECEIVER.parse().unwrap();
let command = Command::SendNativeTokenTransferDeshielded {
from: from.to_string(),
to: to.to_string(),
amount: 100,
};
let command = Command::Transfer(
NativeTokenTransferProgramSubcommand::SendNativeTokenTransferDeshielded {
from: from.to_string(),
to: to.to_string(),
amount: 100,
},
);
let wallet_config = fetch_config().unwrap();
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
@ -892,11 +946,13 @@ pub async fn test_success_shielded_transfer_to_another_owned_account() {
info!("test_success_shielded_transfer_to_another_owned_account");
let from: Address = ACC_SENDER.parse().unwrap();
let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap();
let command = Command::SendNativeTokenTransferShielded {
from: from.to_string(),
to: to.to_string(),
amount: 100,
};
let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Shielded(
NativeTokenTransferProgramSubcommandShielded::SendNativeTokenTransferShielded {
from: from.to_string(),
to: to.to_string(),
amount: 100,
},
));
let wallet_config = fetch_config().unwrap();
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
@ -931,12 +987,13 @@ pub async fn test_success_shielded_transfer_to_another_foreign_account() {
let to_ipk = Secp256k1Point::from_scalar(to_npk.0);
let from: Address = ACC_SENDER.parse().unwrap();
let command = Command::SendNativeTokenTransferShieldedForeignAccount {
let command = Command::Transfer(NativeTokenTransferProgramSubcommand::Shielded(
NativeTokenTransferProgramSubcommandShielded::SendNativeTokenTransferShieldedForeignAccount {
from: from.to_string(),
to_npk: to_npk_string,
to_ipk: hex::encode(to_ipk.0),
amount: 100,
};
}));
let wallet_config = fetch_config().unwrap();
@ -972,11 +1029,13 @@ pub async fn test_pinata() {
let pinata_addr = "cafe".repeat(16);
let pinata_prize = 150;
let solution = 989106;
let command = Command::ClaimPinata {
pinata_addr: pinata_addr.clone(),
winner_addr: ACC_SENDER.to_string(),
solution,
};
let command = Command::PinataProgram(PinataProgramSubcommand::Public(
PinataProgramSubcommandPublic::ClaimPinata {
pinata_addr: pinata_addr.clone(),
winner_addr: ACC_SENDER.to_string(),
solution,
},
));
let wallet_config = fetch_config().unwrap();
@ -1018,11 +1077,13 @@ pub async fn test_pinata_private_receiver() {
let pinata_prize = 150;
let solution = 989106;
let command = Command::ClaimPinataPrivateReceiverOwned {
pinata_addr: pinata_addr.clone(),
winner_addr: ACC_SENDER_PRIVATE.to_string(),
solution,
};
let command = Command::PinataProgram(PinataProgramSubcommand::Private(
PinataProgramSubcommandPrivate::ClaimPinataPrivateReceiverOwned {
pinata_addr: pinata_addr.clone(),
winner_addr: ACC_SENDER_PRIVATE.to_string(),
solution,
},
));
let wallet_config = fetch_config().unwrap();
@ -1050,11 +1111,13 @@ pub async fn test_pinata_private_receiver() {
.unwrap()
.balance;
let command = Command::FetchPrivateAccount {
tx_hash: tx_hash.clone(),
acc_addr: ACC_SENDER_PRIVATE.to_string(),
output_id: 0,
};
let command = Command::Chain(ChainSubcommand::Fetch(
FetchSubcommand::FetchPrivateAccount {
tx_hash: tx_hash.clone(),
acc_addr: ACC_SENDER_PRIVATE.to_string(),
output_id: 0,
},
));
wallet::execute_subcommand(command).await.unwrap();
let wallet_config = fetch_config().unwrap();
@ -1079,18 +1142,22 @@ pub async fn test_pinata_private_receiver_new_account() {
// Create new account for the token supply holder (private)
let SubcommandReturnValue::RegisterAccount { addr: winner_addr } =
wallet::execute_subcommand(Command::RegisterAccountPrivate {})
.await
.unwrap()
wallet::execute_subcommand(Command::Chain(ChainSubcommand::Register(
RegisterSubcommand::RegisterAccountPrivate {},
)))
.await
.unwrap()
else {
panic!("invalid subcommand return value");
};
let command = Command::ClaimPinataPrivateReceiverOwned {
pinata_addr: pinata_addr.clone(),
winner_addr: winner_addr.to_string(),
solution,
};
let command = Command::PinataProgram(PinataProgramSubcommand::Private(
PinataProgramSubcommandPrivate::ClaimPinataPrivateReceiverOwned {
pinata_addr: pinata_addr.clone(),
winner_addr: winner_addr.to_string(),
solution,
},
));
let wallet_config = fetch_config().unwrap();

253
wallet/src/cli/chain.rs Normal file
View File

@ -0,0 +1,253 @@
use std::str::FromStr;
use anyhow::Result;
use clap::Subcommand;
use common::transaction::NSSATransaction;
use nssa::Address;
use crate::{
SubcommandReturnValue, WalletCore, cli::WalletSubcommand, helperfunctions::HumanReadableAccount,
};
///Represents generic chain CLI subcommand
#[derive(Subcommand, Debug, Clone)]
pub enum ChainSubcommand {
///Get
#[command(subcommand)]
Get(GetSubcommand),
///Fetch
#[command(subcommand)]
Fetch(FetchSubcommand),
///Register
#[command(subcommand)]
Register(RegisterSubcommand),
}
///Represents generic getter CLI subcommand
#[derive(Subcommand, Debug, Clone)]
pub enum GetSubcommand {
///Get account `addr` balance
GetPublicAccountBalance {
#[arg(short, long)]
addr: String,
},
///Get account `addr` nonce
GetPublicAccountNonce {
#[arg(short, long)]
addr: String,
},
///Get account at address `addr`
GetPublicAccount {
#[arg(short, long)]
addr: String,
},
///Get private account with `addr` from storage
GetPrivateAccount {
#[arg(short, long)]
addr: String,
},
}
///Represents generic getter CLI subcommand
#[derive(Subcommand, Debug, Clone)]
pub enum FetchSubcommand {
///Fetch transaction by `hash`
FetchTx {
#[arg(short, long)]
tx_hash: String,
},
///Claim account `acc_addr` generated in transaction `tx_hash`, using secret `sh_secret` at ciphertext id `ciph_id`
FetchPrivateAccount {
///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 RegisterSubcommand {
///Register new public account
RegisterAccountPublic {},
///Register new private account
RegisterAccountPrivate {},
}
impl WalletSubcommand for GetSubcommand {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
GetSubcommand::GetPublicAccountBalance { 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::GetPublicAccountNonce { 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::GetPublicAccount { 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::GetPrivateAccount { 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,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
FetchSubcommand::FetchTx { 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::FetchPrivateAccount {
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()?;
println!("Stored persistent accounts at {path:#?}");
Ok(SubcommandReturnValue::Empty)
}
}
}
}
impl WalletSubcommand for RegisterSubcommand {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
RegisterSubcommand::RegisterAccountPublic {} => {
let addr = wallet_core.create_new_account_public();
println!("Generated new account with addr {addr}");
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
Ok(SubcommandReturnValue::RegisterAccount { addr })
}
RegisterSubcommand::RegisterAccountPrivate {} => {
let addr = wallet_core.create_new_account_private();
let (key, _) = wallet_core
.storage
.user_data
.get_private_account(&addr)
.unwrap();
println!("Generated new account with addr {addr}");
println!("With npk {}", hex::encode(&key.nullifer_public_key));
println!(
"With ipk {}",
hex::encode(key.incoming_viewing_public_key.to_bytes())
);
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
Ok(SubcommandReturnValue::RegisterAccount { addr })
}
}
}
}
impl WalletSubcommand for ChainSubcommand {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
ChainSubcommand::Get(get_subcommand) => {
get_subcommand.handle_subcommand(wallet_core).await
}
ChainSubcommand::Fetch(fetch_subcommand) => {
fetch_subcommand.handle_subcommand(wallet_core).await
}
ChainSubcommand::Register(register_subcommand) => {
register_subcommand.handle_subcommand(wallet_core).await
}
}
}
}

View File

@ -2,6 +2,9 @@ use anyhow::Result;
use crate::{SubcommandReturnValue, WalletCore};
pub mod chain;
pub mod native_token_transfer_program;
pub mod pinata_program;
pub mod token_program;
pub(crate) trait WalletSubcommand {

View File

@ -0,0 +1,342 @@
use anyhow::Result;
use clap::Subcommand;
use common::transaction::NSSATransaction;
use nssa::Address;
use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand};
///Represents generic CLI subcommand for a wallet working with native token transfer program
#[derive(Subcommand, Debug, Clone)]
pub enum NativeTokenTransferProgramSubcommand {
///Send native token transfer from `from` to `to` for `amount`
///
/// Public operation
SendNativeTokenTransferPublic {
///from - valid 32 byte hex string
#[arg(long)]
from: String,
///to - valid 32 byte hex string
#[arg(long)]
to: String,
///amount - amount of balance to move
#[arg(long)]
amount: u128,
},
///Private execution
#[command(subcommand)]
Private(NativeTokenTransferProgramSubcommandPrivate),
///Send native token transfer from `from` to `to` for `amount`
///
/// Deshielded operation
SendNativeTokenTransferDeshielded {
///from - valid 32 byte hex string
#[arg(long)]
from: String,
///to - valid 32 byte hex string
#[arg(long)]
to: String,
///amount - amount of balance to move
#[arg(long)]
amount: u128,
},
///Shielded execution
#[command(subcommand)]
Shielded(NativeTokenTransferProgramSubcommandShielded),
}
///Represents generic shielded CLI subcommand for a wallet working with native token transfer program
#[derive(Subcommand, Debug, Clone)]
pub enum NativeTokenTransferProgramSubcommandShielded {
///Send native token transfer from `from` to `to` for `amount`
///
/// Shielded operation
SendNativeTokenTransferShielded {
///from - valid 32 byte hex string
#[arg(long)]
from: String,
///to - valid 32 byte hex string
#[arg(long)]
to: String,
///amount - amount of balance to move
#[arg(long)]
amount: u128,
},
///Send native token transfer from `from` to `to` for `amount`
///
/// Shielded operation
SendNativeTokenTransferShieldedForeignAccount {
///from - valid 32 byte hex string
#[arg(long)]
from: String,
///to_npk - valid 32 byte hex string
#[arg(long)]
to_npk: String,
///to_ipk - valid 33 byte hex string
#[arg(long)]
to_ipk: String,
///amount - amount of balance to move
#[arg(long)]
amount: u128,
},
}
///Represents generic private CLI subcommand for a wallet working with native token transfer program
#[derive(Subcommand, Debug, Clone)]
pub enum NativeTokenTransferProgramSubcommandPrivate {
///Send native token transfer from `from` to `to` for `amount`
///
/// Private operation
SendNativeTokenTransferPrivateOwnedAccount {
///from - valid 32 byte hex string
#[arg(long)]
from: String,
///to - valid 32 byte hex string
#[arg(long)]
to: String,
///amount - amount of balance to move
#[arg(long)]
amount: u128,
},
///Send native token transfer from `from` to `to` for `amount`
///
/// Private operation
SendNativeTokenTransferPrivateForeignAccount {
///from - valid 32 byte hex string
#[arg(long)]
from: String,
///to_npk - valid 32 byte hex string
#[arg(long)]
to_npk: String,
///to_ipk - valid 33 byte hex string
#[arg(long)]
to_ipk: String,
///amount - amount of balance to move
#[arg(long)]
amount: u128,
},
}
impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
NativeTokenTransferProgramSubcommandPrivate::SendNativeTokenTransferPrivateOwnedAccount { from, to, amount } => {
let from: Address = from.parse().unwrap();
let to: Address = to.parse().unwrap();
let (res, [secret_from, secret_to]) = wallet_core
.send_private_native_token_transfer_owned_account(from, to, amount)
.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_from, from), (secret_to, to)];
wallet_core
.decode_insert_privacy_preserving_transaction_results(tx, &acc_decode_data)?;
}
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
NativeTokenTransferProgramSubcommandPrivate::SendNativeTokenTransferPrivateForeignAccount {
from,
to_npk,
to_ipk,
amount,
} => {
let from: Address = from.parse().unwrap();
let to_npk_res = hex::decode(to_npk)?;
let mut to_npk = [0; 32];
to_npk.copy_from_slice(&to_npk_res);
let to_npk = nssa_core::NullifierPublicKey(to_npk);
let to_ipk_res = hex::decode(to_ipk)?;
let mut to_ipk = [0u8; 33];
to_ipk.copy_from_slice(&to_ipk_res);
let to_ipk =
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec());
let (res, [secret_from, _]) = wallet_core
.send_private_native_token_transfer_outer_account(from, to_npk, to_ipk, amount)
.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_from, from)];
wallet_core
.decode_insert_privacy_preserving_transaction_results(tx, &acc_decode_data)?;
}
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
}
}
}
impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
NativeTokenTransferProgramSubcommandShielded::SendNativeTokenTransferShielded { from, to, amount } => {
let from: Address = from.parse().unwrap();
let to: Address = to.parse().unwrap();
let (res, secret) = wallet_core
.send_shielded_native_token_transfer(from, to, amount)
.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, to)];
wallet_core
.decode_insert_privacy_preserving_transaction_results(tx, &acc_decode_data)?;
}
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
NativeTokenTransferProgramSubcommandShielded::SendNativeTokenTransferShieldedForeignAccount {
from,
to_npk,
to_ipk,
amount,
} => {
let from: Address = from.parse().unwrap();
let to_npk_res = hex::decode(to_npk)?;
let mut to_npk = [0; 32];
to_npk.copy_from_slice(&to_npk_res);
let to_npk = nssa_core::NullifierPublicKey(to_npk);
let to_ipk_res = hex::decode(to_ipk)?;
let mut to_ipk = [0u8; 33];
to_ipk.copy_from_slice(&to_ipk_res);
let to_ipk =
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec());
let (res, _) = wallet_core
.send_shielded_native_token_transfer_outer_account(from, to_npk, to_ipk, amount)
.await?;
println!("Results of tx send is {res:#?}");
let tx_hash = res.tx_hash;
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
}
}
}
impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
NativeTokenTransferProgramSubcommand::Private(private_subcommand) => {
private_subcommand.handle_subcommand(wallet_core).await
}
NativeTokenTransferProgramSubcommand::Shielded(shielded_subcommand) => {
shielded_subcommand.handle_subcommand(wallet_core).await
}
NativeTokenTransferProgramSubcommand::SendNativeTokenTransferDeshielded {
from,
to,
amount,
} => {
let from: Address = from.parse().unwrap();
let to: Address = to.parse().unwrap();
let (res, secret) = wallet_core
.send_deshielded_native_token_transfer(from, to, amount)
.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, from)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
tx,
&acc_decode_data,
)?;
}
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
NativeTokenTransferProgramSubcommand::SendNativeTokenTransferPublic {
from,
to,
amount,
} => {
let from: Address = from.parse().unwrap();
let to: Address = to.parse().unwrap();
let res = wallet_core
.send_public_native_token_transfer(from, to, amount)
.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()?;
println!("Stored persistent accounts at {path:#?}");
Ok(SubcommandReturnValue::Empty)
}
}
}
}

View File

@ -0,0 +1,157 @@
use anyhow::Result;
use clap::Subcommand;
use common::transaction::NSSATransaction;
use log::info;
use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand};
///Represents generic CLI subcommand for a wallet working with pinata program
#[derive(Subcommand, Debug, Clone)]
pub enum PinataProgramSubcommand {
///Public execution
#[command(subcommand)]
Public(PinataProgramSubcommandPublic),
///Private execution
#[command(subcommand)]
Private(PinataProgramSubcommandPrivate),
}
///Represents generic public CLI subcommand for a wallet working with pinata program
#[derive(Subcommand, Debug, Clone)]
pub enum PinataProgramSubcommandPublic {
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
// Claim piñata prize
ClaimPinata {
///pinata_addr - valid 32 byte hex string
#[arg(long)]
pinata_addr: String,
///winner_addr - valid 32 byte hex string
#[arg(long)]
winner_addr: String,
///solution - solution to pinata challenge
#[arg(long)]
solution: u128,
},
}
///Represents generic private CLI subcommand for a wallet working with pinata program
#[derive(Subcommand, Debug, Clone)]
pub enum PinataProgramSubcommandPrivate {
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
// Claim piñata prize
ClaimPinataPrivateReceiverOwned {
///pinata_addr - valid 32 byte hex string
#[arg(long)]
pinata_addr: String,
///winner_addr - valid 32 byte hex string
#[arg(long)]
winner_addr: String,
///solution - solution to pinata challenge
#[arg(long)]
solution: u128,
},
}
impl WalletSubcommand for PinataProgramSubcommandPublic {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
PinataProgramSubcommandPublic::ClaimPinata {
pinata_addr,
winner_addr,
solution,
} => {
let res = wallet_core
.claim_pinata(
pinata_addr.parse().unwrap(),
winner_addr.parse().unwrap(),
solution,
)
.await?;
info!("Results of tx send is {res:#?}");
Ok(SubcommandReturnValue::Empty)
}
}
}
}
impl WalletSubcommand for PinataProgramSubcommandPrivate {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
PinataProgramSubcommandPrivate::ClaimPinataPrivateReceiverOwned {
pinata_addr,
winner_addr,
solution,
} => {
let pinata_addr = pinata_addr.parse().unwrap();
let winner_addr = winner_addr.parse().unwrap();
let winner_intialized = wallet_core
.check_private_account_initialized(&winner_addr)
.await;
let (res, [secret_winner]) = if winner_intialized {
wallet_core
.claim_pinata_private_owned_account_already_initialized(
pinata_addr,
winner_addr,
solution,
)
.await?
} else {
wallet_core
.claim_pinata_private_owned_account_not_initialized(
pinata_addr,
winner_addr,
solution,
)
.await?
};
info!("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_winner, winner_addr)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
tx,
&acc_decode_data,
)?;
}
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
}
}
}
impl WalletSubcommand for PinataProgramSubcommand {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
PinataProgramSubcommand::Private(private_subcommand) => {
private_subcommand.handle_subcommand(wallet_core).await
}
PinataProgramSubcommand::Public(public_subcommand) => {
public_subcommand.handle_subcommand(wallet_core).await
}
}
}
}

View File

@ -1,4 +1,4 @@
use std::{fs::File, io::Write, path::PathBuf, str::FromStr, sync::Arc};
use std::{fs::File, io::Write, path::PathBuf, sync::Arc};
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
use common::{
@ -15,12 +15,15 @@ use nssa::{Account, Address};
use clap::{Parser, Subcommand};
use nssa_core::Commitment;
use crate::cli::WalletSubcommand;
use crate::cli::{
WalletSubcommand, chain::ChainSubcommand,
native_token_transfer_program::NativeTokenTransferProgramSubcommand,
pinata_program::PinataProgramSubcommand,
};
use crate::{
cli::token_program::TokenProgramSubcommand,
helperfunctions::{
HumanReadableAccount, fetch_config, fetch_persistent_accounts, get_home,
produce_data_for_storage,
fetch_config, fetch_persistent_accounts, get_home, produce_data_for_storage,
},
poller::TxPoller,
};
@ -181,163 +184,15 @@ impl WalletCore {
#[derive(Subcommand, Debug, Clone)]
#[clap(about)]
pub enum Command {
///Send native token transfer from `from` to `to` for `amount`
///
/// Public operation
SendNativeTokenTransferPublic {
///from - valid 32 byte hex string
#[arg(long)]
from: String,
///to - valid 32 byte hex string
#[arg(long)]
to: String,
///amount - amount of balance to move
#[arg(long)]
amount: u128,
},
///Send native token transfer from `from` to `to` for `amount`
///
/// Private operation
SendNativeTokenTransferPrivateOwnedAccount {
///from - valid 32 byte hex string
#[arg(long)]
from: String,
///to - valid 32 byte hex string
#[arg(long)]
to: String,
///amount - amount of balance to move
#[arg(long)]
amount: u128,
},
///Send native token transfer from `from` to `to` for `amount`
///
/// Private operation
SendNativeTokenTransferPrivateForeignAccount {
///from - valid 32 byte hex string
#[arg(long)]
from: String,
///to_npk - valid 32 byte hex string
#[arg(long)]
to_npk: String,
///to_ipk - valid 33 byte hex string
#[arg(long)]
to_ipk: String,
///amount - amount of balance to move
#[arg(long)]
amount: u128,
},
///Send native token transfer from `from` to `to` for `amount`
///
/// Deshielded operation
SendNativeTokenTransferDeshielded {
///from - valid 32 byte hex string
#[arg(long)]
from: String,
///to - valid 32 byte hex string
#[arg(long)]
to: String,
///amount - amount of balance to move
#[arg(long)]
amount: u128,
},
///Send native token transfer from `from` to `to` for `amount`
///
/// Shielded operation
SendNativeTokenTransferShielded {
///from - valid 32 byte hex string
#[arg(long)]
from: String,
///to - valid 32 byte hex string
#[arg(long)]
to: String,
///amount - amount of balance to move
#[arg(long)]
amount: u128,
},
///Send native token transfer from `from` to `to` for `amount`
///
/// Shielded operation
SendNativeTokenTransferShieldedForeignAccount {
///from - valid 32 byte hex string
#[arg(long)]
from: String,
///to_npk - valid 32 byte hex string
#[arg(long)]
to_npk: String,
///to_ipk - valid 33 byte hex string
#[arg(long)]
to_ipk: String,
///amount - amount of balance to move
#[arg(long)]
amount: u128,
},
///Claim account `acc_addr` generated in transaction `tx_hash`, using secret `sh_secret` at ciphertext id `ciph_id`
FetchPrivateAccount {
///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,
},
///Get private account with `addr` from storage
GetPrivateAccount {
#[arg(short, long)]
addr: String,
},
///Register new public account
RegisterAccountPublic {},
///Register new private account
RegisterAccountPrivate {},
///Fetch transaction by `hash`
FetchTx {
#[arg(short, long)]
tx_hash: String,
},
///Get account `addr` balance
GetPublicAccountBalance {
#[arg(short, long)]
addr: String,
},
///Get account `addr` nonce
GetPublicAccountNonce {
#[arg(short, long)]
addr: String,
},
///Get account at address `addr`
GetPublicAccount {
#[arg(short, long)]
addr: String,
},
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
// Claim piñata prize
ClaimPinata {
///pinata_addr - valid 32 byte hex string
#[arg(long)]
pinata_addr: String,
///winner_addr - valid 32 byte hex string
#[arg(long)]
winner_addr: String,
///solution - solution to pinata challenge
#[arg(long)]
solution: u128,
},
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
// Claim piñata prize
ClaimPinataPrivateReceiverOwned {
///pinata_addr - valid 32 byte hex string
#[arg(long)]
pinata_addr: String,
///winner_addr - valid 32 byte hex string
#[arg(long)]
winner_addr: String,
///solution - solution to pinata challenge
#[arg(long)]
solution: u128,
},
///Transfer command
#[command(subcommand)]
Transfer(NativeTokenTransferProgramSubcommand),
///Chain command
#[command(subcommand)]
Chain(ChainSubcommand),
///Pinata command
#[command(subcommand)]
PinataProgram(PinataProgramSubcommand),
///Token command
#[command(subcommand)]
TokenProgram(TokenProgramSubcommand),
@ -365,373 +220,18 @@ pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValu
let mut wallet_core = WalletCore::start_from_config_update_chain(wallet_config)?;
let subcommand_ret = match command {
Command::SendNativeTokenTransferPublic { from, to, amount } => {
let from: Address = from.parse().unwrap();
let to: Address = to.parse().unwrap();
let res = wallet_core
.send_public_native_token_transfer(from, to, amount)
.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()?;
println!("Stored persistent accounts at {path:#?}");
SubcommandReturnValue::Empty
Command::Transfer(transfer_subcommand) => {
transfer_subcommand
.handle_subcommand(&mut wallet_core)
.await?
}
Command::SendNativeTokenTransferPrivateOwnedAccount { from, to, amount } => {
let from: Address = from.parse().unwrap();
let to: Address = to.parse().unwrap();
let (res, [secret_from, secret_to]) = wallet_core
.send_private_native_token_transfer_owned_account(from, to, amount)
.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_from, from), (secret_to, to)];
wallet_core
.decode_insert_privacy_preserving_transaction_results(tx, &acc_decode_data)?;
}
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
Command::Chain(chain_subcommand) => {
chain_subcommand.handle_subcommand(&mut wallet_core).await?
}
Command::SendNativeTokenTransferPrivateForeignAccount {
from,
to_npk,
to_ipk,
amount,
} => {
let from: Address = from.parse().unwrap();
let to_npk_res = hex::decode(to_npk)?;
let mut to_npk = [0; 32];
to_npk.copy_from_slice(&to_npk_res);
let to_npk = nssa_core::NullifierPublicKey(to_npk);
let to_ipk_res = hex::decode(to_ipk)?;
let mut to_ipk = [0u8; 33];
to_ipk.copy_from_slice(&to_ipk_res);
let to_ipk =
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec());
let (res, [secret_from, _]) = wallet_core
.send_private_native_token_transfer_outer_account(from, to_npk, to_ipk, amount)
.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_from, from)];
wallet_core
.decode_insert_privacy_preserving_transaction_results(tx, &acc_decode_data)?;
}
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
}
Command::SendNativeTokenTransferDeshielded { from, to, amount } => {
let from: Address = from.parse().unwrap();
let to: Address = to.parse().unwrap();
let (res, secret) = wallet_core
.send_deshielded_native_token_transfer(from, to, amount)
.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, from)];
wallet_core
.decode_insert_privacy_preserving_transaction_results(tx, &acc_decode_data)?;
}
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
}
Command::SendNativeTokenTransferShielded { from, to, amount } => {
let from: Address = from.parse().unwrap();
let to: Address = to.parse().unwrap();
let (res, secret) = wallet_core
.send_shielded_native_token_transfer(from, to, amount)
.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, to)];
wallet_core
.decode_insert_privacy_preserving_transaction_results(tx, &acc_decode_data)?;
}
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
}
Command::SendNativeTokenTransferShieldedForeignAccount {
from,
to_npk,
to_ipk,
amount,
} => {
let from: Address = from.parse().unwrap();
let to_npk_res = hex::decode(to_npk)?;
let mut to_npk = [0; 32];
to_npk.copy_from_slice(&to_npk_res);
let to_npk = nssa_core::NullifierPublicKey(to_npk);
let to_ipk_res = hex::decode(to_ipk)?;
let mut to_ipk = [0u8; 33];
to_ipk.copy_from_slice(&to_ipk_res);
let to_ipk =
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec());
let (res, _) = wallet_core
.send_shielded_native_token_transfer_outer_account(from, to_npk, to_ipk, amount)
.await?;
println!("Results of tx send is {res:#?}");
let tx_hash = res.tx_hash;
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
}
Command::FetchPrivateAccount {
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()?;
println!("Stored persistent accounts at {path:#?}");
SubcommandReturnValue::Empty
}
Command::RegisterAccountPublic {} => {
let addr = wallet_core.create_new_account_public();
println!("Generated new account with addr {addr}");
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
SubcommandReturnValue::RegisterAccount { addr }
}
Command::RegisterAccountPrivate {} => {
let addr = wallet_core.create_new_account_private();
let (key, _) = wallet_core
.storage
.user_data
.get_private_account(&addr)
.unwrap();
println!("Generated new account with addr {addr}");
println!("With npk {}", hex::encode(&key.nullifer_public_key));
println!(
"With ipk {}",
hex::encode(key.incoming_viewing_public_key.to_bytes())
);
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
SubcommandReturnValue::RegisterAccount { addr }
}
Command::FetchTx { tx_hash } => {
let tx_obj = wallet_core
.sequencer_client
.get_transaction_by_hash(tx_hash)
.await?;
println!("Transaction object {tx_obj:#?}");
SubcommandReturnValue::Empty
}
Command::GetPublicAccountBalance { addr } => {
let addr = Address::from_str(&addr)?;
let balance = wallet_core.get_account_balance(addr).await?;
println!("Accounts {addr} balance is {balance}");
SubcommandReturnValue::Empty
}
Command::GetPublicAccountNonce { addr } => {
let addr = Address::from_str(&addr)?;
let nonce = wallet_core.get_accounts_nonces(vec![addr]).await?[0];
println!("Accounts {addr} nonce is {nonce}");
SubcommandReturnValue::Empty
}
Command::GetPublicAccount { 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());
SubcommandReturnValue::Account(account)
}
Command::GetPrivateAccount { 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.");
}
SubcommandReturnValue::Empty
}
Command::ClaimPinata {
pinata_addr,
winner_addr,
solution,
} => {
let res = wallet_core
.claim_pinata(
pinata_addr.parse().unwrap(),
winner_addr.parse().unwrap(),
solution,
)
.await?;
info!("Results of tx send is {res:#?}");
SubcommandReturnValue::Empty
}
Command::ClaimPinataPrivateReceiverOwned {
pinata_addr,
winner_addr,
solution,
} => {
let pinata_addr = pinata_addr.parse().unwrap();
let winner_addr = winner_addr.parse().unwrap();
let winner_intialized = wallet_core
.check_private_account_initialized(&winner_addr)
.await;
let (res, [secret_winner]) = if winner_intialized {
wallet_core
.claim_pinata_private_owned_account_already_initialized(
pinata_addr,
winner_addr,
solution,
)
.await?
} else {
wallet_core
.claim_pinata_private_owned_account_not_initialized(
pinata_addr,
winner_addr,
solution,
)
.await?
};
info!("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_winner, winner_addr)];
wallet_core
.decode_insert_privacy_preserving_transaction_results(tx, &acc_decode_data)?;
}
let path = wallet_core.store_persistent_accounts()?;
println!("Stored persistent accounts at {path:#?}");
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
Command::PinataProgram(pinata_subcommand) => {
pinata_subcommand
.handle_subcommand(&mut wallet_core)
.await?
}
Command::TokenProgram(token_subcommand) => {
token_subcommand.handle_subcommand(&mut wallet_core).await?