feat: transfers changes

This commit is contained in:
Oleksandr Pravdyvyi 2025-10-27 14:32:28 +02:00
parent 66ee0c5449
commit 62668161b2
No known key found for this signature in database
GPG Key ID: 9F8955C63C443871
7 changed files with 614 additions and 178 deletions

View File

@ -42,6 +42,14 @@ pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12;
pub const NSSA_PROGRAM_FOR_TEST_DATA_CHANGER: &[u8] = include_bytes!("data_changer.bin");
fn make_public_account_input_from_str(addr: &str) -> String {
format!("Public/{addr:?}")
}
fn make_private_account_input_from_str(addr: &str) -> String {
format!("Private/{addr:?}")
}
#[allow(clippy::type_complexity)]
pub async fn pre_test(
home_dir: PathBuf,

View File

@ -8,18 +8,11 @@ use wallet::{
Command, SubcommandReturnValue, WalletCore,
cli::{
account::{AccountSubcommand, FetchSubcommand, NewSubcommand},
native_token_transfer_program::{
NativeTokenTransferProgramSubcommand, NativeTokenTransferProgramSubcommandPrivate,
NativeTokenTransferProgramSubcommandShielded,
},
native_token_transfer_program::AuthTransferSubcommand,
pinata_program::{
PinataProgramSubcommand, PinataProgramSubcommandPrivate, PinataProgramSubcommandPublic,
},
token_program::{
TokenProgramSubcommand, TokenProgramSubcommandDeshielded,
TokenProgramSubcommandPrivate, TokenProgramSubcommandPublic,
TokenProgramSubcommandShielded,
},
token_program::TokenProgramAgnosticSubcommand,
},
config::PersistentAccountData,
helperfunctions::{fetch_config, fetch_persistent_accounts},
@ -30,7 +23,8 @@ use sequencer_core::sequencer_store::PINATA_BASE58;
use crate::{
ACC_RECEIVER, ACC_RECEIVER_PRIVATE, ACC_SENDER, ACC_SENDER_PRIVATE,
NSSA_PROGRAM_FOR_TEST_DATA_CHANGER, TIME_TO_WAIT_FOR_BLOCK_SECONDS,
fetch_privacy_preserving_tx,
fetch_privacy_preserving_tx, make_private_account_input_from_str,
make_public_account_input_from_str,
};
use crate::{post_test, pre_test, verify_commitment_is_in_state};
@ -42,9 +36,11 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
#[test_suite_fn]
pub async fn test_success() {
info!("test_success");
let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public {
from: ACC_SENDER.to_string(),
to: ACC_RECEIVER.to_string(),
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: make_public_account_input_from_str(ACC_SENDER),
to: Some(make_public_account_input_from_str(ACC_RECEIVER)),
to_npk: None,
to_ipk: None,
amount: 100,
});
@ -103,9 +99,13 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
panic!("Failed to produce new account, not present in persistent accounts");
}
let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public {
from: ACC_SENDER.to_string(),
to: new_persistent_account_addr.clone(),
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: make_public_account_input_from_str(ACC_SENDER),
to: Some(make_public_account_input_from_str(
&new_persistent_account_addr,
)),
to_npk: None,
to_ipk: None,
amount: 100,
});
@ -136,9 +136,11 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
#[test_suite_fn]
pub async fn test_failure() {
info!("test_failure");
let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public {
from: ACC_SENDER.to_string(),
to: ACC_RECEIVER.to_string(),
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: make_public_account_input_from_str(ACC_SENDER),
to: Some(make_public_account_input_from_str(ACC_RECEIVER)),
to_npk: None,
to_ipk: None,
amount: 1000000,
});
@ -175,9 +177,11 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
#[test_suite_fn]
pub async fn test_success_two_transactions() {
info!("test_success_two_transactions");
let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public {
from: ACC_SENDER.to_string(),
to: ACC_RECEIVER.to_string(),
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: make_public_account_input_from_str(ACC_SENDER),
to: Some(make_public_account_input_from_str(ACC_RECEIVER)),
to_npk: None,
to_ipk: None,
amount: 100,
});
@ -208,9 +212,11 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
info!("First TX Success!");
let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Public {
from: ACC_SENDER.to_string(),
to: ACC_RECEIVER.to_string(),
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: make_public_account_input_from_str(ACC_SENDER),
to: Some(make_public_account_input_from_str(ACC_RECEIVER)),
to_npk: None,
to_ipk: None,
amount: 100,
});
@ -306,13 +312,12 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
.expect("Failed to produce new account, not present in persistent accounts");
// Create new token
let subcommand =
TokenProgramSubcommand::Public(TokenProgramSubcommandPublic::CreateNewToken {
definition_addr: definition_addr.to_string(),
supply_addr: supply_addr.to_string(),
name: "A NAME".to_string(),
total_supply: 37,
});
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_addr: make_public_account_input_from_str(&definition_addr.to_string()),
supply_addr: make_public_account_input_from_str(&supply_addr.to_string()),
name: "A NAME".to_string(),
total_supply: 37,
};
wallet::execute_subcommand(Command::Token(subcommand))
.await
.unwrap();
@ -361,12 +366,16 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
);
// Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr`
let subcommand =
TokenProgramSubcommand::Public(TokenProgramSubcommandPublic::TransferToken {
sender_addr: supply_addr.to_string(),
recipient_addr: recipient_addr.to_string(),
balance_to_move: 7,
});
let subcommand = TokenProgramAgnosticSubcommand::Send {
from: make_public_account_input_from_str(&supply_addr.to_string()),
to: Some(make_public_account_input_from_str(
&recipient_addr.to_string(),
)),
to_npk: None,
to_ipk: None,
amount: 7,
};
wallet::execute_subcommand(Command::Token(subcommand))
.await
.unwrap();
@ -449,14 +458,12 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
};
// Create new token
let subcommand = TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned {
definition_addr: definition_addr.to_string(),
supply_addr: supply_addr.to_string(),
name: "A NAME".to_string(),
total_supply: 37,
},
);
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_addr: make_public_account_input_from_str(&definition_addr.to_string()),
supply_addr: make_private_account_input_from_str(&supply_addr.to_string()),
name: "A NAME".to_string(),
total_supply: 37,
};
wallet::execute_subcommand(Command::Token(subcommand))
.await
@ -495,13 +502,15 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await);
// Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr`
let subcommand = TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::TransferTokenPrivateOwned {
sender_addr: supply_addr.to_string(),
recipient_addr: recipient_addr.to_string(),
balance_to_move: 7,
},
);
let subcommand = TokenProgramAgnosticSubcommand::Send {
from: make_private_account_input_from_str(&supply_addr.to_string()),
to: Some(make_private_account_input_from_str(
&recipient_addr.to_string(),
)),
to_npk: None,
to_ipk: None,
amount: 7,
};
wallet::execute_subcommand(Command::Token(subcommand))
.await
@ -526,13 +535,15 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await);
// Transfer additional 7 tokens from `supply_acc` to the account at address `recipient_addr`
let subcommand = TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::TransferTokenPrivateOwned {
sender_addr: supply_addr.to_string(),
recipient_addr: recipient_addr.to_string(),
balance_to_move: 7,
},
);
let subcommand = TokenProgramAgnosticSubcommand::Send {
from: make_private_account_input_from_str(&supply_addr.to_string()),
to: Some(make_private_account_input_from_str(
&recipient_addr.to_string(),
)),
to_npk: None,
to_ipk: None,
amount: 7,
};
wallet::execute_subcommand(Command::Token(subcommand))
.await
@ -597,14 +608,12 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
};
// Create new token
let subcommand = TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned {
definition_addr: definition_addr.to_string(),
supply_addr: supply_addr.to_string(),
name: "A NAME".to_string(),
total_supply: 37,
},
);
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_addr: make_public_account_input_from_str(&definition_addr.to_string()),
supply_addr: make_private_account_input_from_str(&supply_addr.to_string()),
name: "A NAME".to_string(),
total_supply: 37,
};
wallet::execute_subcommand(Command::Token(subcommand))
.await
@ -649,14 +658,15 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
.unwrap();
// Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr`
let subcommand = TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::TransferTokenPrivateForeign {
sender_addr: supply_addr.to_string(),
recipient_npk: hex::encode(recipient_keys.nullifer_public_key.0),
recipient_ipk: hex::encode(recipient_keys.incoming_viewing_public_key.0.clone()),
balance_to_move: 7,
},
);
let subcommand = TokenProgramAgnosticSubcommand::Send {
from: make_private_account_input_from_str(&supply_addr.to_string()),
to: None,
to_npk: Some(hex::encode(recipient_keys.nullifer_public_key.0)),
to_ipk: Some(hex::encode(
recipient_keys.incoming_viewing_public_key.0.clone(),
)),
amount: 7,
};
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } =
wallet::execute_subcommand(Command::Token(subcommand))
@ -733,13 +743,12 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
};
// Create new token
let subcommand =
TokenProgramSubcommand::Public(TokenProgramSubcommandPublic::CreateNewToken {
definition_addr: definition_addr.to_string(),
supply_addr: supply_addr.to_string(),
name: "A NAME".to_string(),
total_supply: 37,
});
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_addr: make_public_account_input_from_str(&definition_addr.to_string()),
supply_addr: make_public_account_input_from_str(&supply_addr.to_string()),
name: "A NAME".to_string(),
total_supply: 37,
};
wallet::execute_subcommand(Command::Token(subcommand))
.await
@ -768,13 +777,15 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
);
// Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr`
let subcommand = TokenProgramSubcommand::Shielded(
TokenProgramSubcommandShielded::TransferTokenShieldedOwned {
sender_addr: supply_addr.to_string(),
recipient_addr: recipient_addr.to_string(),
balance_to_move: 7,
},
);
let subcommand = TokenProgramAgnosticSubcommand::Send {
from: make_public_account_input_from_str(&supply_addr.to_string()),
to: Some(make_private_account_input_from_str(
&recipient_addr.to_string(),
)),
to_npk: None,
to_ipk: None,
amount: 7,
};
wallet::execute_subcommand(Command::Token(subcommand))
.await
@ -794,13 +805,15 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await);
// Transfer additional 7 tokens from `supply_acc` to the account at address `recipient_addr`
let subcommand = TokenProgramSubcommand::Shielded(
TokenProgramSubcommandShielded::TransferTokenShieldedOwned {
sender_addr: supply_addr.to_string(),
recipient_addr: recipient_addr.to_string(),
balance_to_move: 7,
},
);
let subcommand = TokenProgramAgnosticSubcommand::Send {
from: make_public_account_input_from_str(&supply_addr.to_string()),
to: Some(make_private_account_input_from_str(
&recipient_addr.to_string(),
)),
to_npk: None,
to_ipk: None,
amount: 7,
};
wallet::execute_subcommand(Command::Token(subcommand))
.await
@ -860,14 +873,12 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
};
// Create new token
let subcommand = TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned {
definition_addr: definition_addr.to_string(),
supply_addr: supply_addr.to_string(),
name: "A NAME".to_string(),
total_supply: 37,
},
);
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_addr: make_public_account_input_from_str(&definition_addr.to_string()),
supply_addr: make_private_account_input_from_str(&supply_addr.to_string()),
name: "A NAME".to_string(),
total_supply: 37,
};
wallet::execute_subcommand(Command::Token(subcommand))
.await
@ -906,13 +917,15 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await);
// Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr`
let subcommand = TokenProgramSubcommand::Deshielded(
TokenProgramSubcommandDeshielded::TransferTokenDeshielded {
sender_addr: supply_addr.to_string(),
recipient_addr: recipient_addr.to_string(),
balance_to_move: 7,
},
);
let subcommand = TokenProgramAgnosticSubcommand::Send {
from: make_private_account_input_from_str(&supply_addr.to_string()),
to: Some(make_public_account_input_from_str(
&recipient_addr.to_string(),
)),
to_npk: None,
to_ipk: None,
amount: 7,
};
wallet::execute_subcommand(Command::Token(subcommand))
.await
@ -932,13 +945,15 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await);
// Transfer additional 7 tokens from `supply_acc` to the account at address `recipient_addr`
let subcommand = TokenProgramSubcommand::Deshielded(
TokenProgramSubcommandDeshielded::TransferTokenDeshielded {
sender_addr: supply_addr.to_string(),
recipient_addr: recipient_addr.to_string(),
balance_to_move: 7,
},
);
let subcommand = TokenProgramAgnosticSubcommand::Send {
from: make_private_account_input_from_str(&supply_addr.to_string()),
to: Some(make_public_account_input_from_str(
&recipient_addr.to_string(),
)),
to_npk: None,
to_ipk: None,
amount: 7,
};
wallet::execute_subcommand(Command::Token(subcommand))
.await
@ -964,13 +979,13 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
let from: Address = ACC_SENDER_PRIVATE.parse().unwrap();
let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap();
let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private(
NativeTokenTransferProgramSubcommandPrivate::PrivateOwned {
from: from.to_string(),
to: to.to_string(),
amount: 100,
},
));
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: make_private_account_input_from_str(&from.to_string()),
to: Some(make_private_account_input_from_str(&to.to_string())),
to_npk: None,
to_ipk: None,
amount: 100,
});
wallet::execute_subcommand(command).await.unwrap();
@ -1002,14 +1017,13 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
let to_npk_string = hex::encode(to_npk.0);
let to_ipk = Secp256k1Point::from_scalar(to_npk.0);
let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private(
NativeTokenTransferProgramSubcommandPrivate::PrivateForeign {
from: from.to_string(),
to_npk: to_npk_string,
to_ipk: hex::encode(to_ipk.0),
amount: 100,
},
));
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: make_private_account_input_from_str(&from.to_string()),
to: None,
to_npk: Some(to_npk_string),
to_ipk: Some(hex::encode(to_ipk.0)),
amount: 100,
});
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } =
wallet::execute_subcommand(command).await.unwrap()
@ -1067,14 +1081,13 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
.cloned()
.unwrap();
let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private(
NativeTokenTransferProgramSubcommandPrivate::PrivateForeign {
from: from.to_string(),
to_npk: hex::encode(to_keys.nullifer_public_key.0),
to_ipk: hex::encode(to_keys.incoming_viewing_public_key.0),
amount: 100,
},
));
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: make_private_account_input_from_str(&from.to_string()),
to: None,
to_npk: Some(hex::encode(to_keys.nullifer_public_key.0)),
to_ipk: Some(hex::encode(to_keys.incoming_viewing_public_key.0)),
amount: 100,
});
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else {
@ -1138,14 +1151,13 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
.cloned()
.unwrap();
let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Private(
NativeTokenTransferProgramSubcommandPrivate::PrivateForeign {
from: from.to_string(),
to_npk: hex::encode(to_keys.nullifer_public_key.0),
to_ipk: hex::encode(to_keys.incoming_viewing_public_key.0),
amount: 100,
},
));
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: make_private_account_input_from_str(&from.to_string()),
to: None,
to_npk: Some(hex::encode(to_keys.nullifer_public_key.0)),
to_ipk: Some(hex::encode(to_keys.incoming_viewing_public_key.0)),
amount: 100,
});
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else {
@ -1186,9 +1198,12 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
info!("test_success_deshielded_transfer_to_another_account");
let from: Address = ACC_SENDER_PRIVATE.parse().unwrap();
let to: Address = ACC_RECEIVER.parse().unwrap();
let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Deshielded {
from: from.to_string(),
to: to.to_string(),
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: make_private_account_input_from_str(&from.to_string()),
to: Some(make_public_account_input_from_str(&to.to_string())),
to_npk: None,
to_ipk: None,
amount: 100,
});
@ -1232,13 +1247,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
info!("test_success_shielded_transfer_to_another_owned_account");
let from: Address = ACC_SENDER.parse().unwrap();
let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap();
let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Shielded(
NativeTokenTransferProgramSubcommandShielded::ShieldedOwned {
from: from.to_string(),
to: to.to_string(),
amount: 100,
},
));
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: make_public_account_input_from_str(&from.to_string()),
to: Some(make_private_account_input_from_str(&to.to_string())),
to_npk: None,
to_ipk: None,
amount: 100,
});
let wallet_config = fetch_config().await.unwrap();
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
@ -1276,14 +1292,13 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
let to_ipk = Secp256k1Point::from_scalar(to_npk.0);
let from: Address = ACC_SENDER.parse().unwrap();
let command = Command::AuthTransfer(NativeTokenTransferProgramSubcommand::Shielded(
NativeTokenTransferProgramSubcommandShielded::ShieldedForeign {
from: from.to_string(),
to_npk: to_npk_string,
to_ipk: hex::encode(to_ipk.0),
amount: 100,
},
));
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: make_public_account_input_from_str(&from.to_string()),
to: None,
to_npk: Some(to_npk_string),
to_ipk: Some(hex::encode(to_ipk.0)),
amount: 100,
});
let wallet_config = fetch_config().await.unwrap();

View File

@ -82,6 +82,8 @@ pub enum AccountSubcommand {
///New
#[command(subcommand)]
New(NewSubcommand),
///Sync private accounts
SyncPrivate {},
}
///Represents generic getter CLI subcommand
@ -213,7 +215,7 @@ impl WalletSubcommand for NewSubcommand {
"Generated new account with addr {}",
addr.to_bytes().to_base58()
);
println!("With npk {}", hex::encode(&key.nullifer_public_key.0));
println!("With npk {}", hex::encode(key.nullifer_public_key.0));
println!(
"With ipk {}",
hex::encode(key.incoming_viewing_public_key.to_bytes())
@ -303,12 +305,12 @@ impl WalletSubcommand for AccountSubcommand {
let token_prog_id = Program::token().id();
let acc_view = match &account.program_owner {
_ if &account.program_owner == &auth_tr_prog_id => {
_ if account.program_owner == auth_tr_prog_id => {
let acc_view: AuthenticatedTransferAccountView = account.into();
serde_json::to_string(&acc_view)?
}
_ if &account.program_owner == &token_prog_id => {
_ if account.program_owner == token_prog_id => {
if let Some(token_def) = TokenDefinition::parse(&account.data) {
let acc_view: TokedDefinitionAccountView = token_def.into();
@ -337,6 +339,9 @@ impl WalletSubcommand for AccountSubcommand {
AccountSubcommand::New(new_subcommand) => {
new_subcommand.handle_subcommand(wallet_core).await
}
AccountSubcommand::SyncPrivate {} => {
todo!();
}
}
}
}

View File

@ -3,7 +3,187 @@ use clap::Subcommand;
use common::transaction::NSSATransaction;
use nssa::Address;
use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand};
use crate::{
SubcommandReturnValue, WalletCore,
cli::WalletSubcommand,
helperfunctions::{AddressPrivacyKind, parse_addr_with_privacy_prefix},
};
///Represents generic CLI subcommand for a wallet working with native token transfer program
#[derive(Subcommand, Debug, Clone)]
pub enum AuthTransferSubcommand {
Init {
///addr - valid 32 byte base58 string
#[arg(long)]
addr: String,
},
Send {
///from - valid 32 byte base58 string
#[arg(long)]
from: String,
///to - valid 32 byte base58 string
#[arg(long)]
to: Option<String>,
///to_npk - valid 32 byte base58 string
#[arg(long)]
to_npk: Option<String>,
///to_ipk - valid 33 byte base58 string
#[arg(long)]
to_ipk: Option<String>,
///amount - amount of balance to move
#[arg(long)]
amount: u128,
},
}
impl WalletSubcommand for AuthTransferSubcommand {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
AuthTransferSubcommand::Init { addr } => {
let (addr, addr_privacy) = parse_addr_with_privacy_prefix(&addr)?;
match addr_privacy {
AddressPrivacyKind::Public => {
let res = wallet_core
.register_account_under_authenticated_transfers_programs(addr)
.await?;
println!("Results of tx send is {res:#?}");
let transfer_tx =
wallet_core.poll_native_token_transfer(res.tx_hash).await?;
println!("Transaction data is {transfer_tx:?}");
let path = wallet_core.store_persistent_accounts().await?;
println!("Stored persistent accounts at {path:#?}");
}
AddressPrivacyKind::Private => {
let (res, [secret]) = wallet_core
.register_account_under_authenticated_transfers_programs_private(addr)
.await?;
println!("Results of tx send is {res:#?}");
let tx_hash = res.tx_hash;
let transfer_tx = wallet_core
.poll_native_token_transfer(tx_hash.clone())
.await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![(secret, addr)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
tx,
&acc_decode_data,
)?;
}
let path = wallet_core.store_persistent_accounts().await?;
println!("Stored persistent accounts at {path:#?}");
}
}
Ok(SubcommandReturnValue::Empty)
}
AuthTransferSubcommand::Send {
from,
to,
to_npk,
to_ipk,
amount,
} => {
let underlying_subcommand = match (to, to_npk, to_ipk) {
(None, None, None) => {
anyhow::bail!(
"Provide either account address of receiver or their public keys"
);
}
(Some(_), Some(_), Some(_)) => {
anyhow::bail!(
"Provide only one variant: either account address of receiver or their public keys"
);
}
(_, Some(_), None) | (_, None, Some(_)) => {
anyhow::bail!("List of public keys is uncomplete");
}
(Some(to), None, None) => {
let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?;
let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?;
match (from_privacy, to_privacy) {
(AddressPrivacyKind::Public, AddressPrivacyKind::Public) => {
NativeTokenTransferProgramSubcommand::Public {
from: from.to_string(),
to: to.to_string(),
amount,
}
}
(AddressPrivacyKind::Private, AddressPrivacyKind::Private) => {
NativeTokenTransferProgramSubcommand::Private(
NativeTokenTransferProgramSubcommandPrivate::PrivateOwned {
from: from.to_string(),
to: to.to_string(),
amount,
},
)
}
(AddressPrivacyKind::Private, AddressPrivacyKind::Public) => {
NativeTokenTransferProgramSubcommand::Deshielded {
from: from.to_string(),
to: to.to_string(),
amount,
}
}
(AddressPrivacyKind::Public, AddressPrivacyKind::Private) => {
NativeTokenTransferProgramSubcommand::Shielded(
NativeTokenTransferProgramSubcommandShielded::ShieldedOwned {
from: from.to_string(),
to: to.to_string(),
amount,
},
)
}
}
}
(None, Some(to_npk), Some(to_ipk)) => {
let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?;
match from_privacy {
AddressPrivacyKind::Private => {
NativeTokenTransferProgramSubcommand::Private(
NativeTokenTransferProgramSubcommandPrivate::PrivateForeign {
from: from.to_string(),
to_npk,
to_ipk,
amount,
},
)
}
AddressPrivacyKind::Public => {
NativeTokenTransferProgramSubcommand::Shielded(
NativeTokenTransferProgramSubcommandShielded::ShieldedForeign {
from: from.to_string(),
to_npk,
to_ipk,
amount,
},
)
}
}
}
};
underlying_subcommand.handle_subcommand(wallet_core).await
}
}
}
}
///Represents generic CLI subcommand for a wallet working with native token transfer program
#[derive(Subcommand, Debug, Clone)]

View File

@ -3,7 +3,187 @@ use clap::Subcommand;
use common::transaction::NSSATransaction;
use nssa::Address;
use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand};
use crate::{
SubcommandReturnValue, WalletCore,
cli::WalletSubcommand,
helperfunctions::{AddressPrivacyKind, parse_addr_with_privacy_prefix},
};
///Represents generic CLI subcommand for a wallet working with token program
#[derive(Subcommand, Debug, Clone)]
pub enum TokenProgramAgnosticSubcommand {
New {
///addr - valid 32 byte base58 string
#[arg(long)]
definition_addr: String,
///addr - valid 32 byte base58 string
#[arg(long)]
supply_addr: String,
#[arg(short, long)]
name: String,
#[arg(short, long)]
total_supply: u128,
},
Send {
///from - valid 32 byte base58 string
#[arg(long)]
from: String,
///to - valid 32 byte base58 string
#[arg(long)]
to: Option<String>,
///to_npk - valid 32 byte hex string
#[arg(long)]
to_npk: Option<String>,
///to_ipk - valid 33 byte hex string
#[arg(long)]
to_ipk: Option<String>,
///amount - amount of balance to move
#[arg(long)]
amount: u128,
},
}
impl WalletSubcommand for TokenProgramAgnosticSubcommand {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
TokenProgramAgnosticSubcommand::New {
definition_addr,
supply_addr,
name,
total_supply,
} => {
let (definition_addr, definition_addr_privacy) =
parse_addr_with_privacy_prefix(&definition_addr)?;
let (supply_addr, supply_addr_privacy) =
parse_addr_with_privacy_prefix(&supply_addr)?;
let underlying_subcommand = match (definition_addr_privacy, supply_addr_privacy) {
(AddressPrivacyKind::Public, AddressPrivacyKind::Public) => {
TokenProgramSubcommand::Public(
TokenProgramSubcommandPublic::CreateNewToken {
definition_addr: definition_addr.to_string(),
supply_addr: supply_addr.to_string(),
name,
total_supply,
},
)
}
(AddressPrivacyKind::Public, AddressPrivacyKind::Private) => {
TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned {
definition_addr: definition_addr.to_string(),
supply_addr: supply_addr.to_string(),
name,
total_supply,
},
)
}
(AddressPrivacyKind::Private, AddressPrivacyKind::Private) => {
todo!();
}
(AddressPrivacyKind::Private, AddressPrivacyKind::Public) => {
todo!();
}
};
underlying_subcommand.handle_subcommand(wallet_core).await
}
TokenProgramAgnosticSubcommand::Send {
from,
to,
to_npk,
to_ipk,
amount,
} => {
let underlying_subcommand = match (to, to_npk, to_ipk) {
(None, None, None) => {
anyhow::bail!(
"Provide either account address of receiver or their public keys"
);
}
(Some(_), Some(_), Some(_)) => {
anyhow::bail!(
"Provide only one variant: either account address of receiver or their public keys"
);
}
(_, Some(_), None) | (_, None, Some(_)) => {
anyhow::bail!("List of public keys is uncomplete");
}
(Some(to), None, None) => {
let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?;
let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?;
match (from_privacy, to_privacy) {
(AddressPrivacyKind::Public, AddressPrivacyKind::Public) => {
TokenProgramSubcommand::Public(
TokenProgramSubcommandPublic::TransferToken {
sender_addr: from.to_string(),
recipient_addr: to.to_string(),
balance_to_move: amount,
},
)
}
(AddressPrivacyKind::Private, AddressPrivacyKind::Private) => {
TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::TransferTokenPrivateOwned {
sender_addr: from.to_string(),
recipient_addr: to.to_string(),
balance_to_move: amount,
},
)
}
(AddressPrivacyKind::Private, AddressPrivacyKind::Public) => {
TokenProgramSubcommand::Deshielded(
TokenProgramSubcommandDeshielded::TransferTokenDeshielded {
sender_addr: from.to_string(),
recipient_addr: to.to_string(),
balance_to_move: amount,
},
)
}
(AddressPrivacyKind::Public, AddressPrivacyKind::Private) => {
TokenProgramSubcommand::Shielded(
TokenProgramSubcommandShielded::TransferTokenShieldedOwned {
sender_addr: from.to_string(),
recipient_addr: to.to_string(),
balance_to_move: amount,
},
)
}
}
}
(None, Some(to_npk), Some(to_ipk)) => {
let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?;
match from_privacy {
AddressPrivacyKind::Private => TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::TransferTokenPrivateForeign {
sender_addr: from.to_string(),
recipient_npk: to_npk,
recipient_ipk: to_ipk,
balance_to_move: amount,
},
),
AddressPrivacyKind::Public => TokenProgramSubcommand::Shielded(
TokenProgramSubcommandShielded::TransferTokenShieldedForeign {
sender_addr: from.to_string(),
recipient_npk: to_npk,
recipient_ipk: to_ipk,
balance_to_move: amount,
},
),
}
}
};
underlying_subcommand.handle_subcommand(wallet_core).await
}
}
}
}
///Represents generic CLI subcommand for a wallet working with token_program
#[derive(Subcommand, Debug, Clone)]

View File

@ -22,11 +22,10 @@ use tokio::io::AsyncWriteExt;
use crate::cli::{
WalletSubcommand, account::AccountSubcommand, chain::ChainSubcommand,
native_token_transfer_program::NativeTokenTransferProgramSubcommand,
pinata_program::PinataProgramSubcommand,
native_token_transfer_program::AuthTransferSubcommand, pinata_program::PinataProgramSubcommand,
token_program::TokenProgramAgnosticSubcommand,
};
use crate::{
cli::token_program::TokenProgramSubcommand,
helperfunctions::{
fetch_config, fetch_persistent_accounts, get_home, produce_data_for_storage,
},
@ -193,7 +192,7 @@ impl WalletCore {
pub enum Command {
///Transfer command
#[command(subcommand)]
AuthTransfer(NativeTokenTransferProgramSubcommand),
AuthTransfer(AuthTransferSubcommand),
///Chain command
#[command(subcommand)]
ChainInfo(ChainSubcommand),
@ -205,7 +204,7 @@ pub enum Command {
Pinata(PinataProgramSubcommand),
///Token command
#[command(subcommand)]
Token(TokenProgramSubcommand),
Token(TokenProgramAgnosticSubcommand),
AuthenticatedTransferInitializePublicAccount {},
// Check the wallet can connect to the node and builtin local programs
// match the remote versions

View File

@ -537,4 +537,53 @@ impl WalletCore {
Ok(self.sequencer_client.send_tx_private(tx).await?)
}
pub async fn register_account_under_authenticated_transfers_programs_private(
&self,
from: Address,
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
let AccountPreparedData {
nsk: _,
npk: from_npk,
ipk: from_ipk,
auth_acc: sender_pre,
proof: _,
} = self.private_acc_preparation(from, false, false).await?;
let eph_holder_from = EphemeralKeyHolder::new(&from_npk);
let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk);
let instruction: u128 = 0;
let (output, proof) = circuit::execute_and_prove(
&[sender_pre],
&Program::serialize_instruction(instruction).unwrap(),
&[2],
&produce_random_nonces(1),
&[(from_npk.clone(), shared_secret_from.clone())],
&[],
&Program::authenticated_transfer_program(),
)
.unwrap();
let message = Message::try_from_circuit_output(
vec![],
vec![],
vec![(
from_npk.clone(),
from_ipk.clone(),
eph_holder_from.generate_ephemeral_public_key(),
)],
output,
)
.unwrap();
let witness_set = WitnessSet::for_message(&message, proof, &[]);
let tx = PrivacyPreservingTransaction::new(message, witness_set);
Ok((
self.sequencer_client.send_tx_private(tx).await?,
[shared_secret_from],
))
}
}