mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-02 13:23:10 +00:00
1614 lines
57 KiB
Rust
1614 lines
57 KiB
Rust
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
|
use std::{path::PathBuf, time::Duration};
|
|
|
|
use actix_web::dev::ServerHandle;
|
|
use anyhow::Result;
|
|
use clap::Parser;
|
|
use common::{
|
|
sequencer_client::SequencerClient,
|
|
transaction::{EncodedTransaction, NSSATransaction},
|
|
};
|
|
use log::{info, warn};
|
|
use nssa::{Address, PrivacyPreservingTransaction, program::Program};
|
|
use nssa_core::{
|
|
Commitment, NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point,
|
|
};
|
|
use sequencer_core::config::SequencerConfig;
|
|
use sequencer_runner::startup_sequencer;
|
|
use tempfile::TempDir;
|
|
use tokio::task::JoinHandle;
|
|
use wallet::{
|
|
Command, SubcommandReturnValue, WalletCore,
|
|
cli::token_program::{
|
|
TokenProgramSubcommand, TokenProgramSubcommandDeshielded, TokenProgramSubcommandPrivate,
|
|
TokenProgramSubcommandPublic, TokenProgramSubcommandShielded,
|
|
},
|
|
config::PersistentAccountData,
|
|
helperfunctions::{fetch_config, fetch_persistent_accounts},
|
|
};
|
|
|
|
#[derive(Parser, Debug)]
|
|
#[clap(version)]
|
|
struct Args {
|
|
/// Path to configs
|
|
home_dir: PathBuf,
|
|
/// Test name
|
|
test_name: String,
|
|
}
|
|
|
|
pub const ACC_SENDER: &str = "0eee24287296ba55278f1e5403be014754866366388730303c2889be17ada065";
|
|
pub const ACC_RECEIVER: &str = "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2";
|
|
|
|
pub const ACC_SENDER_PRIVATE: &str =
|
|
"9cb6b0035320266e430eac9d96745769e7efcf30d2b9cc21ff000b3f873dc2a8";
|
|
pub const ACC_RECEIVER_PRIVATE: &str =
|
|
"a55f4f98d2f265c91d8a9868564242d8070b9bf7180a29363f52eb76988636fd";
|
|
|
|
pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12;
|
|
|
|
#[allow(clippy::type_complexity)]
|
|
pub async fn pre_test(
|
|
home_dir: PathBuf,
|
|
) -> Result<(ServerHandle, JoinHandle<Result<()>>, TempDir)> {
|
|
let home_dir_sequencer = home_dir.join("sequencer");
|
|
|
|
let mut sequencer_config =
|
|
sequencer_runner::config::from_file(home_dir_sequencer.join("sequencer_config.json"))
|
|
.unwrap();
|
|
|
|
let temp_dir_sequencer = replace_home_dir_with_temp_dir_in_configs(&mut sequencer_config);
|
|
|
|
let (seq_http_server_handle, sequencer_loop_handle) =
|
|
startup_sequencer(sequencer_config).await?;
|
|
|
|
Ok((
|
|
seq_http_server_handle,
|
|
sequencer_loop_handle,
|
|
temp_dir_sequencer,
|
|
))
|
|
}
|
|
|
|
pub fn replace_home_dir_with_temp_dir_in_configs(
|
|
sequencer_config: &mut SequencerConfig,
|
|
) -> TempDir {
|
|
let temp_dir_sequencer = tempfile::tempdir().unwrap();
|
|
|
|
sequencer_config.home = temp_dir_sequencer.path().to_path_buf();
|
|
|
|
temp_dir_sequencer
|
|
}
|
|
|
|
#[allow(clippy::type_complexity)]
|
|
pub async fn post_test(residual: (ServerHandle, JoinHandle<Result<()>>, TempDir)) {
|
|
let (seq_http_server_handle, sequencer_loop_handle, _) = residual;
|
|
|
|
info!("Cleanup");
|
|
|
|
sequencer_loop_handle.abort();
|
|
seq_http_server_handle.stop(true).await;
|
|
|
|
let wallet_home = wallet::helperfunctions::get_home().unwrap();
|
|
let persistent_data_home = wallet_home.join("curr_accounts.json");
|
|
|
|
//Removing persistent accounts after run to not affect other executions
|
|
//Not necessary an error, if fails as there is tests for failure scenario
|
|
let _ = std::fs::remove_file(persistent_data_home)
|
|
.inspect_err(|err| warn!("Failed to remove persistent data with err {err:#?}"));
|
|
|
|
//At this point all of the references to sequencer_core must be lost.
|
|
//So they are dropped and tempdirs will be dropped too,
|
|
}
|
|
|
|
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 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 balance move");
|
|
let acc_1_balance = seq_client
|
|
.get_account_balance(ACC_SENDER.to_string())
|
|
.await
|
|
.unwrap();
|
|
let acc_2_balance = seq_client
|
|
.get_account_balance(ACC_RECEIVER.to_string())
|
|
.await
|
|
.unwrap();
|
|
|
|
info!("Balance of sender : {acc_1_balance:#?}");
|
|
info!("Balance of receiver : {acc_2_balance:#?}");
|
|
|
|
assert_eq!(acc_1_balance.balance, 9900);
|
|
assert_eq!(acc_2_balance.balance, 20100);
|
|
|
|
info!("Success!");
|
|
}
|
|
|
|
pub async fn test_success_move_to_another_account() {
|
|
info!("test_success_move_to_another_account");
|
|
let command = Command::RegisterAccountPublic {};
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
|
|
wallet::execute_subcommand(command).await.unwrap();
|
|
|
|
let persistent_accounts = fetch_persistent_accounts().unwrap();
|
|
|
|
let mut new_persistent_account_addr = String::new();
|
|
|
|
for per_acc in persistent_accounts {
|
|
if (per_acc.address().to_string() != ACC_RECEIVER)
|
|
&& (per_acc.address().to_string() != ACC_SENDER)
|
|
{
|
|
new_persistent_account_addr = per_acc.address().to_string();
|
|
}
|
|
}
|
|
|
|
if new_persistent_account_addr == String::new() {
|
|
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,
|
|
};
|
|
|
|
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 balance move");
|
|
let acc_1_balance = seq_client
|
|
.get_account_balance(ACC_SENDER.to_string())
|
|
.await
|
|
.unwrap();
|
|
let acc_2_balance = seq_client
|
|
.get_account_balance(new_persistent_account_addr)
|
|
.await
|
|
.unwrap();
|
|
|
|
info!("Balance of sender : {acc_1_balance:#?}");
|
|
info!("Balance of receiver : {acc_2_balance:#?}");
|
|
|
|
assert_eq!(acc_1_balance.balance, 9900);
|
|
assert_eq!(acc_2_balance.balance, 100);
|
|
|
|
info!("Success!");
|
|
}
|
|
|
|
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 wallet_config = fetch_config().unwrap();
|
|
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
|
|
let failed_send = wallet::execute_subcommand(command).await;
|
|
|
|
assert!(failed_send.is_err());
|
|
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
info!("Checking correct balance move");
|
|
let acc_1_balance = seq_client
|
|
.get_account_balance(ACC_SENDER.to_string())
|
|
.await
|
|
.unwrap();
|
|
let acc_2_balance = seq_client
|
|
.get_account_balance(ACC_RECEIVER.to_string())
|
|
.await
|
|
.unwrap();
|
|
|
|
info!("Balance of sender : {acc_1_balance:#?}");
|
|
info!("Balance of receiver : {acc_2_balance:#?}");
|
|
|
|
assert_eq!(acc_1_balance.balance, 10000);
|
|
assert_eq!(acc_2_balance.balance, 20000);
|
|
|
|
info!("Success!");
|
|
}
|
|
|
|
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 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 balance move");
|
|
let acc_1_balance = seq_client
|
|
.get_account_balance(ACC_SENDER.to_string())
|
|
.await
|
|
.unwrap();
|
|
let acc_2_balance = seq_client
|
|
.get_account_balance(ACC_RECEIVER.to_string())
|
|
.await
|
|
.unwrap();
|
|
|
|
info!("Balance of sender : {acc_1_balance:#?}");
|
|
info!("Balance of receiver : {acc_2_balance:#?}");
|
|
|
|
assert_eq!(acc_1_balance.balance, 9900);
|
|
assert_eq!(acc_2_balance.balance, 20100);
|
|
|
|
info!("First TX Success!");
|
|
|
|
let command = Command::SendNativeTokenTransferPublic {
|
|
from: ACC_SENDER.to_string(),
|
|
to: ACC_RECEIVER.to_string(),
|
|
amount: 100,
|
|
};
|
|
|
|
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 balance move");
|
|
let acc_1_balance = seq_client
|
|
.get_account_balance(ACC_SENDER.to_string())
|
|
.await
|
|
.unwrap();
|
|
let acc_2_balance = seq_client
|
|
.get_account_balance(ACC_RECEIVER.to_string())
|
|
.await
|
|
.unwrap();
|
|
|
|
info!("Balance of sender : {acc_1_balance:#?}");
|
|
info!("Balance of receiver : {acc_2_balance:#?}");
|
|
|
|
assert_eq!(acc_1_balance.balance, 9800);
|
|
assert_eq!(acc_2_balance.balance, 20200);
|
|
|
|
info!("Second TX Success!");
|
|
}
|
|
|
|
pub async fn test_get_account() {
|
|
info!("test_get_account");
|
|
let wallet_config = fetch_config().unwrap();
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
|
|
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);
|
|
}
|
|
|
|
/// This test creates a new token using the token program. After creating the token, the test executes a
|
|
/// token transfer to a new account.
|
|
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();
|
|
// Create new account for the token supply holder
|
|
wallet::execute_subcommand(Command::RegisterAccountPublic {})
|
|
.await
|
|
.unwrap();
|
|
// Create new account for receiving a token transaction
|
|
wallet::execute_subcommand(Command::RegisterAccountPublic {})
|
|
.await
|
|
.unwrap();
|
|
|
|
let persistent_accounts = fetch_persistent_accounts().unwrap();
|
|
|
|
let mut new_persistent_accounts_addr = Vec::new();
|
|
|
|
for per_acc in persistent_accounts {
|
|
match per_acc {
|
|
PersistentAccountData::Public(per_acc) => {
|
|
if (per_acc.address.to_string() != ACC_RECEIVER)
|
|
&& (per_acc.address.to_string() != ACC_SENDER)
|
|
{
|
|
new_persistent_accounts_addr.push(per_acc.address);
|
|
}
|
|
}
|
|
_ => continue,
|
|
}
|
|
}
|
|
|
|
let [definition_addr, supply_addr, recipient_addr] = new_persistent_accounts_addr
|
|
.try_into()
|
|
.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,
|
|
});
|
|
wallet::execute_subcommand(Command::TokenProgram(subcommand))
|
|
.await
|
|
.unwrap();
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
|
|
// Check the status of the token definition account is the expected after the execution
|
|
let definition_acc = seq_client
|
|
.get_account(definition_addr.to_string())
|
|
.await
|
|
.unwrap()
|
|
.account;
|
|
|
|
assert_eq!(definition_acc.program_owner, Program::token().id());
|
|
// The data of a token definition account has the following layout:
|
|
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ]
|
|
assert_eq!(
|
|
definition_acc.data,
|
|
vec![
|
|
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
]
|
|
);
|
|
|
|
// Check the status of the token holding account with the total supply is the expected after the execution
|
|
let supply_acc = seq_client
|
|
.get_account(supply_addr.to_string())
|
|
.await
|
|
.unwrap()
|
|
.account;
|
|
|
|
// The account must be owned by the token program
|
|
assert_eq!(supply_acc.program_owner, Program::token().id());
|
|
// The data of a token definition account has the following layout:
|
|
// [ 0x01 || corresponding_token_definition_id (32 bytes) || balance (little endian 16 bytes) ]
|
|
// First byte of the data equal to 1 means it's a token holding account
|
|
assert_eq!(supply_acc.data[0], 1);
|
|
// Bytes from 1 to 33 represent the id of the token this account is associated with.
|
|
// In this example, this is a token account of the newly created token, so it is expected
|
|
// to be equal to the address of the token definition account.
|
|
assert_eq!(&supply_acc.data[1..33], definition_addr.to_bytes());
|
|
assert_eq!(
|
|
u128::from_le_bytes(supply_acc.data[33..].try_into().unwrap()),
|
|
37
|
|
);
|
|
|
|
// 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,
|
|
});
|
|
wallet::execute_subcommand(Command::TokenProgram(subcommand))
|
|
.await
|
|
.unwrap();
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
// Check the status of the account at `supply_addr` is the expected after the execution
|
|
let supply_acc = seq_client
|
|
.get_account(supply_addr.to_string())
|
|
.await
|
|
.unwrap()
|
|
.account;
|
|
// The account must be owned by the token program
|
|
assert_eq!(supply_acc.program_owner, Program::token().id());
|
|
// First byte equal to 1 means it's a token holding account
|
|
assert_eq!(supply_acc.data[0], 1);
|
|
// Bytes from 1 to 33 represent the id of the token this account is associated with.
|
|
assert_eq!(&supply_acc.data[1..33], definition_addr.to_bytes());
|
|
assert_eq!(
|
|
u128::from_le_bytes(supply_acc.data[33..].try_into().unwrap()),
|
|
30
|
|
);
|
|
|
|
// Check the status of the account at `recipient_addr` is the expected after the execution
|
|
let recipient_acc = seq_client
|
|
.get_account(recipient_addr.to_string())
|
|
.await
|
|
.unwrap()
|
|
.account;
|
|
|
|
// The account must be owned by the token program
|
|
assert_eq!(recipient_acc.program_owner, Program::token().id());
|
|
// First byte equal to 1 means it's a token holding account
|
|
assert_eq!(recipient_acc.data[0], 1);
|
|
// Bytes from 1 to 33 represent the id of the token this account is associated with.
|
|
assert_eq!(&recipient_acc.data[1..33], definition_addr.to_bytes());
|
|
assert_eq!(
|
|
u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()),
|
|
7
|
|
);
|
|
}
|
|
|
|
/// This test creates a new private token using the token program. After creating the token, the test executes a
|
|
/// private token transfer to a new account. All accounts are owned except definition.
|
|
pub async fn test_success_token_program_private_owned() {
|
|
let wallet_config = fetch_config().unwrap();
|
|
|
|
// Create new account for the token definition (public)
|
|
let SubcommandReturnValue::RegisterAccount {
|
|
addr: definition_addr,
|
|
} = wallet::execute_subcommand(Command::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()
|
|
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()
|
|
else {
|
|
panic!("invalid subcommand return value");
|
|
};
|
|
|
|
// 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,
|
|
},
|
|
);
|
|
|
|
wallet::execute_subcommand(Command::TokenProgram(subcommand))
|
|
.await
|
|
.unwrap();
|
|
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
|
|
// Check the status of the token definition account is the expected after the execution
|
|
let definition_acc = seq_client
|
|
.get_account(definition_addr.to_string())
|
|
.await
|
|
.unwrap()
|
|
.account;
|
|
|
|
assert_eq!(definition_acc.program_owner, Program::token().id());
|
|
// The data of a token definition account has the following layout:
|
|
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ]
|
|
assert_eq!(
|
|
definition_acc.data,
|
|
vec![
|
|
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
]
|
|
);
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let new_commitment1 = wallet_storage
|
|
.get_private_account_commitment(&supply_addr)
|
|
.unwrap();
|
|
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,
|
|
});
|
|
|
|
wallet::execute_subcommand(Command::TokenProgram(subcommand))
|
|
.await
|
|
.unwrap();
|
|
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let new_commitment1 = wallet_storage
|
|
.get_private_account_commitment(&supply_addr)
|
|
.unwrap();
|
|
assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await);
|
|
|
|
let new_commitment2 = wallet_storage
|
|
.get_private_account_commitment(&recipient_addr)
|
|
.unwrap();
|
|
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,
|
|
});
|
|
|
|
wallet::execute_subcommand(Command::TokenProgram(subcommand))
|
|
.await
|
|
.unwrap();
|
|
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let new_commitment1 = wallet_storage
|
|
.get_private_account_commitment(&supply_addr)
|
|
.unwrap();
|
|
assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await);
|
|
|
|
let new_commitment2 = wallet_storage
|
|
.get_private_account_commitment(&recipient_addr)
|
|
.unwrap();
|
|
assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await);
|
|
}
|
|
|
|
/// This test creates a new private token using the token program. After creating the token, the test executes a
|
|
/// private token transfer to a new account.
|
|
pub async fn test_success_token_program_private_claiming_path() {
|
|
let wallet_config = fetch_config().unwrap();
|
|
|
|
// Create new account for the token definition (public)
|
|
let SubcommandReturnValue::RegisterAccount {
|
|
addr: definition_addr,
|
|
} = wallet::execute_subcommand(Command::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()
|
|
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()
|
|
else {
|
|
panic!("invalid subcommand return value");
|
|
};
|
|
|
|
// 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,
|
|
},
|
|
);
|
|
|
|
wallet::execute_subcommand(Command::TokenProgram(subcommand))
|
|
.await
|
|
.unwrap();
|
|
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
|
|
// Check the status of the token definition account is the expected after the execution
|
|
let definition_acc = seq_client
|
|
.get_account(definition_addr.to_string())
|
|
.await
|
|
.unwrap()
|
|
.account;
|
|
|
|
assert_eq!(definition_acc.program_owner, Program::token().id());
|
|
// The data of a token definition account has the following layout:
|
|
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ]
|
|
assert_eq!(
|
|
definition_acc.data,
|
|
vec![
|
|
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
]
|
|
);
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let new_commitment1 = wallet_storage
|
|
.get_private_account_commitment(&supply_addr)
|
|
.unwrap();
|
|
assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await);
|
|
|
|
let (recipient_keys, _) = wallet_storage
|
|
.storage
|
|
.user_data
|
|
.get_private_account(&recipient_addr)
|
|
.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 SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } =
|
|
wallet::execute_subcommand(Command::TokenProgram(subcommand))
|
|
.await
|
|
.unwrap()
|
|
else {
|
|
panic!("invalid subcommand return value");
|
|
};
|
|
|
|
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,
|
|
};
|
|
|
|
wallet::execute_subcommand(command).await.unwrap();
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let new_commitment1 = wallet_storage
|
|
.get_private_account_commitment(&supply_addr)
|
|
.unwrap();
|
|
assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await);
|
|
|
|
let new_commitment2 = wallet_storage
|
|
.get_private_account_commitment(&recipient_addr)
|
|
.unwrap();
|
|
assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await);
|
|
}
|
|
|
|
/// This test creates a new public token using the token program. After creating the token, the test executes a
|
|
/// shielded token transfer to a new account. All accounts are owned except definition.
|
|
pub async fn test_success_token_program_shielded_owned() {
|
|
let wallet_config = fetch_config().unwrap();
|
|
|
|
// Create new account for the token definition (public)
|
|
let SubcommandReturnValue::RegisterAccount {
|
|
addr: definition_addr,
|
|
} = wallet::execute_subcommand(Command::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::RegisterAccountPublic {})
|
|
.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()
|
|
else {
|
|
panic!("invalid subcommand return value");
|
|
};
|
|
|
|
// 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,
|
|
});
|
|
|
|
wallet::execute_subcommand(Command::TokenProgram(subcommand))
|
|
.await
|
|
.unwrap();
|
|
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
|
|
// Check the status of the token definition account is the expected after the execution
|
|
let definition_acc = seq_client
|
|
.get_account(definition_addr.to_string())
|
|
.await
|
|
.unwrap()
|
|
.account;
|
|
|
|
assert_eq!(definition_acc.program_owner, Program::token().id());
|
|
// The data of a token definition account has the following layout:
|
|
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ]
|
|
assert_eq!(
|
|
definition_acc.data,
|
|
vec![
|
|
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
]
|
|
);
|
|
|
|
// 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,
|
|
},
|
|
);
|
|
|
|
wallet::execute_subcommand(Command::TokenProgram(subcommand))
|
|
.await
|
|
.unwrap();
|
|
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let new_commitment2 = wallet_storage
|
|
.get_private_account_commitment(&recipient_addr)
|
|
.unwrap();
|
|
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,
|
|
},
|
|
);
|
|
|
|
wallet::execute_subcommand(Command::TokenProgram(subcommand))
|
|
.await
|
|
.unwrap();
|
|
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let new_commitment2 = wallet_storage
|
|
.get_private_account_commitment(&recipient_addr)
|
|
.unwrap();
|
|
assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await);
|
|
}
|
|
|
|
/// This test creates a new private token using the token program. After creating the token, the test executes a
|
|
/// deshielded token transfer to a new account. All accounts are owned except definition.
|
|
pub async fn test_success_token_program_deshielded_owned() {
|
|
let wallet_config = fetch_config().unwrap();
|
|
|
|
// Create new account for the token definition (public)
|
|
let SubcommandReturnValue::RegisterAccount {
|
|
addr: definition_addr,
|
|
} = wallet::execute_subcommand(Command::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()
|
|
else {
|
|
panic!("invalid subcommand return value");
|
|
};
|
|
// Create new account for receiving a token transaction
|
|
let SubcommandReturnValue::RegisterAccount {
|
|
addr: recipient_addr,
|
|
} = wallet::execute_subcommand(Command::RegisterAccountPublic {})
|
|
.await
|
|
.unwrap()
|
|
else {
|
|
panic!("invalid subcommand return value");
|
|
};
|
|
|
|
// 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,
|
|
},
|
|
);
|
|
|
|
wallet::execute_subcommand(Command::TokenProgram(subcommand))
|
|
.await
|
|
.unwrap();
|
|
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
|
|
// Check the status of the token definition account is the expected after the execution
|
|
let definition_acc = seq_client
|
|
.get_account(definition_addr.to_string())
|
|
.await
|
|
.unwrap()
|
|
.account;
|
|
|
|
assert_eq!(definition_acc.program_owner, Program::token().id());
|
|
// The data of a token definition account has the following layout:
|
|
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ]
|
|
assert_eq!(
|
|
definition_acc.data,
|
|
vec![
|
|
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
]
|
|
);
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let new_commitment1 = wallet_storage
|
|
.get_private_account_commitment(&supply_addr)
|
|
.unwrap();
|
|
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,
|
|
},
|
|
);
|
|
|
|
wallet::execute_subcommand(Command::TokenProgram(subcommand))
|
|
.await
|
|
.unwrap();
|
|
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let new_commitment1 = wallet_storage
|
|
.get_private_account_commitment(&supply_addr)
|
|
.unwrap();
|
|
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,
|
|
},
|
|
);
|
|
|
|
wallet::execute_subcommand(Command::TokenProgram(subcommand))
|
|
.await
|
|
.unwrap();
|
|
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let new_commitment1 = wallet_storage
|
|
.get_private_account_commitment(&supply_addr)
|
|
.unwrap();
|
|
assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await);
|
|
}
|
|
|
|
pub async fn test_success_private_transfer_to_another_owned_account() {
|
|
info!("test_success_private_transfer_to_another_owned_account");
|
|
let from: Address = ACC_SENDER_PRIVATE.parse().unwrap();
|
|
let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap();
|
|
|
|
let command = Command::SendNativeTokenTransferPrivateOwnedAccount {
|
|
from: from.to_string(),
|
|
to: to.to_string(),
|
|
amount: 100,
|
|
};
|
|
|
|
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;
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let new_commitment1 = wallet_storage
|
|
.get_private_account_commitment(&from)
|
|
.unwrap();
|
|
assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await);
|
|
|
|
let new_commitment2 = wallet_storage.get_private_account_commitment(&to).unwrap();
|
|
assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await);
|
|
|
|
info!("Success!");
|
|
}
|
|
|
|
pub async fn test_success_private_transfer_to_another_foreign_account() {
|
|
info!("test_success_private_transfer_to_another_foreign_account");
|
|
let from: Address = ACC_SENDER_PRIVATE.parse().unwrap();
|
|
let to_npk = NullifierPublicKey([42; 32]);
|
|
let to_npk_string = hex::encode(to_npk.0);
|
|
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 SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } =
|
|
wallet::execute_subcommand(command).await.unwrap()
|
|
else {
|
|
panic!("invalid subcommand return value");
|
|
};
|
|
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let new_commitment1 = wallet_storage
|
|
.get_private_account_commitment(&from)
|
|
.unwrap();
|
|
|
|
let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await;
|
|
assert_eq!(tx.message.new_commitments[0], new_commitment1);
|
|
|
|
assert_eq!(tx.message.new_commitments.len(), 2);
|
|
for commitment in tx.message.new_commitments.into_iter() {
|
|
assert!(verify_commitment_is_in_state(commitment, &seq_client).await);
|
|
}
|
|
|
|
info!("Success!");
|
|
}
|
|
|
|
pub async fn test_success_private_transfer_to_another_owned_account_claiming_path() {
|
|
info!("test_success_private_transfer_to_another_owned_account_claiming_path");
|
|
let from: Address = ACC_SENDER_PRIVATE.parse().unwrap();
|
|
|
|
let command = Command::RegisterAccountPrivate {};
|
|
|
|
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
|
|
let SubcommandReturnValue::RegisterAccount { addr: to_addr } = sub_ret else {
|
|
panic!("FAILED TO REGISTER ACCOUNT");
|
|
};
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config.clone()).unwrap();
|
|
|
|
let (to_keys, _) = wallet_storage
|
|
.storage
|
|
.user_data
|
|
.user_private_accounts
|
|
.get(&to_addr)
|
|
.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 sub_ret = wallet::execute_subcommand(command).await.unwrap();
|
|
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else {
|
|
panic!("FAILED TO SEND TX");
|
|
};
|
|
|
|
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,
|
|
};
|
|
wallet::execute_subcommand(command).await.unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let new_commitment1 = wallet_storage
|
|
.get_private_account_commitment(&from)
|
|
.unwrap();
|
|
assert_eq!(tx.message.new_commitments[0], new_commitment1);
|
|
|
|
assert_eq!(tx.message.new_commitments.len(), 2);
|
|
for commitment in tx.message.new_commitments.into_iter() {
|
|
assert!(verify_commitment_is_in_state(commitment, &seq_client).await);
|
|
}
|
|
|
|
let to_res_acc = wallet_storage.get_account_private(&to_addr).unwrap();
|
|
|
|
assert_eq!(to_res_acc.balance, 100);
|
|
|
|
info!("Success!");
|
|
}
|
|
|
|
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 wallet_config = fetch_config().unwrap();
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config.clone()).unwrap();
|
|
|
|
let from_acc = wallet_storage.get_account_private(&from).unwrap();
|
|
assert_eq!(from_acc.balance, 10000);
|
|
|
|
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;
|
|
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let from_acc = wallet_storage.get_account_private(&from).unwrap();
|
|
let new_commitment = wallet_storage
|
|
.get_private_account_commitment(&from)
|
|
.unwrap();
|
|
assert!(verify_commitment_is_in_state(new_commitment, &seq_client).await);
|
|
|
|
let acc_2_balance = seq_client
|
|
.get_account_balance(to.to_string())
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(from_acc.balance, 10000 - 100);
|
|
assert_eq!(acc_2_balance.balance, 20100);
|
|
|
|
info!("Success!");
|
|
}
|
|
|
|
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 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;
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let acc_to = wallet_storage.get_account_private(&to).unwrap();
|
|
let new_commitment = wallet_storage.get_private_account_commitment(&to).unwrap();
|
|
assert!(verify_commitment_is_in_state(new_commitment, &seq_client).await);
|
|
|
|
let acc_from_balance = seq_client
|
|
.get_account_balance(from.to_string())
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(acc_from_balance.balance, 9900);
|
|
assert_eq!(acc_to.balance, 20000 + 100);
|
|
|
|
info!("Success!");
|
|
}
|
|
|
|
pub async fn test_success_shielded_transfer_to_another_foreign_account() {
|
|
info!("test_success_shielded_transfer_to_another_foreign_account");
|
|
let to_npk = NullifierPublicKey([42; 32]);
|
|
let to_npk_string = hex::encode(to_npk.0);
|
|
let to_ipk = Secp256k1Point::from_scalar(to_npk.0);
|
|
let from: Address = ACC_SENDER.parse().unwrap();
|
|
|
|
let command = Command::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();
|
|
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
|
|
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } =
|
|
wallet::execute_subcommand(command).await.unwrap()
|
|
else {
|
|
panic!("invalid subcommand return value");
|
|
};
|
|
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash).await;
|
|
|
|
let acc_1_balance = seq_client
|
|
.get_account_balance(from.to_string())
|
|
.await
|
|
.unwrap();
|
|
|
|
assert!(
|
|
verify_commitment_is_in_state(tx.message.new_commitments[0].clone(), &seq_client).await
|
|
);
|
|
|
|
assert_eq!(acc_1_balance.balance, 9900);
|
|
|
|
info!("Success!");
|
|
}
|
|
|
|
pub async fn test_pinata() {
|
|
info!("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 wallet_config = fetch_config().unwrap();
|
|
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
|
|
let pinata_balance_pre = seq_client
|
|
.get_account_balance(pinata_addr.clone())
|
|
.await
|
|
.unwrap()
|
|
.balance;
|
|
|
|
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 balance move");
|
|
let pinata_balance_post = seq_client
|
|
.get_account_balance(pinata_addr.clone())
|
|
.await
|
|
.unwrap()
|
|
.balance;
|
|
|
|
let winner_balance_post = seq_client
|
|
.get_account_balance(ACC_SENDER.to_string())
|
|
.await
|
|
.unwrap()
|
|
.balance;
|
|
|
|
assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize);
|
|
assert_eq!(winner_balance_post, 10000 + pinata_prize);
|
|
|
|
info!("Success!");
|
|
}
|
|
|
|
pub async fn test_authenticated_transfer_initialize_function() {
|
|
info!("test initialize account for authenticated transfer");
|
|
let command = Command::AuthenticatedTransferInitializePublicAccount {};
|
|
|
|
let SubcommandReturnValue::RegisterAccount { addr } =
|
|
wallet::execute_subcommand(command).await.unwrap()
|
|
else {
|
|
panic!("Error creating account");
|
|
};
|
|
|
|
info!("Checking correct execution");
|
|
let wallet_config = fetch_config().unwrap();
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
let account = seq_client
|
|
.get_account(addr.to_string())
|
|
.await
|
|
.unwrap()
|
|
.account;
|
|
|
|
let expected_program_owner = Program::authenticated_transfer_program().id();
|
|
let expected_nonce = 1;
|
|
let expected_balance = 0;
|
|
|
|
assert_eq!(account.program_owner, expected_program_owner);
|
|
assert_eq!(account.balance, expected_balance);
|
|
assert_eq!(account.nonce, expected_nonce);
|
|
assert!(account.data.is_empty());
|
|
info!("Success!");
|
|
}
|
|
|
|
pub async fn test_pinata_private_receiver() {
|
|
info!("test_pinata_private_receiver");
|
|
let pinata_addr = "cafe".repeat(16);
|
|
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 wallet_config = fetch_config().unwrap();
|
|
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
|
|
let pinata_balance_pre = seq_client
|
|
.get_account_balance(pinata_addr.clone())
|
|
.await
|
|
.unwrap()
|
|
.balance;
|
|
|
|
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } =
|
|
wallet::execute_subcommand(command).await.unwrap()
|
|
else {
|
|
panic!("invalid subcommand return value");
|
|
};
|
|
|
|
info!("Waiting for next block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
info!("Checking correct balance move");
|
|
let pinata_balance_post = seq_client
|
|
.get_account_balance(pinata_addr.clone())
|
|
.await
|
|
.unwrap()
|
|
.balance;
|
|
|
|
let command = Command::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();
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let new_commitment1 = wallet_storage
|
|
.get_private_account_commitment(&ACC_SENDER_PRIVATE.parse().unwrap())
|
|
.unwrap();
|
|
assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await);
|
|
|
|
assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize);
|
|
|
|
info!("Success!");
|
|
}
|
|
|
|
pub async fn test_pinata_private_receiver_new_account() {
|
|
info!("test_pinata_private_receiver");
|
|
let pinata_addr = "cafe".repeat(16);
|
|
let pinata_prize = 150;
|
|
let solution = 989106;
|
|
|
|
// Create new account for the token supply holder (private)
|
|
let SubcommandReturnValue::RegisterAccount { addr: winner_addr } =
|
|
wallet::execute_subcommand(Command::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 wallet_config = fetch_config().unwrap();
|
|
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
|
|
let pinata_balance_pre = seq_client
|
|
.get_account_balance(pinata_addr.clone())
|
|
.await
|
|
.unwrap()
|
|
.balance;
|
|
|
|
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 balance move");
|
|
let pinata_balance_post = seq_client
|
|
.get_account_balance(pinata_addr.clone())
|
|
.await
|
|
.unwrap()
|
|
.balance;
|
|
|
|
let wallet_config = fetch_config().unwrap();
|
|
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
|
|
|
let new_commitment1 = wallet_storage
|
|
.get_private_account_commitment(&winner_addr)
|
|
.unwrap();
|
|
assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await);
|
|
|
|
assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize);
|
|
|
|
info!("Success!");
|
|
}
|
|
|
|
macro_rules! test_cleanup_wrap {
|
|
($home_dir:ident, $test_func:ident) => {{
|
|
let res = pre_test($home_dir.clone()).await.unwrap();
|
|
|
|
info!("Waiting for first block creation");
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
$test_func().await;
|
|
|
|
post_test(res).await;
|
|
}};
|
|
}
|
|
|
|
pub async fn main_tests_runner() -> Result<()> {
|
|
env_logger::init();
|
|
|
|
let args = Args::parse();
|
|
let Args {
|
|
home_dir,
|
|
test_name,
|
|
} = args;
|
|
|
|
match test_name.as_str() {
|
|
"test_success_token_program" => {
|
|
test_cleanup_wrap!(home_dir, test_success_token_program);
|
|
}
|
|
"test_success_move_to_another_account" => {
|
|
test_cleanup_wrap!(home_dir, test_success_move_to_another_account);
|
|
}
|
|
"test_success" => {
|
|
test_cleanup_wrap!(home_dir, test_success);
|
|
}
|
|
"test_failure" => {
|
|
test_cleanup_wrap!(home_dir, test_failure);
|
|
}
|
|
"test_get_account" => {
|
|
test_cleanup_wrap!(home_dir, test_get_account);
|
|
}
|
|
"test_success_two_transactions" => {
|
|
test_cleanup_wrap!(home_dir, test_success_two_transactions);
|
|
}
|
|
"test_success_private_transfer_to_another_owned_account" => {
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_private_transfer_to_another_owned_account
|
|
);
|
|
}
|
|
"test_success_private_transfer_to_another_foreign_account" => {
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_private_transfer_to_another_foreign_account
|
|
);
|
|
}
|
|
"test_success_private_transfer_to_another_owned_account_claiming_path" => {
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_private_transfer_to_another_owned_account_claiming_path
|
|
);
|
|
}
|
|
"test_success_deshielded_transfer_to_another_account" => {
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_deshielded_transfer_to_another_account
|
|
);
|
|
}
|
|
"test_success_shielded_transfer_to_another_owned_account" => {
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_shielded_transfer_to_another_owned_account
|
|
);
|
|
}
|
|
"test_success_shielded_transfer_to_another_foreign_account" => {
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_shielded_transfer_to_another_foreign_account
|
|
);
|
|
}
|
|
"test_pinata" => {
|
|
test_cleanup_wrap!(home_dir, test_pinata);
|
|
}
|
|
"test_authenticated_transfer_initialize_function" => {
|
|
test_cleanup_wrap!(home_dir, test_authenticated_transfer_initialize_function);
|
|
}
|
|
"test_pinata_private_receiver" => {
|
|
test_cleanup_wrap!(home_dir, test_pinata_private_receiver);
|
|
}
|
|
"test_success_token_program_private_owned" => {
|
|
test_cleanup_wrap!(home_dir, test_success_token_program_private_owned);
|
|
}
|
|
"test_success_token_program_private_claiming_path" => {
|
|
test_cleanup_wrap!(home_dir, test_success_token_program_private_claiming_path);
|
|
}
|
|
"test_pinata_private_receiver_new_account" => {
|
|
test_cleanup_wrap!(home_dir, test_pinata_private_receiver_new_account);
|
|
}
|
|
"test_success_token_program_shielded_owned" => {
|
|
test_cleanup_wrap!(home_dir, test_success_token_program_shielded_owned);
|
|
}
|
|
"test_success_token_program_deshielded_owned" => {
|
|
test_cleanup_wrap!(home_dir, test_success_token_program_deshielded_owned);
|
|
}
|
|
"all" => {
|
|
test_cleanup_wrap!(home_dir, test_success_move_to_another_account);
|
|
test_cleanup_wrap!(home_dir, test_success);
|
|
test_cleanup_wrap!(home_dir, test_failure);
|
|
test_cleanup_wrap!(home_dir, test_get_account);
|
|
test_cleanup_wrap!(home_dir, test_success_two_transactions);
|
|
test_cleanup_wrap!(home_dir, test_success_token_program);
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_private_transfer_to_another_owned_account
|
|
);
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_private_transfer_to_another_foreign_account
|
|
);
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_deshielded_transfer_to_another_account
|
|
);
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_shielded_transfer_to_another_owned_account
|
|
);
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_shielded_transfer_to_another_foreign_account
|
|
);
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_private_transfer_to_another_owned_account_claiming_path
|
|
);
|
|
test_cleanup_wrap!(home_dir, test_success_token_program_shielded_owned);
|
|
test_cleanup_wrap!(home_dir, test_pinata);
|
|
test_cleanup_wrap!(home_dir, test_authenticated_transfer_initialize_function);
|
|
test_cleanup_wrap!(home_dir, test_pinata_private_receiver);
|
|
test_cleanup_wrap!(home_dir, test_success_token_program_private_owned);
|
|
test_cleanup_wrap!(home_dir, test_success_token_program_deshielded_owned);
|
|
test_cleanup_wrap!(home_dir, test_success_token_program_private_claiming_path);
|
|
test_cleanup_wrap!(home_dir, test_pinata_private_receiver_new_account);
|
|
}
|
|
"all_private" => {
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_private_transfer_to_another_owned_account
|
|
);
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_private_transfer_to_another_foreign_account
|
|
);
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_deshielded_transfer_to_another_account
|
|
);
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_shielded_transfer_to_another_owned_account
|
|
);
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_shielded_transfer_to_another_foreign_account
|
|
);
|
|
test_cleanup_wrap!(
|
|
home_dir,
|
|
test_success_private_transfer_to_another_owned_account_claiming_path
|
|
);
|
|
test_cleanup_wrap!(home_dir, test_pinata_private_receiver);
|
|
test_cleanup_wrap!(home_dir, test_success_token_program_private_owned);
|
|
test_cleanup_wrap!(home_dir, test_success_token_program_private_claiming_path);
|
|
test_cleanup_wrap!(home_dir, test_pinata_private_receiver_new_account);
|
|
}
|
|
_ => {
|
|
anyhow::bail!("Unknown test name");
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
async fn fetch_privacy_preserving_tx(
|
|
seq_client: &SequencerClient,
|
|
tx_hash: String,
|
|
) -> PrivacyPreservingTransaction {
|
|
let transaction_encoded = seq_client
|
|
.get_transaction_by_hash(tx_hash.clone())
|
|
.await
|
|
.unwrap()
|
|
.transaction
|
|
.unwrap();
|
|
|
|
let tx_base64_decode = BASE64.decode(transaction_encoded).unwrap();
|
|
match NSSATransaction::try_from(
|
|
&borsh::from_slice::<EncodedTransaction>(&tx_base64_decode).unwrap(),
|
|
)
|
|
.unwrap()
|
|
{
|
|
NSSATransaction::PrivacyPreserving(privacy_preserving_transaction) => {
|
|
privacy_preserving_transaction
|
|
}
|
|
_ => panic!("Invalid tx type"),
|
|
}
|
|
}
|
|
|
|
async fn verify_commitment_is_in_state(
|
|
commitment: Commitment,
|
|
seq_client: &SequencerClient,
|
|
) -> bool {
|
|
matches!(
|
|
seq_client.get_proof_for_commitment(commitment).await,
|
|
Ok(Some(_))
|
|
)
|
|
}
|