mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-02 13:23:10 +00:00
Merge pull request #205 from vacp2p/arjentix/iss-200-wallet-compute-pinata-solution
Refactor wallet & compute pinata solution in wallet
This commit is contained in:
commit
04ab7444a4
@ -56,7 +56,7 @@ fn make_private_account_input_from_str(account_id: &str) -> String {
|
||||
pub async fn pre_test(
|
||||
home_dir: PathBuf,
|
||||
) -> Result<(ServerHandle, JoinHandle<Result<()>>, TempDir)> {
|
||||
wallet::execute_setup("test_pass".to_owned()).await?;
|
||||
wallet::cli::execute_setup("test_pass".to_owned()).await?;
|
||||
|
||||
let home_dir_sequencer = home_dir.join("sequencer");
|
||||
|
||||
|
||||
@ -16,13 +16,15 @@ use sequencer_runner::startup_sequencer;
|
||||
use tempfile::TempDir;
|
||||
use tokio::task::JoinHandle;
|
||||
use wallet::{
|
||||
Command, SubcommandReturnValue, WalletCore,
|
||||
WalletCore,
|
||||
cli::{
|
||||
Command, SubcommandReturnValue,
|
||||
account::{AccountSubcommand, NewSubcommand},
|
||||
config::ConfigSubcommand,
|
||||
native_token_transfer_program::AuthTransferSubcommand,
|
||||
pinata_program::PinataProgramAgnosticSubcommand,
|
||||
token_program::TokenProgramAgnosticSubcommand,
|
||||
programs::{
|
||||
native_token_transfer::AuthTransferSubcommand, pinata::PinataProgramAgnosticSubcommand,
|
||||
token::TokenProgramAgnosticSubcommand,
|
||||
},
|
||||
},
|
||||
config::PersistentStorage,
|
||||
helperfunctions::{fetch_config, fetch_persistent_storage},
|
||||
@ -57,7 +59,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
@ -92,7 +94,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let PersistentStorage {
|
||||
accounts: persistent_accounts,
|
||||
@ -123,7 +125,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
@ -162,7 +164,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
|
||||
let failed_send = wallet::execute_subcommand(command).await;
|
||||
let failed_send = wallet::cli::execute_subcommand(command).await;
|
||||
|
||||
assert!(failed_send.is_err());
|
||||
|
||||
@ -203,7 +205,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
@ -234,7 +236,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
@ -289,7 +291,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for the token definition
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: definition_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -302,7 +304,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for the token supply holder
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: supply_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -315,7 +317,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for receiving a token transaction
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: recipient_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -335,7 +337,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
name: "A NAME".to_string(),
|
||||
total_supply: 37,
|
||||
};
|
||||
wallet::execute_subcommand(Command::Token(subcommand))
|
||||
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||
.await
|
||||
.unwrap();
|
||||
info!("Waiting for next block creation");
|
||||
@ -394,7 +396,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
amount: 7,
|
||||
};
|
||||
|
||||
wallet::execute_subcommand(Command::Token(subcommand))
|
||||
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||
.await
|
||||
.unwrap();
|
||||
info!("Waiting for next block creation");
|
||||
@ -449,7 +451,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for the token definition (public)
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: definition_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -462,7 +464,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for the token supply holder (private)
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: supply_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Private {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -475,7 +477,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for receiving a token transaction
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: recipient_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Private {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -496,7 +498,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
total_supply: 37,
|
||||
};
|
||||
|
||||
wallet::execute_subcommand(Command::Token(subcommand))
|
||||
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -543,7 +545,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
amount: 7,
|
||||
};
|
||||
|
||||
wallet::execute_subcommand(Command::Token(subcommand))
|
||||
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -577,7 +579,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
amount: 7,
|
||||
};
|
||||
|
||||
wallet::execute_subcommand(Command::Token(subcommand))
|
||||
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -610,7 +612,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for the token definition (public)
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: definition_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -623,7 +625,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for the token supply holder (private)
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: supply_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Private {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -636,7 +638,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for receiving a token transaction
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: recipient_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Private {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -657,7 +659,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
total_supply: 37,
|
||||
};
|
||||
|
||||
wallet::execute_subcommand(Command::Token(subcommand))
|
||||
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -711,7 +713,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
};
|
||||
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash: _ } =
|
||||
wallet::execute_subcommand(Command::Token(subcommand))
|
||||
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||
.await
|
||||
.unwrap()
|
||||
else {
|
||||
@ -723,7 +725,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
let command = Command::Account(AccountSubcommand::SyncPrivate {});
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config)
|
||||
@ -752,7 +754,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for the token definition (public)
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: definition_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -765,7 +767,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for the token supply holder (public)
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: supply_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -778,7 +780,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for receiving a token transaction
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: recipient_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Private {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -799,7 +801,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
total_supply: 37,
|
||||
};
|
||||
|
||||
wallet::execute_subcommand(Command::Token(subcommand))
|
||||
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -836,7 +838,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
amount: 7,
|
||||
};
|
||||
|
||||
wallet::execute_subcommand(Command::Token(subcommand))
|
||||
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -865,7 +867,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
amount: 7,
|
||||
};
|
||||
|
||||
wallet::execute_subcommand(Command::Token(subcommand))
|
||||
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -894,7 +896,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for the token definition (public)
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: definition_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -907,7 +909,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for the token supply holder (private)
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: supply_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Private {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -920,7 +922,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for receiving a token transaction
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: recipient_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -941,7 +943,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
total_supply: 37,
|
||||
};
|
||||
|
||||
wallet::execute_subcommand(Command::Token(subcommand))
|
||||
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -988,7 +990,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
amount: 7,
|
||||
};
|
||||
|
||||
wallet::execute_subcommand(Command::Token(subcommand))
|
||||
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -1017,7 +1019,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
amount: 7,
|
||||
};
|
||||
|
||||
wallet::execute_subcommand(Command::Token(subcommand))
|
||||
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -1049,7 +1051,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
@ -1088,7 +1090,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
});
|
||||
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } =
|
||||
wallet::execute_subcommand(command).await.unwrap()
|
||||
wallet::cli::execute_subcommand(command).await.unwrap()
|
||||
else {
|
||||
panic!("invalid subcommand return value");
|
||||
};
|
||||
@ -1128,7 +1130,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
cci: ChainIndex::root(),
|
||||
}));
|
||||
|
||||
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
|
||||
let sub_ret = wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: to_account_id,
|
||||
} = sub_ret
|
||||
@ -1157,7 +1159,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
|
||||
let sub_ret = wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else {
|
||||
panic!("FAILED TO SEND TX");
|
||||
};
|
||||
@ -1165,7 +1167,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await;
|
||||
|
||||
let command = Command::Account(AccountSubcommand::SyncPrivate {});
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config)
|
||||
.await
|
||||
.unwrap();
|
||||
@ -1192,13 +1194,13 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// info!(
|
||||
// "########## test_success_private_transfer_to_another_owned_account_cont_run_path
|
||||
// ##########" );
|
||||
// let continious_run_handle = tokio::spawn(wallet::execute_continious_run());
|
||||
// let continious_run_handle = tokio::spawn(wallet::cli::execute_continious_run());
|
||||
|
||||
// let from: AccountId = ACC_SENDER_PRIVATE.parse().unwrap();
|
||||
|
||||
// let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private {}));
|
||||
|
||||
// let sub_ret = wallet::execute_subcommand(command).await.unwrap();
|
||||
// let sub_ret = wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
// let SubcommandReturnValue::RegisterAccount {
|
||||
// account_id: to_account_id,
|
||||
// } = sub_ret
|
||||
@ -1228,7 +1230,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// amount: 100,
|
||||
// });
|
||||
|
||||
// let sub_ret = wallet::execute_subcommand(command).await.unwrap();
|
||||
// let sub_ret = wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
// let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else {
|
||||
// panic!("FAILED TO SEND TX");
|
||||
// };
|
||||
@ -1279,7 +1281,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let from_acc = wallet_storage.get_account_private(&from).unwrap();
|
||||
assert_eq!(from_acc.balance, 10000);
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
@ -1322,7 +1324,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
@ -1368,7 +1370,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } =
|
||||
wallet::execute_subcommand(command).await.unwrap()
|
||||
wallet::cli::execute_subcommand(command).await.unwrap()
|
||||
else {
|
||||
panic!("invalid subcommand return value");
|
||||
};
|
||||
@ -1398,10 +1400,8 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let pinata_account_id = PINATA_BASE58;
|
||||
|
||||
let pinata_prize = 150;
|
||||
let solution = 989106;
|
||||
let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
|
||||
to_account_id: make_public_account_input_from_str(ACC_SENDER),
|
||||
solution,
|
||||
to: make_public_account_input_from_str(ACC_SENDER),
|
||||
});
|
||||
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
@ -1414,7 +1414,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
.unwrap()
|
||||
.balance;
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
@ -1493,7 +1493,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
cci: ChainIndex::root(),
|
||||
}));
|
||||
let SubcommandReturnValue::RegisterAccount { account_id } =
|
||||
wallet::execute_subcommand(command).await.unwrap()
|
||||
wallet::cli::execute_subcommand(command).await.unwrap()
|
||||
else {
|
||||
panic!("Error creating account");
|
||||
};
|
||||
@ -1501,7 +1501,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Init {
|
||||
account_id: make_public_account_input_from_str(&account_id.to_string()),
|
||||
});
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Checking correct execution");
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
@ -1529,11 +1529,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
info!("########## test_pinata_private_receiver ##########");
|
||||
let pinata_account_id = PINATA_BASE58;
|
||||
let pinata_prize = 150;
|
||||
let solution = 989106;
|
||||
|
||||
let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
|
||||
to_account_id: make_private_account_input_from_str(ACC_SENDER_PRIVATE),
|
||||
solution,
|
||||
to: make_private_account_input_from_str(ACC_SENDER_PRIVATE),
|
||||
});
|
||||
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
@ -1547,7 +1545,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
.balance;
|
||||
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash: _ } =
|
||||
wallet::execute_subcommand(command).await.unwrap()
|
||||
wallet::cli::execute_subcommand(command).await.unwrap()
|
||||
else {
|
||||
panic!("invalid subcommand return value");
|
||||
};
|
||||
@ -1563,7 +1561,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
.balance;
|
||||
|
||||
let command = Command::Account(AccountSubcommand::SyncPrivate {});
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
@ -1586,12 +1584,11 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
info!("########## test_pinata_private_receiver_new_account ##########");
|
||||
let pinata_account_id = PINATA_BASE58;
|
||||
let pinata_prize = 150;
|
||||
let solution = 989106;
|
||||
|
||||
// Create new account for the token supply holder (private)
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
account_id: winner_account_id,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Private {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
@ -1603,8 +1600,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
};
|
||||
|
||||
let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
|
||||
to_account_id: make_private_account_input_from_str(&winner_account_id.to_string()),
|
||||
solution,
|
||||
to: make_private_account_input_from_str(&winner_account_id.to_string()),
|
||||
});
|
||||
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
@ -1617,7 +1613,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
.unwrap()
|
||||
.balance;
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
@ -1657,7 +1653,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
key: "seq_poll_retry_delay_millis".to_string(),
|
||||
value: "1000".to_string(),
|
||||
});
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
|
||||
@ -1668,7 +1664,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
key: "seq_poll_retry_delay_millis".to_string(),
|
||||
value: old_seq_poll_retry_delay_millis.to_string(),
|
||||
});
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Success!");
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ base58.workspace = true
|
||||
hex = "0.4.3"
|
||||
rand.workspace = true
|
||||
itertools = "0.14.0"
|
||||
sha2.workspace = true
|
||||
|
||||
[dependencies.key_protocol]
|
||||
path = "../key_protocol"
|
||||
|
||||
@ -7,10 +7,11 @@ use nssa::{Account, AccountId, program::Program};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
SubcommandReturnValue, WalletCore,
|
||||
cli::WalletSubcommand,
|
||||
helperfunctions::{AccountPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix},
|
||||
parse_block_range,
|
||||
WalletCore,
|
||||
cli::{SubcommandReturnValue, WalletSubcommand},
|
||||
helperfunctions::{
|
||||
AccountPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix, parse_block_range,
|
||||
},
|
||||
};
|
||||
|
||||
const TOKEN_DEFINITION_TYPE: u8 = 0;
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
use anyhow::Result;
|
||||
use clap::Subcommand;
|
||||
|
||||
use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand};
|
||||
use crate::{
|
||||
WalletCore,
|
||||
cli::{SubcommandReturnValue, WalletSubcommand},
|
||||
};
|
||||
|
||||
/// Represents generic chain CLI subcommand
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
use anyhow::Result;
|
||||
use clap::Subcommand;
|
||||
|
||||
use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand};
|
||||
use crate::{
|
||||
WalletCore,
|
||||
cli::{SubcommandReturnValue, WalletSubcommand},
|
||||
};
|
||||
|
||||
/// Represents generic config CLI subcommand
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
|
||||
@ -1,15 +1,200 @@
|
||||
use anyhow::Result;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{SubcommandReturnValue, WalletCore};
|
||||
use anyhow::Result;
|
||||
use clap::{Parser, Subcommand};
|
||||
use common::sequencer_client::SequencerClient;
|
||||
use nssa::program::Program;
|
||||
|
||||
use crate::{
|
||||
WalletCore,
|
||||
cli::{
|
||||
account::AccountSubcommand,
|
||||
chain::ChainSubcommand,
|
||||
config::ConfigSubcommand,
|
||||
programs::{
|
||||
native_token_transfer::AuthTransferSubcommand, pinata::PinataProgramAgnosticSubcommand,
|
||||
token::TokenProgramAgnosticSubcommand,
|
||||
},
|
||||
},
|
||||
helperfunctions::{fetch_config, parse_block_range},
|
||||
};
|
||||
|
||||
pub mod account;
|
||||
pub mod chain;
|
||||
pub mod config;
|
||||
pub mod native_token_transfer_program;
|
||||
pub mod pinata_program;
|
||||
pub mod token_program;
|
||||
pub mod programs;
|
||||
|
||||
pub(crate) trait WalletSubcommand {
|
||||
async fn handle_subcommand(self, wallet_core: &mut WalletCore)
|
||||
-> Result<SubcommandReturnValue>;
|
||||
}
|
||||
|
||||
/// Represents CLI command for a wallet
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
#[clap(about)]
|
||||
pub enum Command {
|
||||
/// Authenticated transfer subcommand
|
||||
#[command(subcommand)]
|
||||
AuthTransfer(AuthTransferSubcommand),
|
||||
/// Generic chain info subcommand
|
||||
#[command(subcommand)]
|
||||
ChainInfo(ChainSubcommand),
|
||||
/// Account view and sync subcommand
|
||||
#[command(subcommand)]
|
||||
Account(AccountSubcommand),
|
||||
/// Pinata program interaction subcommand
|
||||
#[command(subcommand)]
|
||||
Pinata(PinataProgramAgnosticSubcommand),
|
||||
/// Token program interaction subcommand
|
||||
#[command(subcommand)]
|
||||
Token(TokenProgramAgnosticSubcommand),
|
||||
/// Check the wallet can connect to the node and builtin local programs
|
||||
/// match the remote versions
|
||||
CheckHealth {},
|
||||
/// Command to setup config, get and set config fields
|
||||
#[command(subcommand)]
|
||||
Config(ConfigSubcommand),
|
||||
}
|
||||
|
||||
/// Represents overarching CLI command for a wallet with setup included
|
||||
#[derive(Debug, Subcommand, Clone)]
|
||||
#[clap(about)]
|
||||
pub enum OverCommand {
|
||||
/// Represents CLI command for a wallet
|
||||
#[command(subcommand)]
|
||||
Command(Command),
|
||||
/// Setup of a storage. Initializes rots for public and private trees from `password`.
|
||||
Setup {
|
||||
#[arg(short, long)]
|
||||
password: String,
|
||||
},
|
||||
}
|
||||
|
||||
/// To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config
|
||||
///
|
||||
/// All account adresses must be valid 32 byte base58 strings.
|
||||
///
|
||||
/// All account account_ids must be provided as {privacy_prefix}/{account_id},
|
||||
/// where valid options for `privacy_prefix` is `Public` and `Private`
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(version, about)]
|
||||
pub struct Args {
|
||||
/// Continious run flag
|
||||
#[arg(short, long)]
|
||||
pub continuous_run: bool,
|
||||
/// Wallet command
|
||||
#[command(subcommand)]
|
||||
pub command: Option<OverCommand>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SubcommandReturnValue {
|
||||
PrivacyPreservingTransfer { tx_hash: String },
|
||||
RegisterAccount { account_id: nssa::AccountId },
|
||||
Account(nssa::Account),
|
||||
Empty,
|
||||
SyncedToBlock(u64),
|
||||
}
|
||||
|
||||
pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValue> {
|
||||
let wallet_config = fetch_config().await?;
|
||||
let mut wallet_core = WalletCore::start_from_config_update_chain(wallet_config).await?;
|
||||
|
||||
let subcommand_ret = match command {
|
||||
Command::AuthTransfer(transfer_subcommand) => {
|
||||
transfer_subcommand
|
||||
.handle_subcommand(&mut wallet_core)
|
||||
.await?
|
||||
}
|
||||
Command::ChainInfo(chain_subcommand) => {
|
||||
chain_subcommand.handle_subcommand(&mut wallet_core).await?
|
||||
}
|
||||
Command::Account(account_subcommand) => {
|
||||
account_subcommand
|
||||
.handle_subcommand(&mut wallet_core)
|
||||
.await?
|
||||
}
|
||||
Command::Pinata(pinata_subcommand) => {
|
||||
pinata_subcommand
|
||||
.handle_subcommand(&mut wallet_core)
|
||||
.await?
|
||||
}
|
||||
Command::CheckHealth {} => {
|
||||
let remote_program_ids = wallet_core
|
||||
.sequencer_client
|
||||
.get_program_ids()
|
||||
.await
|
||||
.expect("Error fetching program ids");
|
||||
let Some(authenticated_transfer_id) = remote_program_ids.get("authenticated_transfer")
|
||||
else {
|
||||
panic!("Missing authenticated transfer ID from remote");
|
||||
};
|
||||
if authenticated_transfer_id != &Program::authenticated_transfer_program().id() {
|
||||
panic!("Local ID for authenticated transfer program is different from remote");
|
||||
}
|
||||
let Some(token_id) = remote_program_ids.get("token") else {
|
||||
panic!("Missing token program ID from remote");
|
||||
};
|
||||
if token_id != &Program::token().id() {
|
||||
panic!("Local ID for token program is different from remote");
|
||||
}
|
||||
let Some(circuit_id) = remote_program_ids.get("privacy_preserving_circuit") else {
|
||||
panic!("Missing privacy preserving circuit ID from remote");
|
||||
};
|
||||
if circuit_id != &nssa::PRIVACY_PRESERVING_CIRCUIT_ID {
|
||||
panic!("Local ID for privacy preserving circuit is different from remote");
|
||||
}
|
||||
|
||||
println!("✅All looks good!");
|
||||
|
||||
SubcommandReturnValue::Empty
|
||||
}
|
||||
Command::Token(token_subcommand) => {
|
||||
token_subcommand.handle_subcommand(&mut wallet_core).await?
|
||||
}
|
||||
Command::Config(config_subcommand) => {
|
||||
config_subcommand
|
||||
.handle_subcommand(&mut wallet_core)
|
||||
.await?
|
||||
}
|
||||
};
|
||||
|
||||
Ok(subcommand_ret)
|
||||
}
|
||||
|
||||
pub async fn execute_continuous_run() -> Result<()> {
|
||||
let config = fetch_config().await?;
|
||||
let seq_client = Arc::new(SequencerClient::new(config.sequencer_addr.clone())?);
|
||||
let mut wallet_core = WalletCore::start_from_config_update_chain(config.clone()).await?;
|
||||
|
||||
let mut latest_block_num = seq_client.get_last_block().await?.last_block;
|
||||
let mut curr_last_block = latest_block_num;
|
||||
|
||||
loop {
|
||||
parse_block_range(
|
||||
curr_last_block,
|
||||
latest_block_num,
|
||||
seq_client.clone(),
|
||||
&mut wallet_core,
|
||||
)
|
||||
.await?;
|
||||
|
||||
curr_last_block = latest_block_num + 1;
|
||||
|
||||
tokio::time::sleep(std::time::Duration::from_millis(
|
||||
config.seq_poll_timeout_millis,
|
||||
))
|
||||
.await;
|
||||
|
||||
latest_block_num = seq_client.get_last_block().await?.last_block;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn execute_setup(password: String) -> Result<()> {
|
||||
let config = fetch_config().await?;
|
||||
let wallet_core = WalletCore::start_from_config_new_storage(config.clone(), password).await?;
|
||||
|
||||
wallet_core.store_persistent_data().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
3
wallet/src/cli/programs/mod.rs
Normal file
3
wallet/src/cli/programs/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub mod native_token_transfer;
|
||||
pub mod pinata;
|
||||
pub mod token;
|
||||
@ -4,9 +4,10 @@ use common::transaction::NSSATransaction;
|
||||
use nssa::AccountId;
|
||||
|
||||
use crate::{
|
||||
SubcommandReturnValue, WalletCore,
|
||||
cli::WalletSubcommand,
|
||||
WalletCore,
|
||||
cli::{SubcommandReturnValue, WalletSubcommand},
|
||||
helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix},
|
||||
program_facades::native_token_transfer::NativeTokenTransfer,
|
||||
};
|
||||
|
||||
/// Represents generic CLI subcommand for a wallet working with native token transfer program
|
||||
@ -56,11 +57,11 @@ impl WalletSubcommand for AuthTransferSubcommand {
|
||||
AccountPrivacyKind::Public => {
|
||||
let account_id = account_id.parse()?;
|
||||
|
||||
let res = wallet_core
|
||||
.register_account_under_authenticated_transfers_programs(account_id)
|
||||
let res = NativeTokenTransfer(wallet_core)
|
||||
.register_account(account_id)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let transfer_tx =
|
||||
wallet_core.poll_native_token_transfer(res.tx_hash).await?;
|
||||
@ -74,13 +75,11 @@ impl WalletSubcommand for AuthTransferSubcommand {
|
||||
AccountPrivacyKind::Private => {
|
||||
let account_id = account_id.parse()?;
|
||||
|
||||
let (res, [secret]) = wallet_core
|
||||
.register_account_under_authenticated_transfers_programs_private(
|
||||
account_id,
|
||||
)
|
||||
let (res, secret) = NativeTokenTransfer(wallet_core)
|
||||
.register_account_private(account_id)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
let transfer_tx = wallet_core
|
||||
@ -317,23 +316,11 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
|
||||
let from: AccountId = from.parse().unwrap();
|
||||
let to: AccountId = to.parse().unwrap();
|
||||
|
||||
let to_initialization = wallet_core.check_private_account_initialized(&to).await?;
|
||||
let (res, [secret_from, secret_to]) = NativeTokenTransfer(wallet_core)
|
||||
.send_private_transfer_to_owned_account(from, to, amount)
|
||||
.await?;
|
||||
|
||||
let (res, [secret_from, secret_to]) = if let Some(to_proof) = to_initialization {
|
||||
wallet_core
|
||||
.send_private_native_token_transfer_owned_account_already_initialized(
|
||||
from, to, amount, to_proof,
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
wallet_core
|
||||
.send_private_native_token_transfer_owned_account_not_initialized(
|
||||
from, to, amount,
|
||||
)
|
||||
.await?
|
||||
};
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
let transfer_tx = wallet_core
|
||||
@ -373,11 +360,11 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
|
||||
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)
|
||||
let (res, [secret_from, _]) = NativeTokenTransfer(wallet_core)
|
||||
.send_private_transfer_to_outer_account(from, to_npk, to_ipk, amount)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
let transfer_tx = wallet_core
|
||||
@ -413,21 +400,11 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
|
||||
let from: AccountId = from.parse().unwrap();
|
||||
let to: AccountId = to.parse().unwrap();
|
||||
|
||||
let to_initialization = wallet_core.check_private_account_initialized(&to).await?;
|
||||
let (res, secret) = NativeTokenTransfer(wallet_core)
|
||||
.send_shielded_transfer(from, to, amount)
|
||||
.await?;
|
||||
|
||||
let (res, [secret]) = if let Some(to_proof) = to_initialization {
|
||||
wallet_core
|
||||
.send_shielded_native_token_transfer_already_initialized(
|
||||
from, to, amount, to_proof,
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
wallet_core
|
||||
.send_shielded_native_token_transfer_not_initialized(from, to, amount)
|
||||
.await?
|
||||
};
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
let transfer_tx = wallet_core
|
||||
@ -468,11 +445,11 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
|
||||
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)
|
||||
let (res, _) = NativeTokenTransfer(wallet_core)
|
||||
.send_shielded_transfer_to_outer_account(from, to_npk, to_ipk, amount)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
|
||||
@ -502,11 +479,11 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
|
||||
let from: AccountId = from.parse().unwrap();
|
||||
let to: AccountId = to.parse().unwrap();
|
||||
|
||||
let (res, [secret]) = wallet_core
|
||||
.send_deshielded_native_token_transfer(from, to, amount)
|
||||
let (res, secret) = NativeTokenTransfer(wallet_core)
|
||||
.send_deshielded_transfer(from, to, amount)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
let transfer_tx = wallet_core
|
||||
@ -532,11 +509,11 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
|
||||
let from: AccountId = from.parse().unwrap();
|
||||
let to: AccountId = to.parse().unwrap();
|
||||
|
||||
let res = wallet_core
|
||||
.send_public_native_token_transfer(from, to, amount)
|
||||
let res = NativeTokenTransfer(wallet_core)
|
||||
.send_public_transfer(from, to, amount)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let transfer_tx = wallet_core.poll_native_token_transfer(res.tx_hash).await?;
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
use anyhow::Result;
|
||||
use anyhow::{Context, Result};
|
||||
use clap::Subcommand;
|
||||
use common::{PINATA_BASE58, transaction::NSSATransaction};
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
SubcommandReturnValue, WalletCore,
|
||||
cli::WalletSubcommand,
|
||||
WalletCore,
|
||||
cli::{SubcommandReturnValue, WalletSubcommand},
|
||||
helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix},
|
||||
program_facades::pinata::Pinata,
|
||||
};
|
||||
|
||||
/// Represents generic CLI subcommand for a wallet working with pinata program
|
||||
@ -14,12 +14,9 @@ use crate::{
|
||||
pub enum PinataProgramAgnosticSubcommand {
|
||||
/// Claim pinata
|
||||
Claim {
|
||||
/// to_account_id - valid 32 byte base58 string with privacy prefix
|
||||
/// to - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
to_account_id: String,
|
||||
/// solution - solution to pinata challenge
|
||||
#[arg(long)]
|
||||
solution: u128,
|
||||
to: String,
|
||||
},
|
||||
}
|
||||
|
||||
@ -29,26 +26,20 @@ impl WalletSubcommand for PinataProgramAgnosticSubcommand {
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
let underlying_subcommand = match self {
|
||||
PinataProgramAgnosticSubcommand::Claim {
|
||||
to_account_id,
|
||||
solution,
|
||||
} => {
|
||||
let (to_account_id, to_addr_privacy) =
|
||||
parse_addr_with_privacy_prefix(&to_account_id)?;
|
||||
PinataProgramAgnosticSubcommand::Claim { to } => {
|
||||
let (to, to_addr_privacy) = parse_addr_with_privacy_prefix(&to)?;
|
||||
|
||||
match to_addr_privacy {
|
||||
AccountPrivacyKind::Public => {
|
||||
PinataProgramSubcommand::Public(PinataProgramSubcommandPublic::Claim {
|
||||
pinata_account_id: PINATA_BASE58.to_string(),
|
||||
winner_account_id: to_account_id,
|
||||
solution,
|
||||
winner_account_id: to,
|
||||
})
|
||||
}
|
||||
AccountPrivacyKind::Private => PinataProgramSubcommand::Private(
|
||||
PinataProgramSubcommandPrivate::ClaimPrivateOwned {
|
||||
pinata_account_id: PINATA_BASE58.to_string(),
|
||||
winner_account_id: to_account_id,
|
||||
solution,
|
||||
winner_account_id: to,
|
||||
},
|
||||
),
|
||||
}
|
||||
@ -82,9 +73,6 @@ pub enum PinataProgramSubcommandPublic {
|
||||
/// winner_account_id - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
winner_account_id: String,
|
||||
/// solution - solution to pinata challenge
|
||||
#[arg(long)]
|
||||
solution: u128,
|
||||
},
|
||||
}
|
||||
|
||||
@ -100,9 +88,6 @@ pub enum PinataProgramSubcommandPrivate {
|
||||
/// winner_account_id - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
winner_account_id: String,
|
||||
/// solution - solution to pinata challenge
|
||||
#[arg(long)]
|
||||
solution: u128,
|
||||
},
|
||||
}
|
||||
|
||||
@ -115,16 +100,28 @@ impl WalletSubcommand for PinataProgramSubcommandPublic {
|
||||
PinataProgramSubcommandPublic::Claim {
|
||||
pinata_account_id,
|
||||
winner_account_id,
|
||||
solution,
|
||||
} => {
|
||||
let res = wallet_core
|
||||
.claim_pinata(
|
||||
pinata_account_id.parse().unwrap(),
|
||||
let pinata_account_id = pinata_account_id.parse().unwrap();
|
||||
let solution = find_solution(wallet_core, pinata_account_id)
|
||||
.await
|
||||
.context("failed to compute solution")?;
|
||||
|
||||
let res = Pinata(wallet_core)
|
||||
.claim(
|
||||
pinata_account_id,
|
||||
winner_account_id.parse().unwrap(),
|
||||
solution,
|
||||
)
|
||||
.await?;
|
||||
info!("Results of tx send is {res:#?}");
|
||||
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
let transfer_tx = wallet_core
|
||||
.poll_native_token_transfer(tx_hash.clone())
|
||||
.await?;
|
||||
|
||||
println!("Transaction data is {transfer_tx:?}");
|
||||
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
@ -141,41 +138,26 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate {
|
||||
PinataProgramSubcommandPrivate::ClaimPrivateOwned {
|
||||
pinata_account_id,
|
||||
winner_account_id,
|
||||
solution,
|
||||
} => {
|
||||
let pinata_account_id = pinata_account_id.parse().unwrap();
|
||||
let winner_account_id = winner_account_id.parse().unwrap();
|
||||
let solution = find_solution(wallet_core, pinata_account_id)
|
||||
.await
|
||||
.context("failed to compute solution")?;
|
||||
|
||||
let winner_initialization = wallet_core
|
||||
.check_private_account_initialized(&winner_account_id)
|
||||
let (res, secret_winner) = Pinata(wallet_core)
|
||||
.claim_private_owned_account(pinata_account_id, winner_account_id, solution)
|
||||
.await?;
|
||||
|
||||
let (res, [secret_winner]) = if let Some(winner_proof) = winner_initialization {
|
||||
wallet_core
|
||||
.claim_pinata_private_owned_account_already_initialized(
|
||||
pinata_account_id,
|
||||
winner_account_id,
|
||||
solution,
|
||||
winner_proof,
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
wallet_core
|
||||
.claim_pinata_private_owned_account_not_initialized(
|
||||
pinata_account_id,
|
||||
winner_account_id,
|
||||
solution,
|
||||
)
|
||||
.await?
|
||||
};
|
||||
|
||||
info!("Results of tx send is {res:#?}");
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
let transfer_tx = wallet_core
|
||||
.poll_native_token_transfer(tx_hash.clone())
|
||||
.await?;
|
||||
|
||||
println!("Transaction data is {transfer_tx:?}");
|
||||
|
||||
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||
let acc_decode_data = vec![(secret_winner, winner_account_id)];
|
||||
|
||||
@ -210,3 +192,46 @@ impl WalletSubcommand for PinataProgramSubcommand {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn find_solution(wallet: &WalletCore, pinata_account_id: nssa::AccountId) -> Result<u128> {
|
||||
let account = wallet.get_account_public(pinata_account_id).await?;
|
||||
let data: [u8; 33] = account
|
||||
.data
|
||||
.try_into()
|
||||
.map_err(|_| anyhow::Error::msg("invalid pinata account data"))?;
|
||||
|
||||
println!("Computing solution for pinata...");
|
||||
let now = std::time::Instant::now();
|
||||
|
||||
let solution = compute_solution(data);
|
||||
|
||||
println!("Found solution {solution} in {:?}", now.elapsed());
|
||||
Ok(solution)
|
||||
}
|
||||
|
||||
fn compute_solution(data: [u8; 33]) -> u128 {
|
||||
let difficulty = data[0];
|
||||
let seed = &data[1..];
|
||||
|
||||
let mut solution = 0u128;
|
||||
while !validate_solution(difficulty, seed, solution) {
|
||||
solution = solution.checked_add(1).expect("solution overflowed u128");
|
||||
}
|
||||
|
||||
solution
|
||||
}
|
||||
|
||||
fn validate_solution(difficulty: u8, seed: &[u8], solution: u128) -> bool {
|
||||
use sha2::{Digest as _, digest::FixedOutput as _};
|
||||
|
||||
let mut bytes = [0; 32 + 16];
|
||||
bytes[..32].copy_from_slice(seed);
|
||||
bytes[32..].copy_from_slice(&solution.to_le_bytes());
|
||||
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(bytes);
|
||||
let digest: [u8; 32] = hasher.finalize_fixed().into();
|
||||
|
||||
let difficulty = difficulty as usize;
|
||||
digest[..difficulty].iter().all(|&b| b == 0)
|
||||
}
|
||||
@ -4,9 +4,10 @@ use common::transaction::NSSATransaction;
|
||||
use nssa::AccountId;
|
||||
|
||||
use crate::{
|
||||
SubcommandReturnValue, WalletCore,
|
||||
cli::WalletSubcommand,
|
||||
WalletCore,
|
||||
cli::{SubcommandReturnValue, WalletSubcommand},
|
||||
helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix},
|
||||
program_facades::token::Token,
|
||||
};
|
||||
|
||||
/// Represents generic CLI subcommand for a wallet working with token program
|
||||
@ -338,8 +339,8 @@ impl WalletSubcommand for TokenProgramSubcommandPublic {
|
||||
}
|
||||
let mut name_bytes = [0; 6];
|
||||
name_bytes[..name.len()].copy_from_slice(name);
|
||||
wallet_core
|
||||
.send_new_token_definition(
|
||||
Token(wallet_core)
|
||||
.send_new_definition(
|
||||
definition_account_id.parse().unwrap(),
|
||||
supply_account_id.parse().unwrap(),
|
||||
name_bytes,
|
||||
@ -353,8 +354,8 @@ impl WalletSubcommand for TokenProgramSubcommandPublic {
|
||||
recipient_account_id,
|
||||
balance_to_move,
|
||||
} => {
|
||||
wallet_core
|
||||
.send_transfer_token_transaction(
|
||||
Token(wallet_core)
|
||||
.send_transfer_transaction(
|
||||
sender_account_id.parse().unwrap(),
|
||||
recipient_account_id.parse().unwrap(),
|
||||
balance_to_move,
|
||||
@ -389,8 +390,8 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
|
||||
let definition_account_id: AccountId = definition_account_id.parse().unwrap();
|
||||
let supply_account_id: AccountId = supply_account_id.parse().unwrap();
|
||||
|
||||
let (res, [secret_supply]) = wallet_core
|
||||
.send_new_token_definition_private_owned(
|
||||
let (res, secret_supply) = Token(wallet_core)
|
||||
.send_new_definition_private_owned(
|
||||
definition_account_id,
|
||||
supply_account_id,
|
||||
name_bytes,
|
||||
@ -398,7 +399,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
|
||||
)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
let transfer_tx = wallet_core
|
||||
@ -428,31 +429,15 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
|
||||
let sender_account_id: AccountId = sender_account_id.parse().unwrap();
|
||||
let recipient_account_id: AccountId = recipient_account_id.parse().unwrap();
|
||||
|
||||
let recipient_initialization = wallet_core
|
||||
.check_private_account_initialized(&recipient_account_id)
|
||||
let (res, [secret_sender, secret_recipient]) = Token(wallet_core)
|
||||
.send_transfer_transaction_private_owned_account(
|
||||
sender_account_id,
|
||||
recipient_account_id,
|
||||
balance_to_move,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let (res, [secret_sender, secret_recipient]) =
|
||||
if let Some(recipient_proof) = recipient_initialization {
|
||||
wallet_core
|
||||
.send_transfer_token_transaction_private_owned_account_already_initialized(
|
||||
sender_account_id,
|
||||
recipient_account_id,
|
||||
balance_to_move,
|
||||
recipient_proof,
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
wallet_core
|
||||
.send_transfer_token_transaction_private_owned_account_not_initialized(
|
||||
sender_account_id,
|
||||
recipient_account_id,
|
||||
balance_to_move,
|
||||
)
|
||||
.await?
|
||||
};
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
let transfer_tx = wallet_core
|
||||
@ -496,8 +481,8 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
|
||||
recipient_ipk.to_vec(),
|
||||
);
|
||||
|
||||
let (res, [secret_sender, _]) = wallet_core
|
||||
.send_transfer_token_transaction_private_foreign_account(
|
||||
let (res, [secret_sender, _]) = Token(wallet_core)
|
||||
.send_transfer_transaction_private_foreign_account(
|
||||
sender_account_id,
|
||||
recipient_npk,
|
||||
recipient_ipk,
|
||||
@ -505,7 +490,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
|
||||
)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
let transfer_tx = wallet_core
|
||||
@ -545,15 +530,15 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded {
|
||||
let sender_account_id: AccountId = sender_account_id.parse().unwrap();
|
||||
let recipient_account_id: AccountId = recipient_account_id.parse().unwrap();
|
||||
|
||||
let (res, [secret_sender]) = wallet_core
|
||||
.send_transfer_token_transaction_deshielded(
|
||||
let (res, secret_sender) = Token(wallet_core)
|
||||
.send_transfer_transaction_deshielded(
|
||||
sender_account_id,
|
||||
recipient_account_id,
|
||||
balance_to_move,
|
||||
)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
let transfer_tx = wallet_core
|
||||
@ -604,8 +589,8 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
|
||||
recipient_ipk.to_vec(),
|
||||
);
|
||||
|
||||
let res = wallet_core
|
||||
.send_transfer_token_transaction_shielded_foreign_account(
|
||||
let (res, _) = Token(wallet_core)
|
||||
.send_transfer_transaction_shielded_foreign_account(
|
||||
sender_account_id,
|
||||
recipient_npk,
|
||||
recipient_ipk,
|
||||
@ -613,7 +598,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
|
||||
)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
let transfer_tx = wallet_core
|
||||
@ -638,31 +623,15 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
|
||||
let sender_account_id: AccountId = sender_account_id.parse().unwrap();
|
||||
let recipient_account_id: AccountId = recipient_account_id.parse().unwrap();
|
||||
|
||||
let recipient_initialization = wallet_core
|
||||
.check_private_account_initialized(&recipient_account_id)
|
||||
let (res, secret_recipient) = Token(wallet_core)
|
||||
.send_transfer_transaction_shielded_owned_account(
|
||||
sender_account_id,
|
||||
recipient_account_id,
|
||||
balance_to_move,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let (res, [secret_recipient]) =
|
||||
if let Some(recipient_proof) = recipient_initialization {
|
||||
wallet_core
|
||||
.send_transfer_token_transaction_shielded_owned_account_already_initialized(
|
||||
sender_account_id,
|
||||
recipient_account_id,
|
||||
balance_to_move,
|
||||
recipient_proof,
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
wallet_core
|
||||
.send_transfer_token_transaction_shielded_owned_account_not_initialized(
|
||||
sender_account_id,
|
||||
recipient_account_id,
|
||||
balance_to_move,
|
||||
)
|
||||
.await?
|
||||
};
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
let transfer_tx = wallet_core
|
||||
@ -1,16 +1,21 @@
|
||||
use std::{path::PathBuf, str::FromStr};
|
||||
use std::{path::PathBuf, str::FromStr, sync::Arc};
|
||||
|
||||
use anyhow::Result;
|
||||
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
||||
use key_protocol::key_protocol_core::NSSAUserData;
|
||||
use nssa::Account;
|
||||
use common::{
|
||||
block::HashableBlockData, sequencer_client::SequencerClient, transaction::NSSATransaction,
|
||||
};
|
||||
use key_protocol::{
|
||||
key_management::key_tree::traits::KeyNode as _, key_protocol_core::NSSAUserData,
|
||||
};
|
||||
use nssa::{Account, privacy_preserving_transaction::message::EncryptedAccountData};
|
||||
use nssa_core::account::Nonce;
|
||||
use rand::{RngCore, rngs::OsRng};
|
||||
use serde::Serialize;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
|
||||
use crate::{
|
||||
HOME_DIR_ENV_VAR,
|
||||
HOME_DIR_ENV_VAR, WalletCore,
|
||||
config::{
|
||||
InitialAccountData, InitialAccountDataPrivate, InitialAccountDataPublic,
|
||||
PersistentAccountDataPrivate, PersistentAccountDataPublic, PersistentStorage, WalletConfig,
|
||||
@ -225,6 +230,125 @@ impl From<Account> for HumanReadableAccount {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn parse_block_range(
|
||||
start: u64,
|
||||
stop: u64,
|
||||
seq_client: Arc<SequencerClient>,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<()> {
|
||||
for block_id in start..(stop + 1) {
|
||||
let block =
|
||||
borsh::from_slice::<HashableBlockData>(&seq_client.get_block(block_id).await?.block)?;
|
||||
|
||||
for tx in block.transactions {
|
||||
let nssa_tx = NSSATransaction::try_from(&tx)?;
|
||||
|
||||
if let NSSATransaction::PrivacyPreserving(tx) = nssa_tx {
|
||||
let mut affected_accounts = vec![];
|
||||
|
||||
for (acc_account_id, (key_chain, _)) in
|
||||
&wallet_core.storage.user_data.default_user_private_accounts
|
||||
{
|
||||
let view_tag = EncryptedAccountData::compute_view_tag(
|
||||
key_chain.nullifer_public_key.clone(),
|
||||
key_chain.incoming_viewing_public_key.clone(),
|
||||
);
|
||||
|
||||
for (ciph_id, encrypted_data) in tx
|
||||
.message()
|
||||
.encrypted_private_post_states
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
if encrypted_data.view_tag == view_tag {
|
||||
let ciphertext = &encrypted_data.ciphertext;
|
||||
let commitment = &tx.message.new_commitments[ciph_id];
|
||||
let shared_secret = key_chain
|
||||
.calculate_shared_secret_receiver(encrypted_data.epk.clone());
|
||||
|
||||
let res_acc = nssa_core::EncryptionScheme::decrypt(
|
||||
ciphertext,
|
||||
&shared_secret,
|
||||
commitment,
|
||||
ciph_id as u32,
|
||||
);
|
||||
|
||||
if let Some(res_acc) = res_acc {
|
||||
println!(
|
||||
"Received new account for account_id {acc_account_id:#?} with account object {res_acc:#?}"
|
||||
);
|
||||
|
||||
affected_accounts.push((*acc_account_id, res_acc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for keys_node in wallet_core
|
||||
.storage
|
||||
.user_data
|
||||
.private_key_tree
|
||||
.key_map
|
||||
.values()
|
||||
{
|
||||
let acc_account_id = keys_node.account_id();
|
||||
let key_chain = &keys_node.value.0;
|
||||
|
||||
let view_tag = EncryptedAccountData::compute_view_tag(
|
||||
key_chain.nullifer_public_key.clone(),
|
||||
key_chain.incoming_viewing_public_key.clone(),
|
||||
);
|
||||
|
||||
for (ciph_id, encrypted_data) in tx
|
||||
.message()
|
||||
.encrypted_private_post_states
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
if encrypted_data.view_tag == view_tag {
|
||||
let ciphertext = &encrypted_data.ciphertext;
|
||||
let commitment = &tx.message.new_commitments[ciph_id];
|
||||
let shared_secret = key_chain
|
||||
.calculate_shared_secret_receiver(encrypted_data.epk.clone());
|
||||
|
||||
let res_acc = nssa_core::EncryptionScheme::decrypt(
|
||||
ciphertext,
|
||||
&shared_secret,
|
||||
commitment,
|
||||
ciph_id as u32,
|
||||
);
|
||||
|
||||
if let Some(res_acc) = res_acc {
|
||||
println!(
|
||||
"Received new account for account_id {acc_account_id:#?} with account object {res_acc:#?}"
|
||||
);
|
||||
|
||||
affected_accounts.push((acc_account_id, res_acc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (affected_account_id, new_acc) in affected_accounts {
|
||||
wallet_core
|
||||
.storage
|
||||
.insert_private_account_data(affected_account_id, new_acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wallet_core.last_synced_block = block_id;
|
||||
wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!(
|
||||
"Block at id {block_id} with timestamp {} parsed",
|
||||
block.timestamp
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@ -3,31 +3,24 @@ use std::{path::PathBuf, sync::Arc};
|
||||
use anyhow::Result;
|
||||
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
||||
use chain_storage::WalletChainStore;
|
||||
use clap::{Parser, Subcommand};
|
||||
use common::{
|
||||
block::HashableBlockData,
|
||||
sequencer_client::SequencerClient,
|
||||
error::ExecutionFailureKind,
|
||||
sequencer_client::{SequencerClient, json::SendTxResponse},
|
||||
transaction::{EncodedTransaction, NSSATransaction},
|
||||
};
|
||||
use config::WalletConfig;
|
||||
use key_protocol::key_management::key_tree::{chain_index::ChainIndex, traits::KeyNode};
|
||||
use key_protocol::key_management::key_tree::chain_index::ChainIndex;
|
||||
use log::info;
|
||||
use nssa::{
|
||||
Account, AccountId, privacy_preserving_transaction::message::EncryptedAccountData,
|
||||
program::Program,
|
||||
};
|
||||
use nssa_core::{Commitment, MembershipProof};
|
||||
use nssa::{Account, AccountId, PrivacyPreservingTransaction, program::Program};
|
||||
use nssa_core::{Commitment, MembershipProof, SharedSecretKey, program::InstructionData};
|
||||
pub use privacy_preserving_tx::PrivacyPreservingAccount;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
use crate::{
|
||||
cli::{
|
||||
WalletSubcommand, account::AccountSubcommand, chain::ChainSubcommand,
|
||||
config::ConfigSubcommand, native_token_transfer_program::AuthTransferSubcommand,
|
||||
pinata_program::PinataProgramAgnosticSubcommand,
|
||||
token_program::TokenProgramAgnosticSubcommand,
|
||||
},
|
||||
config::PersistentStorage,
|
||||
helperfunctions::{fetch_config, fetch_persistent_storage, get_home, produce_data_for_storage},
|
||||
helperfunctions::{
|
||||
fetch_persistent_storage, get_home, produce_data_for_storage, produce_random_nonces,
|
||||
},
|
||||
poller::TxPoller,
|
||||
};
|
||||
|
||||
@ -37,11 +30,9 @@ pub mod chain_storage;
|
||||
pub mod cli;
|
||||
pub mod config;
|
||||
pub mod helperfunctions;
|
||||
pub mod pinata_interactions;
|
||||
pub mod poller;
|
||||
pub mod token_program_interactions;
|
||||
pub mod token_transfers;
|
||||
pub mod transaction_utils;
|
||||
mod privacy_preserving_tx;
|
||||
pub mod program_facades;
|
||||
|
||||
pub struct WalletCore {
|
||||
pub storage: WalletChainStore,
|
||||
@ -156,6 +147,15 @@ impl WalletCore {
|
||||
Ok(response.account)
|
||||
}
|
||||
|
||||
pub fn get_account_public_signing_key(
|
||||
&self,
|
||||
account_id: &AccountId,
|
||||
) -> Option<&nssa::PrivateKey> {
|
||||
self.storage
|
||||
.user_data
|
||||
.get_pub_account_signing_key(account_id)
|
||||
}
|
||||
|
||||
pub fn get_account_private(&self, account_id: &AccountId) -> Option<Account> {
|
||||
self.storage
|
||||
.user_data
|
||||
@ -218,293 +218,79 @@ impl WalletCore {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents CLI command for a wallet
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
#[clap(about)]
|
||||
pub enum Command {
|
||||
/// Authenticated transfer subcommand
|
||||
#[command(subcommand)]
|
||||
AuthTransfer(AuthTransferSubcommand),
|
||||
/// Generic chain info subcommand
|
||||
#[command(subcommand)]
|
||||
ChainInfo(ChainSubcommand),
|
||||
/// Account view and sync subcommand
|
||||
#[command(subcommand)]
|
||||
Account(AccountSubcommand),
|
||||
/// Pinata program interaction subcommand
|
||||
#[command(subcommand)]
|
||||
Pinata(PinataProgramAgnosticSubcommand),
|
||||
/// Token program interaction subcommand
|
||||
#[command(subcommand)]
|
||||
Token(TokenProgramAgnosticSubcommand),
|
||||
/// Check the wallet can connect to the node and builtin local programs
|
||||
/// match the remote versions
|
||||
CheckHealth {},
|
||||
/// Command to setup config, get and set config fields
|
||||
#[command(subcommand)]
|
||||
Config(ConfigSubcommand),
|
||||
}
|
||||
|
||||
/// Represents overarching CLI command for a wallet with setup included
|
||||
#[derive(Debug, Subcommand, Clone)]
|
||||
#[clap(about)]
|
||||
pub enum OverCommand {
|
||||
/// Represents CLI command for a wallet
|
||||
#[command(subcommand)]
|
||||
Command(Command),
|
||||
/// Setup of a storage. Initializes rots for public and private trees from `password`.
|
||||
Setup {
|
||||
#[arg(short, long)]
|
||||
password: String,
|
||||
},
|
||||
}
|
||||
|
||||
/// To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config
|
||||
///
|
||||
/// All account adresses must be valid 32 byte base58 strings.
|
||||
///
|
||||
/// All account account_ids must be provided as {privacy_prefix}/{account_id},
|
||||
/// where valid options for `privacy_prefix` is `Public` and `Private`
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(version, about)]
|
||||
pub struct Args {
|
||||
/// Continious run flag
|
||||
#[arg(short, long)]
|
||||
pub continious_run: bool,
|
||||
/// Wallet command
|
||||
#[command(subcommand)]
|
||||
pub command: Option<OverCommand>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SubcommandReturnValue {
|
||||
PrivacyPreservingTransfer { tx_hash: String },
|
||||
RegisterAccount { account_id: nssa::AccountId },
|
||||
Account(nssa::Account),
|
||||
Empty,
|
||||
SyncedToBlock(u64),
|
||||
}
|
||||
|
||||
pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValue> {
|
||||
let wallet_config = fetch_config().await?;
|
||||
let mut wallet_core = WalletCore::start_from_config_update_chain(wallet_config).await?;
|
||||
|
||||
let subcommand_ret = match command {
|
||||
Command::AuthTransfer(transfer_subcommand) => {
|
||||
transfer_subcommand
|
||||
.handle_subcommand(&mut wallet_core)
|
||||
.await?
|
||||
}
|
||||
Command::ChainInfo(chain_subcommand) => {
|
||||
chain_subcommand.handle_subcommand(&mut wallet_core).await?
|
||||
}
|
||||
Command::Account(account_subcommand) => {
|
||||
account_subcommand
|
||||
.handle_subcommand(&mut wallet_core)
|
||||
.await?
|
||||
}
|
||||
Command::Pinata(pinata_subcommand) => {
|
||||
pinata_subcommand
|
||||
.handle_subcommand(&mut wallet_core)
|
||||
.await?
|
||||
}
|
||||
Command::CheckHealth {} => {
|
||||
let remote_program_ids = wallet_core
|
||||
.sequencer_client
|
||||
.get_program_ids()
|
||||
.await
|
||||
.expect("Error fetching program ids");
|
||||
let Some(authenticated_transfer_id) = remote_program_ids.get("authenticated_transfer")
|
||||
else {
|
||||
panic!("Missing authenticated transfer ID from remote");
|
||||
};
|
||||
if authenticated_transfer_id != &Program::authenticated_transfer_program().id() {
|
||||
panic!("Local ID for authenticated transfer program is different from remote");
|
||||
}
|
||||
let Some(token_id) = remote_program_ids.get("token") else {
|
||||
panic!("Missing token program ID from remote");
|
||||
};
|
||||
if token_id != &Program::token().id() {
|
||||
panic!("Local ID for token program is different from remote");
|
||||
}
|
||||
let Some(circuit_id) = remote_program_ids.get("privacy_preserving_circuit") else {
|
||||
panic!("Missing privacy preserving circuit ID from remote");
|
||||
};
|
||||
if circuit_id != &nssa::PRIVACY_PRESERVING_CIRCUIT_ID {
|
||||
panic!("Local ID for privacy preserving circuit is different from remote");
|
||||
}
|
||||
|
||||
println!("✅All looks good!");
|
||||
|
||||
SubcommandReturnValue::Empty
|
||||
}
|
||||
Command::Token(token_subcommand) => {
|
||||
token_subcommand.handle_subcommand(&mut wallet_core).await?
|
||||
}
|
||||
Command::Config(config_subcommand) => {
|
||||
config_subcommand
|
||||
.handle_subcommand(&mut wallet_core)
|
||||
.await?
|
||||
}
|
||||
};
|
||||
|
||||
Ok(subcommand_ret)
|
||||
}
|
||||
|
||||
pub async fn parse_block_range(
|
||||
start: u64,
|
||||
stop: u64,
|
||||
seq_client: Arc<SequencerClient>,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<()> {
|
||||
for block_id in start..(stop + 1) {
|
||||
let block =
|
||||
borsh::from_slice::<HashableBlockData>(&seq_client.get_block(block_id).await?.block)?;
|
||||
|
||||
for tx in block.transactions {
|
||||
let nssa_tx = NSSATransaction::try_from(&tx)?;
|
||||
|
||||
if let NSSATransaction::PrivacyPreserving(tx) = nssa_tx {
|
||||
let mut affected_accounts = vec![];
|
||||
|
||||
for (acc_account_id, (key_chain, _)) in
|
||||
&wallet_core.storage.user_data.default_user_private_accounts
|
||||
{
|
||||
let view_tag = EncryptedAccountData::compute_view_tag(
|
||||
key_chain.nullifer_public_key.clone(),
|
||||
key_chain.incoming_viewing_public_key.clone(),
|
||||
);
|
||||
|
||||
for (ciph_id, encrypted_data) in tx
|
||||
.message()
|
||||
.encrypted_private_post_states
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
if encrypted_data.view_tag == view_tag {
|
||||
let ciphertext = &encrypted_data.ciphertext;
|
||||
let commitment = &tx.message.new_commitments[ciph_id];
|
||||
let shared_secret = key_chain
|
||||
.calculate_shared_secret_receiver(encrypted_data.epk.clone());
|
||||
|
||||
let res_acc = nssa_core::EncryptionScheme::decrypt(
|
||||
ciphertext,
|
||||
&shared_secret,
|
||||
commitment,
|
||||
ciph_id as u32,
|
||||
);
|
||||
|
||||
if let Some(res_acc) = res_acc {
|
||||
println!(
|
||||
"Received new account for account_id {acc_account_id:#?} with account object {res_acc:#?}"
|
||||
);
|
||||
|
||||
affected_accounts.push((*acc_account_id, res_acc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for keys_node in wallet_core
|
||||
.storage
|
||||
.user_data
|
||||
.private_key_tree
|
||||
.key_map
|
||||
.values()
|
||||
{
|
||||
let acc_account_id = keys_node.account_id();
|
||||
let key_chain = &keys_node.value.0;
|
||||
|
||||
let view_tag = EncryptedAccountData::compute_view_tag(
|
||||
key_chain.nullifer_public_key.clone(),
|
||||
key_chain.incoming_viewing_public_key.clone(),
|
||||
);
|
||||
|
||||
for (ciph_id, encrypted_data) in tx
|
||||
.message()
|
||||
.encrypted_private_post_states
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
if encrypted_data.view_tag == view_tag {
|
||||
let ciphertext = &encrypted_data.ciphertext;
|
||||
let commitment = &tx.message.new_commitments[ciph_id];
|
||||
let shared_secret = key_chain
|
||||
.calculate_shared_secret_receiver(encrypted_data.epk.clone());
|
||||
|
||||
let res_acc = nssa_core::EncryptionScheme::decrypt(
|
||||
ciphertext,
|
||||
&shared_secret,
|
||||
commitment,
|
||||
ciph_id as u32,
|
||||
);
|
||||
|
||||
if let Some(res_acc) = res_acc {
|
||||
println!(
|
||||
"Received new account for account_id {acc_account_id:#?} with account object {res_acc:#?}"
|
||||
);
|
||||
|
||||
affected_accounts.push((acc_account_id, res_acc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (affected_account_id, new_acc) in affected_accounts {
|
||||
wallet_core
|
||||
.storage
|
||||
.insert_private_account_data(affected_account_id, new_acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wallet_core.last_synced_block = block_id;
|
||||
wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!(
|
||||
"Block at id {block_id} with timestamp {} parsed",
|
||||
block.timestamp
|
||||
);
|
||||
pub async fn send_privacy_preserving_tx(
|
||||
&self,
|
||||
accounts: Vec<PrivacyPreservingAccount>,
|
||||
instruction_data: &InstructionData,
|
||||
program: &Program,
|
||||
) -> Result<(SendTxResponse, Vec<SharedSecretKey>), ExecutionFailureKind> {
|
||||
self.send_privacy_preserving_tx_with_pre_check(accounts, instruction_data, program, |_| {
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub async fn send_privacy_preserving_tx_with_pre_check(
|
||||
&self,
|
||||
accounts: Vec<PrivacyPreservingAccount>,
|
||||
instruction_data: &InstructionData,
|
||||
program: &Program,
|
||||
tx_pre_check: impl FnOnce(&[&Account]) -> Result<(), ExecutionFailureKind>,
|
||||
) -> Result<(SendTxResponse, Vec<SharedSecretKey>), ExecutionFailureKind> {
|
||||
let acc_manager = privacy_preserving_tx::AccountManager::new(self, accounts).await?;
|
||||
|
||||
pub async fn execute_continious_run() -> Result<()> {
|
||||
let config = fetch_config().await?;
|
||||
let seq_client = Arc::new(SequencerClient::new(config.sequencer_addr.clone())?);
|
||||
let mut wallet_core = WalletCore::start_from_config_update_chain(config.clone()).await?;
|
||||
let pre_states = acc_manager.pre_states();
|
||||
tx_pre_check(
|
||||
&pre_states
|
||||
.iter()
|
||||
.map(|pre| &pre.account)
|
||||
.collect::<Vec<_>>(),
|
||||
)?;
|
||||
|
||||
let mut latest_block_num = seq_client.get_last_block().await?.last_block;
|
||||
let mut curr_last_block = latest_block_num;
|
||||
|
||||
loop {
|
||||
parse_block_range(
|
||||
curr_last_block,
|
||||
latest_block_num,
|
||||
seq_client.clone(),
|
||||
&mut wallet_core,
|
||||
let private_account_keys = acc_manager.private_account_keys();
|
||||
let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove(
|
||||
&pre_states,
|
||||
instruction_data,
|
||||
acc_manager.visibility_mask(),
|
||||
&produce_random_nonces(private_account_keys.len()),
|
||||
&private_account_keys
|
||||
.iter()
|
||||
.map(|keys| (keys.npk.clone(), keys.ssk.clone()))
|
||||
.collect::<Vec<_>>(),
|
||||
&acc_manager.private_account_auth(),
|
||||
program,
|
||||
)
|
||||
.await?;
|
||||
.unwrap();
|
||||
|
||||
curr_last_block = latest_block_num + 1;
|
||||
let message =
|
||||
nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output(
|
||||
acc_manager.public_account_ids(),
|
||||
Vec::from_iter(acc_manager.public_account_nonces()),
|
||||
private_account_keys
|
||||
.iter()
|
||||
.map(|keys| (keys.npk.clone(), keys.ipk.clone(), keys.epk.clone()))
|
||||
.collect(),
|
||||
output,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
tokio::time::sleep(std::time::Duration::from_millis(
|
||||
config.seq_poll_timeout_millis,
|
||||
let witness_set =
|
||||
nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message(
|
||||
&message,
|
||||
proof,
|
||||
&acc_manager.witness_signing_keys(),
|
||||
);
|
||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||
|
||||
let shared_secrets = private_account_keys
|
||||
.into_iter()
|
||||
.map(|keys| keys.ssk)
|
||||
.collect();
|
||||
|
||||
Ok((
|
||||
self.sequencer_client.send_tx_private(tx).await?,
|
||||
shared_secrets,
|
||||
))
|
||||
.await;
|
||||
|
||||
latest_block_num = seq_client.get_last_block().await?.last_block;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn execute_setup(password: String) -> Result<()> {
|
||||
let config = fetch_config().await?;
|
||||
let wallet_core = WalletCore::start_from_config_new_storage(config.clone(), password).await?;
|
||||
|
||||
wallet_core.store_persistent_data().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
use anyhow::Result;
|
||||
use clap::{CommandFactory, Parser};
|
||||
use clap::{CommandFactory as _, Parser as _};
|
||||
use tokio::runtime::Builder;
|
||||
use wallet::{Args, OverCommand, execute_continious_run, execute_setup, execute_subcommand};
|
||||
use wallet::cli::{Args, OverCommand, execute_continuous_run, execute_setup, execute_subcommand};
|
||||
|
||||
pub const NUM_THREADS: usize = 2;
|
||||
|
||||
// TODO #169: We have sample configs for sequencer, but not for wallet
|
||||
// TODO #168: Why it requires config as a directory? Maybe better to deduce directory from config
|
||||
// file path? TODO #172: Why it requires config as env var while sequencer_runner accepts as
|
||||
// argument? TODO #171: Running pinata doesn't give output about transaction hash and etc.
|
||||
// file path?
|
||||
// TODO #172: Why it requires config as env var while sequencer_runner accepts as
|
||||
// argument?
|
||||
// TODO #171: Running pinata doesn't give output about transaction hash and etc.
|
||||
fn main() -> Result<()> {
|
||||
let runtime = Builder::new_multi_thread()
|
||||
.worker_threads(NUM_THREADS)
|
||||
@ -21,22 +23,20 @@ fn main() -> Result<()> {
|
||||
env_logger::init();
|
||||
|
||||
runtime.block_on(async move {
|
||||
if let Some(overcommand) = args.command {
|
||||
match overcommand {
|
||||
if let Some(over_command) = args.command {
|
||||
match over_command {
|
||||
OverCommand::Command(command) => {
|
||||
execute_subcommand(command).await.unwrap();
|
||||
}
|
||||
OverCommand::Setup { password } => {
|
||||
execute_setup(password).await.unwrap();
|
||||
let _output = execute_subcommand(command).await?;
|
||||
Ok(())
|
||||
}
|
||||
OverCommand::Setup { password } => execute_setup(password).await,
|
||||
}
|
||||
} else if args.continious_run {
|
||||
execute_continious_run().await.unwrap();
|
||||
} else if args.continuous_run {
|
||||
execute_continuous_run().await
|
||||
} else {
|
||||
let help = Args::command().render_long_help();
|
||||
println!("{help}");
|
||||
Ok(())
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,161 +0,0 @@
|
||||
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
|
||||
use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder;
|
||||
use nssa::{AccountId, privacy_preserving_transaction::circuit};
|
||||
use nssa_core::{MembershipProof, SharedSecretKey, account::AccountWithMetadata};
|
||||
|
||||
use crate::{
|
||||
WalletCore, helperfunctions::produce_random_nonces, transaction_utils::AccountPreparedData,
|
||||
};
|
||||
|
||||
impl WalletCore {
|
||||
pub async fn claim_pinata(
|
||||
&self,
|
||||
pinata_account_id: AccountId,
|
||||
winner_account_id: AccountId,
|
||||
solution: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let account_ids = vec![pinata_account_id, winner_account_id];
|
||||
let program_id = nssa::program::Program::pinata().id();
|
||||
let message =
|
||||
nssa::public_transaction::Message::try_new(program_id, account_ids, vec![], solution)
|
||||
.unwrap();
|
||||
|
||||
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self.sequencer_client.send_tx_public(tx).await?)
|
||||
}
|
||||
|
||||
pub async fn claim_pinata_private_owned_account_already_initialized(
|
||||
&self,
|
||||
pinata_account_id: AccountId,
|
||||
winner_account_id: AccountId,
|
||||
solution: u128,
|
||||
winner_proof: MembershipProof,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
|
||||
let AccountPreparedData {
|
||||
nsk: winner_nsk,
|
||||
npk: winner_npk,
|
||||
ipk: winner_ipk,
|
||||
auth_acc: winner_pre,
|
||||
proof: _,
|
||||
} = self
|
||||
.private_acc_preparation(winner_account_id, true, false)
|
||||
.await?;
|
||||
|
||||
let pinata_acc = self.get_account_public(pinata_account_id).await.unwrap();
|
||||
|
||||
let program = nssa::program::Program::pinata();
|
||||
|
||||
let pinata_pre = AccountWithMetadata::new(pinata_acc.clone(), false, pinata_account_id);
|
||||
|
||||
let eph_holder_winner = EphemeralKeyHolder::new(&winner_npk);
|
||||
let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk);
|
||||
|
||||
let (output, proof) = circuit::execute_and_prove(
|
||||
&[pinata_pre, winner_pre],
|
||||
&nssa::program::Program::serialize_instruction(solution).unwrap(),
|
||||
&[0, 1],
|
||||
&produce_random_nonces(1),
|
||||
&[(winner_npk.clone(), shared_secret_winner.clone())],
|
||||
&[(winner_nsk.unwrap(), winner_proof)],
|
||||
&program,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let message =
|
||||
nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output(
|
||||
vec![pinata_account_id],
|
||||
vec![],
|
||||
vec![(
|
||||
winner_npk.clone(),
|
||||
winner_ipk.clone(),
|
||||
eph_holder_winner.generate_ephemeral_public_key(),
|
||||
)],
|
||||
output,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set =
|
||||
nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message(
|
||||
&message,
|
||||
proof,
|
||||
&[],
|
||||
);
|
||||
let tx = nssa::privacy_preserving_transaction::PrivacyPreservingTransaction::new(
|
||||
message,
|
||||
witness_set,
|
||||
);
|
||||
|
||||
Ok((
|
||||
self.sequencer_client.send_tx_private(tx).await?,
|
||||
[shared_secret_winner],
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn claim_pinata_private_owned_account_not_initialized(
|
||||
&self,
|
||||
pinata_account_id: AccountId,
|
||||
winner_account_id: AccountId,
|
||||
solution: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
|
||||
let AccountPreparedData {
|
||||
nsk: _,
|
||||
npk: winner_npk,
|
||||
ipk: winner_ipk,
|
||||
auth_acc: winner_pre,
|
||||
proof: _,
|
||||
} = self
|
||||
.private_acc_preparation(winner_account_id, false, false)
|
||||
.await?;
|
||||
|
||||
let pinata_acc = self.get_account_public(pinata_account_id).await.unwrap();
|
||||
|
||||
let program = nssa::program::Program::pinata();
|
||||
|
||||
let pinata_pre = AccountWithMetadata::new(pinata_acc.clone(), false, pinata_account_id);
|
||||
|
||||
let eph_holder_winner = EphemeralKeyHolder::new(&winner_npk);
|
||||
let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk);
|
||||
|
||||
let (output, proof) = circuit::execute_and_prove(
|
||||
&[pinata_pre, winner_pre],
|
||||
&nssa::program::Program::serialize_instruction(solution).unwrap(),
|
||||
&[0, 2],
|
||||
&produce_random_nonces(1),
|
||||
&[(winner_npk.clone(), shared_secret_winner.clone())],
|
||||
&[],
|
||||
&program,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let message =
|
||||
nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output(
|
||||
vec![pinata_account_id],
|
||||
vec![],
|
||||
vec![(
|
||||
winner_npk.clone(),
|
||||
winner_ipk.clone(),
|
||||
eph_holder_winner.generate_ephemeral_public_key(),
|
||||
)],
|
||||
output,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set =
|
||||
nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message(
|
||||
&message,
|
||||
proof,
|
||||
&[],
|
||||
);
|
||||
let tx = nssa::privacy_preserving_transaction::PrivacyPreservingTransaction::new(
|
||||
message,
|
||||
witness_set,
|
||||
);
|
||||
|
||||
Ok((
|
||||
self.sequencer_client.send_tx_private(tx).await?,
|
||||
[shared_secret_winner],
|
||||
))
|
||||
}
|
||||
}
|
||||
212
wallet/src/privacy_preserving_tx.rs
Normal file
212
wallet/src/privacy_preserving_tx.rs
Normal file
@ -0,0 +1,212 @@
|
||||
use common::error::ExecutionFailureKind;
|
||||
use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder;
|
||||
use nssa::{AccountId, PrivateKey};
|
||||
use nssa_core::{
|
||||
MembershipProof, NullifierPublicKey, NullifierSecretKey, SharedSecretKey,
|
||||
account::{AccountWithMetadata, Nonce},
|
||||
encryption::{EphemeralPublicKey, IncomingViewingPublicKey},
|
||||
};
|
||||
|
||||
use crate::WalletCore;
|
||||
|
||||
pub enum PrivacyPreservingAccount {
|
||||
Public(AccountId),
|
||||
PrivateOwned(AccountId),
|
||||
PrivateForeign {
|
||||
npk: NullifierPublicKey,
|
||||
ipk: IncomingViewingPublicKey,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct PrivateAccountKeys {
|
||||
pub npk: NullifierPublicKey,
|
||||
pub ssk: SharedSecretKey,
|
||||
pub ipk: IncomingViewingPublicKey,
|
||||
pub epk: EphemeralPublicKey,
|
||||
}
|
||||
|
||||
enum State {
|
||||
Public {
|
||||
account: AccountWithMetadata,
|
||||
sk: Option<PrivateKey>,
|
||||
},
|
||||
Private(AccountPreparedData),
|
||||
}
|
||||
|
||||
pub struct AccountManager {
|
||||
states: Vec<State>,
|
||||
visibility_mask: Vec<u8>,
|
||||
}
|
||||
|
||||
impl AccountManager {
|
||||
pub async fn new(
|
||||
wallet: &WalletCore,
|
||||
accounts: Vec<PrivacyPreservingAccount>,
|
||||
) -> Result<Self, ExecutionFailureKind> {
|
||||
let mut pre_states = Vec::with_capacity(accounts.len());
|
||||
let mut visibility_mask = Vec::with_capacity(accounts.len());
|
||||
|
||||
for account in accounts {
|
||||
let (state, mask) = match account {
|
||||
PrivacyPreservingAccount::Public(account_id) => {
|
||||
let acc = wallet
|
||||
.get_account_public(account_id)
|
||||
.await
|
||||
.map_err(|_| ExecutionFailureKind::KeyNotFoundError)?;
|
||||
|
||||
let sk = wallet.get_account_public_signing_key(&account_id).cloned();
|
||||
let account = AccountWithMetadata::new(acc.clone(), sk.is_some(), account_id);
|
||||
|
||||
(State::Public { account, sk }, 0)
|
||||
}
|
||||
PrivacyPreservingAccount::PrivateOwned(account_id) => {
|
||||
let pre = private_acc_preparation(wallet, account_id).await?;
|
||||
let mask = if pre.auth_acc.is_authorized { 1 } else { 2 };
|
||||
|
||||
(State::Private(pre), mask)
|
||||
}
|
||||
PrivacyPreservingAccount::PrivateForeign { npk, ipk } => {
|
||||
let acc = nssa_core::account::Account::default();
|
||||
let auth_acc = AccountWithMetadata::new(acc, false, &npk);
|
||||
let pre = AccountPreparedData {
|
||||
nsk: None,
|
||||
npk,
|
||||
ipk,
|
||||
auth_acc,
|
||||
proof: None,
|
||||
};
|
||||
|
||||
(State::Private(pre), 2)
|
||||
}
|
||||
};
|
||||
|
||||
pre_states.push(state);
|
||||
visibility_mask.push(mask);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
states: pre_states,
|
||||
visibility_mask,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn pre_states(&self) -> Vec<AccountWithMetadata> {
|
||||
self.states
|
||||
.iter()
|
||||
.map(|state| match state {
|
||||
State::Public { account, .. } => account.clone(),
|
||||
State::Private(pre) => pre.auth_acc.clone(),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn visibility_mask(&self) -> &[u8] {
|
||||
&self.visibility_mask
|
||||
}
|
||||
|
||||
pub fn public_account_nonces(&self) -> Vec<Nonce> {
|
||||
self.states
|
||||
.iter()
|
||||
.filter_map(|state| match state {
|
||||
State::Public { account, sk } => sk.as_ref().map(|_| account.account.nonce),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn private_account_keys(&self) -> Vec<PrivateAccountKeys> {
|
||||
self.states
|
||||
.iter()
|
||||
.filter_map(|state| match state {
|
||||
State::Private(pre) => {
|
||||
let eph_holder = EphemeralKeyHolder::new(&pre.npk);
|
||||
|
||||
Some(PrivateAccountKeys {
|
||||
npk: pre.npk.clone(),
|
||||
ssk: eph_holder.calculate_shared_secret_sender(&pre.ipk),
|
||||
ipk: pre.ipk.clone(),
|
||||
epk: eph_holder.generate_ephemeral_public_key(),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn private_account_auth(&self) -> Vec<(NullifierSecretKey, MembershipProof)> {
|
||||
self.states
|
||||
.iter()
|
||||
.filter_map(|state| match state {
|
||||
State::Private(pre) => Some((pre.nsk?, pre.proof.clone()?)),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn public_account_ids(&self) -> Vec<AccountId> {
|
||||
self.states
|
||||
.iter()
|
||||
.filter_map(|state| match state {
|
||||
State::Public { account, .. } => Some(account.account_id),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn witness_signing_keys(&self) -> Vec<&PrivateKey> {
|
||||
self.states
|
||||
.iter()
|
||||
.filter_map(|state| match state {
|
||||
State::Public { sk, .. } => sk.as_ref(),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
struct AccountPreparedData {
|
||||
nsk: Option<NullifierSecretKey>,
|
||||
npk: NullifierPublicKey,
|
||||
ipk: IncomingViewingPublicKey,
|
||||
auth_acc: AccountWithMetadata,
|
||||
proof: Option<MembershipProof>,
|
||||
}
|
||||
|
||||
async fn private_acc_preparation(
|
||||
wallet: &WalletCore,
|
||||
account_id: AccountId,
|
||||
) -> Result<AccountPreparedData, ExecutionFailureKind> {
|
||||
let Some((from_keys, from_acc)) = wallet
|
||||
.storage
|
||||
.user_data
|
||||
.get_private_account(&account_id)
|
||||
.cloned()
|
||||
else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let mut nsk = Some(from_keys.private_key_holder.nullifier_secret_key);
|
||||
|
||||
let from_npk = from_keys.nullifer_public_key;
|
||||
let from_ipk = from_keys.incoming_viewing_public_key;
|
||||
|
||||
// TODO: Remove this unwrap, error types must be compatible
|
||||
let proof = wallet
|
||||
.check_private_account_initialized(&account_id)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
if proof.is_none() {
|
||||
nsk = None;
|
||||
}
|
||||
|
||||
let sender_pre = AccountWithMetadata::new(from_acc.clone(), proof.is_some(), &from_npk);
|
||||
|
||||
Ok(AccountPreparedData {
|
||||
nsk,
|
||||
npk: from_npk,
|
||||
ipk: from_ipk,
|
||||
auth_acc: sender_pre,
|
||||
proof,
|
||||
})
|
||||
}
|
||||
6
wallet/src/program_facades/mod.rs
Normal file
6
wallet/src/program_facades/mod.rs
Normal file
@ -0,0 +1,6 @@
|
||||
//! This module contains [`WalletCore`](crate::WalletCore) facades for interacting with various
|
||||
//! on-chain programs.
|
||||
|
||||
pub mod native_token_transfer;
|
||||
pub mod pinata;
|
||||
pub mod token;
|
||||
@ -0,0 +1,35 @@
|
||||
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
|
||||
use nssa::AccountId;
|
||||
|
||||
use super::{NativeTokenTransfer, auth_transfer_preparation};
|
||||
use crate::PrivacyPreservingAccount;
|
||||
|
||||
impl NativeTokenTransfer<'_> {
|
||||
pub async fn send_deshielded_transfer(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to: AccountId,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx_with_pre_check(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivateOwned(from),
|
||||
PrivacyPreservingAccount::Public(to),
|
||||
],
|
||||
&instruction_data,
|
||||
&program,
|
||||
tx_pre_check,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected sender's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
}
|
||||
33
wallet/src/program_facades/native_token_transfer/mod.rs
Normal file
33
wallet/src/program_facades/native_token_transfer/mod.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use common::error::ExecutionFailureKind;
|
||||
use nssa::{Account, program::Program};
|
||||
use nssa_core::program::InstructionData;
|
||||
|
||||
use crate::WalletCore;
|
||||
|
||||
pub mod deshielded;
|
||||
pub mod private;
|
||||
pub mod public;
|
||||
pub mod shielded;
|
||||
|
||||
pub struct NativeTokenTransfer<'w>(pub &'w WalletCore);
|
||||
|
||||
fn auth_transfer_preparation(
|
||||
balance_to_move: u128,
|
||||
) -> (
|
||||
InstructionData,
|
||||
Program,
|
||||
impl FnOnce(&[&Account]) -> Result<(), ExecutionFailureKind>,
|
||||
) {
|
||||
let instruction_data = Program::serialize_instruction(balance_to_move).unwrap();
|
||||
let program = Program::authenticated_transfer_program();
|
||||
let tx_pre_check = move |accounts: &[&Account]| {
|
||||
let from = accounts[0];
|
||||
if from.balance >= balance_to_move {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||
}
|
||||
};
|
||||
|
||||
(instruction_data, program, tx_pre_check)
|
||||
}
|
||||
89
wallet/src/program_facades/native_token_transfer/private.rs
Normal file
89
wallet/src/program_facades/native_token_transfer/private.rs
Normal file
@ -0,0 +1,89 @@
|
||||
use std::vec;
|
||||
|
||||
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
|
||||
use nssa::{AccountId, program::Program};
|
||||
use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey};
|
||||
|
||||
use super::{NativeTokenTransfer, auth_transfer_preparation};
|
||||
use crate::PrivacyPreservingAccount;
|
||||
|
||||
impl NativeTokenTransfer<'_> {
|
||||
pub async fn register_account_private(
|
||||
&self,
|
||||
from: AccountId,
|
||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||
let instruction: u128 = 0;
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx_with_pre_check(
|
||||
vec![PrivacyPreservingAccount::PrivateOwned(from)],
|
||||
&Program::serialize_instruction(instruction).unwrap(),
|
||||
&Program::authenticated_transfer_program(),
|
||||
|_| Ok(()),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let mut secrets_iter = secrets.into_iter();
|
||||
let first = secrets_iter.next().expect("expected sender's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_private_transfer_to_outer_account(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to_npk: NullifierPublicKey,
|
||||
to_ipk: IncomingViewingPublicKey,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx_with_pre_check(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivateOwned(from),
|
||||
PrivacyPreservingAccount::PrivateForeign {
|
||||
npk: to_npk,
|
||||
ipk: to_ipk,
|
||||
},
|
||||
],
|
||||
&instruction_data,
|
||||
&program,
|
||||
tx_pre_check,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let mut secrets_iter = secrets.into_iter();
|
||||
let first = secrets_iter.next().expect("expected sender's secret");
|
||||
let second = secrets_iter.next().expect("expected receiver's secret");
|
||||
(resp, [first, second])
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_private_transfer_to_owned_account(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to: AccountId,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx_with_pre_check(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivateOwned(from),
|
||||
PrivacyPreservingAccount::PrivateOwned(to),
|
||||
],
|
||||
&instruction_data,
|
||||
&program,
|
||||
tx_pre_check,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let mut secrets_iter = secrets.into_iter();
|
||||
let first = secrets_iter.next().expect("expected sender's secret");
|
||||
let second = secrets_iter.next().expect("expected receiver's secret");
|
||||
(resp, [first, second])
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -5,21 +5,21 @@ use nssa::{
|
||||
public_transaction::{Message, WitnessSet},
|
||||
};
|
||||
|
||||
use crate::WalletCore;
|
||||
use super::NativeTokenTransfer;
|
||||
|
||||
impl WalletCore {
|
||||
pub async fn send_public_native_token_transfer(
|
||||
impl NativeTokenTransfer<'_> {
|
||||
pub async fn send_public_transfer(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to: AccountId,
|
||||
balance_to_move: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let Ok(balance) = self.get_account_balance(from).await else {
|
||||
let Ok(balance) = self.0.get_account_balance(from).await else {
|
||||
return Err(ExecutionFailureKind::SequencerError);
|
||||
};
|
||||
|
||||
if balance >= balance_to_move {
|
||||
let Ok(nonces) = self.get_accounts_nonces(vec![from]).await else {
|
||||
let Ok(nonces) = self.0.get_accounts_nonces(vec![from]).await else {
|
||||
return Err(ExecutionFailureKind::SequencerError);
|
||||
};
|
||||
|
||||
@ -28,7 +28,7 @@ impl WalletCore {
|
||||
let message =
|
||||
Message::try_new(program_id, account_ids, nonces, balance_to_move).unwrap();
|
||||
|
||||
let signing_key = self.storage.user_data.get_pub_account_signing_key(&from);
|
||||
let signing_key = self.0.storage.user_data.get_pub_account_signing_key(&from);
|
||||
|
||||
let Some(signing_key) = signing_key else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
@ -38,17 +38,17 @@ impl WalletCore {
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self.sequencer_client.send_tx_public(tx).await?)
|
||||
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
|
||||
} else {
|
||||
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn register_account_under_authenticated_transfers_programs(
|
||||
pub async fn register_account(
|
||||
&self,
|
||||
from: AccountId,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let Ok(nonces) = self.get_accounts_nonces(vec![from]).await else {
|
||||
let Ok(nonces) = self.0.get_accounts_nonces(vec![from]).await else {
|
||||
return Err(ExecutionFailureKind::SequencerError);
|
||||
};
|
||||
|
||||
@ -57,7 +57,7 @@ impl WalletCore {
|
||||
let program_id = Program::authenticated_transfer_program().id();
|
||||
let message = Message::try_new(program_id, account_ids, nonces, instruction).unwrap();
|
||||
|
||||
let signing_key = self.storage.user_data.get_pub_account_signing_key(&from);
|
||||
let signing_key = self.0.storage.user_data.get_pub_account_signing_key(&from);
|
||||
|
||||
let Some(signing_key) = signing_key else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
@ -67,6 +67,6 @@ impl WalletCore {
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self.sequencer_client.send_tx_public(tx).await?)
|
||||
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
|
||||
}
|
||||
}
|
||||
68
wallet/src/program_facades/native_token_transfer/shielded.rs
Normal file
68
wallet/src/program_facades/native_token_transfer/shielded.rs
Normal file
@ -0,0 +1,68 @@
|
||||
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
|
||||
use nssa::AccountId;
|
||||
use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey};
|
||||
|
||||
use super::{NativeTokenTransfer, auth_transfer_preparation};
|
||||
use crate::PrivacyPreservingAccount;
|
||||
|
||||
impl NativeTokenTransfer<'_> {
|
||||
pub async fn send_shielded_transfer(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to: AccountId,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx_with_pre_check(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(from),
|
||||
PrivacyPreservingAccount::PrivateOwned(to),
|
||||
],
|
||||
&instruction_data,
|
||||
&program,
|
||||
tx_pre_check,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected sender's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_shielded_transfer_to_outer_account(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to_npk: NullifierPublicKey,
|
||||
to_ipk: IncomingViewingPublicKey,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx_with_pre_check(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(from),
|
||||
PrivacyPreservingAccount::PrivateForeign {
|
||||
npk: to_npk,
|
||||
ipk: to_ipk,
|
||||
},
|
||||
],
|
||||
&instruction_data,
|
||||
&program,
|
||||
tx_pre_check,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected sender's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
}
|
||||
52
wallet/src/program_facades/pinata.rs
Normal file
52
wallet/src/program_facades/pinata.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
|
||||
use nssa::AccountId;
|
||||
use nssa_core::SharedSecretKey;
|
||||
|
||||
use crate::{PrivacyPreservingAccount, WalletCore};
|
||||
|
||||
pub struct Pinata<'w>(pub &'w WalletCore);
|
||||
|
||||
impl Pinata<'_> {
|
||||
pub async fn claim(
|
||||
&self,
|
||||
pinata_account_id: AccountId,
|
||||
winner_account_id: AccountId,
|
||||
solution: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let account_ids = vec![pinata_account_id, winner_account_id];
|
||||
let program_id = nssa::program::Program::pinata().id();
|
||||
let message =
|
||||
nssa::public_transaction::Message::try_new(program_id, account_ids, vec![], solution)
|
||||
.unwrap();
|
||||
|
||||
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
|
||||
}
|
||||
|
||||
pub async fn claim_private_owned_account(
|
||||
&self,
|
||||
pinata_account_id: AccountId,
|
||||
winner_account_id: AccountId,
|
||||
solution: u128,
|
||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(pinata_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(winner_account_id),
|
||||
],
|
||||
&nssa::program::Program::serialize_instruction(solution).unwrap(),
|
||||
&nssa::program::Program::pinata(),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected recipient's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
}
|
||||
275
wallet/src/program_facades/token.rs
Normal file
275
wallet/src/program_facades/token.rs
Normal file
@ -0,0 +1,275 @@
|
||||
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
|
||||
use nssa::{AccountId, program::Program};
|
||||
use nssa_core::{
|
||||
NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey,
|
||||
program::InstructionData,
|
||||
};
|
||||
|
||||
use crate::{PrivacyPreservingAccount, WalletCore};
|
||||
|
||||
pub struct Token<'w>(pub &'w WalletCore);
|
||||
|
||||
impl Token<'_> {
|
||||
pub async fn send_new_definition(
|
||||
&self,
|
||||
definition_account_id: AccountId,
|
||||
supply_account_id: AccountId,
|
||||
name: [u8; 6],
|
||||
total_supply: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let account_ids = vec![definition_account_id, supply_account_id];
|
||||
let program_id = nssa::program::Program::token().id();
|
||||
// Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)]
|
||||
let mut instruction = [0; 23];
|
||||
instruction[1..17].copy_from_slice(&total_supply.to_le_bytes());
|
||||
instruction[17..].copy_from_slice(&name);
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program_id,
|
||||
account_ids,
|
||||
vec![],
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
|
||||
}
|
||||
|
||||
pub async fn send_new_definition_private_owned(
|
||||
&self,
|
||||
definition_account_id: AccountId,
|
||||
supply_account_id: AccountId,
|
||||
name: [u8; 6],
|
||||
total_supply: u128,
|
||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||
let (instruction_data, program) = token_program_preparation_definition(name, total_supply);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(definition_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(supply_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
&program,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected recipient's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_transfer_transaction(
|
||||
&self,
|
||||
sender_account_id: AccountId,
|
||||
recipient_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let account_ids = vec![sender_account_id, recipient_account_id];
|
||||
let program_id = nssa::program::Program::token().id();
|
||||
// Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 ||
|
||||
// 0x00 || 0x00 || 0x00].
|
||||
let mut instruction = [0; 23];
|
||||
instruction[0] = 0x01;
|
||||
instruction[1..17].copy_from_slice(&amount.to_le_bytes());
|
||||
let Ok(nonces) = self.0.get_accounts_nonces(vec![sender_account_id]).await else {
|
||||
return Err(ExecutionFailureKind::SequencerError);
|
||||
};
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program_id,
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let Some(signing_key) = self
|
||||
.0
|
||||
.storage
|
||||
.user_data
|
||||
.get_pub_account_signing_key(&sender_account_id)
|
||||
else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
|
||||
}
|
||||
|
||||
pub async fn send_transfer_transaction_private_owned_account(
|
||||
&self,
|
||||
sender_account_id: AccountId,
|
||||
recipient_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let (instruction_data, program) = token_program_preparation_transfer(amount);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivateOwned(sender_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(recipient_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
&program,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let mut iter = secrets.into_iter();
|
||||
let first = iter.next().expect("expected sender's secret");
|
||||
let second = iter.next().expect("expected recipient's secret");
|
||||
(resp, [first, second])
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_transfer_transaction_private_foreign_account(
|
||||
&self,
|
||||
sender_account_id: AccountId,
|
||||
recipient_npk: NullifierPublicKey,
|
||||
recipient_ipk: IncomingViewingPublicKey,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let (instruction_data, program) = token_program_preparation_transfer(amount);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivateOwned(sender_account_id),
|
||||
PrivacyPreservingAccount::PrivateForeign {
|
||||
npk: recipient_npk,
|
||||
ipk: recipient_ipk,
|
||||
},
|
||||
],
|
||||
&instruction_data,
|
||||
&program,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let mut iter = secrets.into_iter();
|
||||
let first = iter.next().expect("expected sender's secret");
|
||||
let second = iter.next().expect("expected recipient's secret");
|
||||
(resp, [first, second])
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_transfer_transaction_deshielded(
|
||||
&self,
|
||||
sender_account_id: AccountId,
|
||||
recipient_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||
let (instruction_data, program) = token_program_preparation_transfer(amount);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivateOwned(sender_account_id),
|
||||
PrivacyPreservingAccount::Public(recipient_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
&program,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected sender's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_transfer_transaction_shielded_owned_account(
|
||||
&self,
|
||||
sender_account_id: AccountId,
|
||||
recipient_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||
let (instruction_data, program) = token_program_preparation_transfer(amount);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(sender_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(recipient_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
&program,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected recipient's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_transfer_transaction_shielded_foreign_account(
|
||||
&self,
|
||||
sender_account_id: AccountId,
|
||||
recipient_npk: NullifierPublicKey,
|
||||
recipient_ipk: IncomingViewingPublicKey,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||
let (instruction_data, program) = token_program_preparation_transfer(amount);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(sender_account_id),
|
||||
PrivacyPreservingAccount::PrivateForeign {
|
||||
npk: recipient_npk,
|
||||
ipk: recipient_ipk,
|
||||
},
|
||||
],
|
||||
&instruction_data,
|
||||
&program,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected recipient's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn token_program_preparation_transfer(amount: u128) -> (InstructionData, Program) {
|
||||
// Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 ||
|
||||
// 0x00 || 0x00 || 0x00].
|
||||
let mut instruction = [0; 23];
|
||||
instruction[0] = 0x01;
|
||||
instruction[1..17].copy_from_slice(&amount.to_le_bytes());
|
||||
let instruction_data = Program::serialize_instruction(instruction).unwrap();
|
||||
let program = Program::token();
|
||||
|
||||
(instruction_data, program)
|
||||
}
|
||||
|
||||
fn token_program_preparation_definition(
|
||||
name: [u8; 6],
|
||||
total_supply: u128,
|
||||
) -> (InstructionData, Program) {
|
||||
// Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)]
|
||||
let mut instruction = [0; 23];
|
||||
instruction[1..17].copy_from_slice(&total_supply.to_le_bytes());
|
||||
instruction[17..].copy_from_slice(&name);
|
||||
let instruction_data = Program::serialize_instruction(instruction).unwrap();
|
||||
let program = Program::token();
|
||||
|
||||
(instruction_data, program)
|
||||
}
|
||||
@ -1,278 +0,0 @@
|
||||
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
|
||||
use nssa::{Account, AccountId, program::Program};
|
||||
use nssa_core::{
|
||||
MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey,
|
||||
program::InstructionData,
|
||||
};
|
||||
|
||||
use crate::WalletCore;
|
||||
|
||||
impl WalletCore {
|
||||
pub fn token_program_preparation_transfer(
|
||||
amount: u128,
|
||||
) -> (
|
||||
InstructionData,
|
||||
Program,
|
||||
impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
|
||||
) {
|
||||
// Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 ||
|
||||
// 0x00 || 0x00 || 0x00].
|
||||
let mut instruction = [0; 23];
|
||||
instruction[0] = 0x01;
|
||||
instruction[1..17].copy_from_slice(&amount.to_le_bytes());
|
||||
let instruction_data = Program::serialize_instruction(instruction).unwrap();
|
||||
let program = Program::token();
|
||||
let tx_pre_check = |_: &Account, _: &Account| Ok(());
|
||||
|
||||
(instruction_data, program, tx_pre_check)
|
||||
}
|
||||
|
||||
pub fn token_program_preparation_definition(
|
||||
name: [u8; 6],
|
||||
total_supply: u128,
|
||||
) -> (
|
||||
InstructionData,
|
||||
Program,
|
||||
impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
|
||||
) {
|
||||
// Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)]
|
||||
let mut instruction = [0; 23];
|
||||
instruction[1..17].copy_from_slice(&total_supply.to_le_bytes());
|
||||
instruction[17..].copy_from_slice(&name);
|
||||
let instruction_data = Program::serialize_instruction(instruction).unwrap();
|
||||
let program = Program::token();
|
||||
let tx_pre_check = |_: &Account, _: &Account| Ok(());
|
||||
|
||||
(instruction_data, program, tx_pre_check)
|
||||
}
|
||||
|
||||
pub async fn send_new_token_definition(
|
||||
&self,
|
||||
definition_account_id: AccountId,
|
||||
supply_account_id: AccountId,
|
||||
name: [u8; 6],
|
||||
total_supply: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let account_ids = vec![definition_account_id, supply_account_id];
|
||||
let program_id = nssa::program::Program::token().id();
|
||||
// Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)]
|
||||
let mut instruction = [0; 23];
|
||||
instruction[1..17].copy_from_slice(&total_supply.to_le_bytes());
|
||||
instruction[17..].copy_from_slice(&name);
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program_id,
|
||||
account_ids,
|
||||
vec![],
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self.sequencer_client.send_tx_public(tx).await?)
|
||||
}
|
||||
|
||||
pub async fn send_new_token_definition_private_owned(
|
||||
&self,
|
||||
definition_account_id: AccountId,
|
||||
supply_account_id: AccountId,
|
||||
name: [u8; 6],
|
||||
total_supply: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) =
|
||||
WalletCore::token_program_preparation_definition(name, total_supply);
|
||||
|
||||
// Kind of non-obvious naming
|
||||
// Basically this funtion is called because authentication mask is [0, 2]
|
||||
self.shielded_two_accs_receiver_uninit(
|
||||
definition_account_id,
|
||||
supply_account_id,
|
||||
instruction_data,
|
||||
tx_pre_check,
|
||||
program,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_transfer_token_transaction(
|
||||
&self,
|
||||
sender_account_id: AccountId,
|
||||
recipient_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let account_ids = vec![sender_account_id, recipient_account_id];
|
||||
let program_id = nssa::program::Program::token().id();
|
||||
// Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 ||
|
||||
// 0x00 || 0x00 || 0x00].
|
||||
let mut instruction = [0; 23];
|
||||
instruction[0] = 0x01;
|
||||
instruction[1..17].copy_from_slice(&amount.to_le_bytes());
|
||||
let Ok(nonces) = self.get_accounts_nonces(vec![sender_account_id]).await else {
|
||||
return Err(ExecutionFailureKind::SequencerError);
|
||||
};
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program_id,
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let Some(signing_key) = self
|
||||
.storage
|
||||
.user_data
|
||||
.get_pub_account_signing_key(&sender_account_id)
|
||||
else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self.sequencer_client.send_tx_public(tx).await?)
|
||||
}
|
||||
|
||||
pub async fn send_transfer_token_transaction_private_owned_account_already_initialized(
|
||||
&self,
|
||||
sender_account_id: AccountId,
|
||||
recipient_account_id: AccountId,
|
||||
amount: u128,
|
||||
recipient_proof: MembershipProof,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) =
|
||||
WalletCore::token_program_preparation_transfer(amount);
|
||||
|
||||
self.private_tx_two_accs_all_init(
|
||||
sender_account_id,
|
||||
recipient_account_id,
|
||||
instruction_data,
|
||||
tx_pre_check,
|
||||
program,
|
||||
recipient_proof,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_transfer_token_transaction_private_owned_account_not_initialized(
|
||||
&self,
|
||||
sender_account_id: AccountId,
|
||||
recipient_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) =
|
||||
WalletCore::token_program_preparation_transfer(amount);
|
||||
|
||||
self.private_tx_two_accs_receiver_uninit(
|
||||
sender_account_id,
|
||||
recipient_account_id,
|
||||
instruction_data,
|
||||
tx_pre_check,
|
||||
program,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_transfer_token_transaction_private_foreign_account(
|
||||
&self,
|
||||
sender_account_id: AccountId,
|
||||
recipient_npk: NullifierPublicKey,
|
||||
recipient_ipk: IncomingViewingPublicKey,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) =
|
||||
WalletCore::token_program_preparation_transfer(amount);
|
||||
|
||||
self.private_tx_two_accs_receiver_outer(
|
||||
sender_account_id,
|
||||
recipient_npk,
|
||||
recipient_ipk,
|
||||
instruction_data,
|
||||
tx_pre_check,
|
||||
program,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_transfer_token_transaction_deshielded(
|
||||
&self,
|
||||
sender_account_id: AccountId,
|
||||
recipient_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) =
|
||||
WalletCore::token_program_preparation_transfer(amount);
|
||||
|
||||
self.deshielded_tx_two_accs(
|
||||
sender_account_id,
|
||||
recipient_account_id,
|
||||
instruction_data,
|
||||
tx_pre_check,
|
||||
program,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_transfer_token_transaction_shielded_owned_account_already_initialized(
|
||||
&self,
|
||||
sender_account_id: AccountId,
|
||||
recipient_account_id: AccountId,
|
||||
amount: u128,
|
||||
recipient_proof: MembershipProof,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) =
|
||||
WalletCore::token_program_preparation_transfer(amount);
|
||||
|
||||
self.shielded_two_accs_all_init(
|
||||
sender_account_id,
|
||||
recipient_account_id,
|
||||
instruction_data,
|
||||
tx_pre_check,
|
||||
program,
|
||||
recipient_proof,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_transfer_token_transaction_shielded_owned_account_not_initialized(
|
||||
&self,
|
||||
sender_account_id: AccountId,
|
||||
recipient_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) =
|
||||
WalletCore::token_program_preparation_transfer(amount);
|
||||
|
||||
self.shielded_two_accs_receiver_uninit(
|
||||
sender_account_id,
|
||||
recipient_account_id,
|
||||
instruction_data,
|
||||
tx_pre_check,
|
||||
program,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_transfer_token_transaction_shielded_foreign_account(
|
||||
&self,
|
||||
sender_account_id: AccountId,
|
||||
recipient_npk: NullifierPublicKey,
|
||||
recipient_ipk: IncomingViewingPublicKey,
|
||||
amount: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) =
|
||||
WalletCore::token_program_preparation_transfer(amount);
|
||||
|
||||
self.shielded_two_accs_receiver_outer(
|
||||
sender_account_id,
|
||||
recipient_npk,
|
||||
recipient_ipk,
|
||||
instruction_data,
|
||||
tx_pre_check,
|
||||
program,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
|
||||
use nssa::AccountId;
|
||||
|
||||
use crate::WalletCore;
|
||||
|
||||
impl WalletCore {
|
||||
pub async fn send_deshielded_native_token_transfer(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to: AccountId,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 1]), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) =
|
||||
WalletCore::auth_transfer_preparation(balance_to_move);
|
||||
|
||||
self.deshielded_tx_two_accs(from, to, instruction_data, tx_pre_check, program)
|
||||
.await
|
||||
}
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
use common::error::ExecutionFailureKind;
|
||||
use nssa::{Account, program::Program};
|
||||
use nssa_core::program::InstructionData;
|
||||
|
||||
use crate::WalletCore;
|
||||
|
||||
pub mod deshielded;
|
||||
pub mod private;
|
||||
pub mod public;
|
||||
pub mod shielded;
|
||||
|
||||
impl WalletCore {
|
||||
pub fn auth_transfer_preparation(
|
||||
balance_to_move: u128,
|
||||
) -> (
|
||||
InstructionData,
|
||||
Program,
|
||||
impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
|
||||
) {
|
||||
let instruction_data = Program::serialize_instruction(balance_to_move).unwrap();
|
||||
let program = Program::authenticated_transfer_program();
|
||||
let tx_pre_check = move |from: &Account, _: &Account| {
|
||||
if from.balance >= balance_to_move {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||
}
|
||||
};
|
||||
|
||||
(instruction_data, program, tx_pre_check)
|
||||
}
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
|
||||
use nssa::AccountId;
|
||||
use nssa_core::{
|
||||
MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey,
|
||||
};
|
||||
|
||||
use crate::WalletCore;
|
||||
|
||||
impl WalletCore {
|
||||
pub async fn send_private_native_token_transfer_outer_account(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to_npk: NullifierPublicKey,
|
||||
to_ipk: IncomingViewingPublicKey,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) =
|
||||
WalletCore::auth_transfer_preparation(balance_to_move);
|
||||
|
||||
self.private_tx_two_accs_receiver_outer(
|
||||
from,
|
||||
to_npk,
|
||||
to_ipk,
|
||||
instruction_data,
|
||||
tx_pre_check,
|
||||
program,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_private_native_token_transfer_owned_account_not_initialized(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to: AccountId,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) =
|
||||
WalletCore::auth_transfer_preparation(balance_to_move);
|
||||
|
||||
self.private_tx_two_accs_receiver_uninit(from, to, instruction_data, tx_pre_check, program)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_private_native_token_transfer_owned_account_already_initialized(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to: AccountId,
|
||||
balance_to_move: u128,
|
||||
to_proof: MembershipProof,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) =
|
||||
WalletCore::auth_transfer_preparation(balance_to_move);
|
||||
|
||||
self.private_tx_two_accs_all_init(
|
||||
from,
|
||||
to,
|
||||
instruction_data,
|
||||
tx_pre_check,
|
||||
program,
|
||||
to_proof,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
|
||||
use nssa::AccountId;
|
||||
use nssa_core::{
|
||||
MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey,
|
||||
};
|
||||
|
||||
use crate::WalletCore;
|
||||
|
||||
impl WalletCore {
|
||||
pub async fn send_shielded_native_token_transfer_already_initialized(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to: AccountId,
|
||||
balance_to_move: u128,
|
||||
to_proof: MembershipProof,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) =
|
||||
WalletCore::auth_transfer_preparation(balance_to_move);
|
||||
|
||||
self.shielded_two_accs_all_init(from, to, instruction_data, tx_pre_check, program, to_proof)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_shielded_native_token_transfer_not_initialized(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to: AccountId,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) =
|
||||
WalletCore::auth_transfer_preparation(balance_to_move);
|
||||
|
||||
self.shielded_two_accs_receiver_uninit(from, to, instruction_data, tx_pre_check, program)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_shielded_native_token_transfer_outer_account(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to_npk: NullifierPublicKey,
|
||||
to_ipk: IncomingViewingPublicKey,
|
||||
balance_to_move: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) =
|
||||
WalletCore::auth_transfer_preparation(balance_to_move);
|
||||
|
||||
self.shielded_two_accs_receiver_outer(
|
||||
from,
|
||||
to_npk,
|
||||
to_ipk,
|
||||
instruction_data,
|
||||
tx_pre_check,
|
||||
program,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
@ -1,592 +0,0 @@
|
||||
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
|
||||
use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder;
|
||||
use nssa::{
|
||||
Account, AccountId, PrivacyPreservingTransaction,
|
||||
privacy_preserving_transaction::{circuit, message::Message, witness_set::WitnessSet},
|
||||
program::Program,
|
||||
};
|
||||
use nssa_core::{
|
||||
Commitment, MembershipProof, NullifierPublicKey, NullifierSecretKey, SharedSecretKey,
|
||||
account::AccountWithMetadata, encryption::IncomingViewingPublicKey, program::InstructionData,
|
||||
};
|
||||
|
||||
use crate::{WalletCore, helperfunctions::produce_random_nonces};
|
||||
|
||||
pub(crate) struct AccountPreparedData {
|
||||
pub nsk: Option<NullifierSecretKey>,
|
||||
pub npk: NullifierPublicKey,
|
||||
pub ipk: IncomingViewingPublicKey,
|
||||
pub auth_acc: AccountWithMetadata,
|
||||
pub proof: Option<MembershipProof>,
|
||||
}
|
||||
|
||||
impl WalletCore {
|
||||
pub(crate) async fn private_acc_preparation(
|
||||
&self,
|
||||
account_id: AccountId,
|
||||
is_authorized: bool,
|
||||
needs_proof: bool,
|
||||
) -> Result<AccountPreparedData, ExecutionFailureKind> {
|
||||
let Some((from_keys, from_acc)) = self
|
||||
.storage
|
||||
.user_data
|
||||
.get_private_account(&account_id)
|
||||
.cloned()
|
||||
else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let mut nsk = None;
|
||||
let mut proof = None;
|
||||
|
||||
let from_npk = from_keys.nullifer_public_key;
|
||||
let from_ipk = from_keys.incoming_viewing_public_key;
|
||||
|
||||
let sender_commitment = Commitment::new(&from_npk, &from_acc);
|
||||
|
||||
let sender_pre = AccountWithMetadata::new(from_acc.clone(), is_authorized, &from_npk);
|
||||
|
||||
if is_authorized {
|
||||
nsk = Some(from_keys.private_key_holder.nullifier_secret_key);
|
||||
}
|
||||
|
||||
if needs_proof {
|
||||
proof = self
|
||||
.sequencer_client
|
||||
.get_proof_for_commitment(sender_commitment)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
Ok(AccountPreparedData {
|
||||
nsk,
|
||||
npk: from_npk,
|
||||
ipk: from_ipk,
|
||||
auth_acc: sender_pre,
|
||||
proof,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) async fn private_tx_two_accs_all_init(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to: AccountId,
|
||||
instruction_data: InstructionData,
|
||||
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
|
||||
program: Program,
|
||||
to_proof: MembershipProof,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let AccountPreparedData {
|
||||
nsk: from_nsk,
|
||||
npk: from_npk,
|
||||
ipk: from_ipk,
|
||||
auth_acc: sender_pre,
|
||||
proof: from_proof,
|
||||
} = self.private_acc_preparation(from, true, true).await?;
|
||||
|
||||
let AccountPreparedData {
|
||||
nsk: to_nsk,
|
||||
npk: to_npk,
|
||||
ipk: to_ipk,
|
||||
auth_acc: recipient_pre,
|
||||
proof: _,
|
||||
} = self.private_acc_preparation(to, true, false).await?;
|
||||
|
||||
tx_pre_check(&sender_pre.account, &recipient_pre.account)?;
|
||||
|
||||
let eph_holder_from = EphemeralKeyHolder::new(&from_npk);
|
||||
let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk);
|
||||
|
||||
let eph_holder_to = EphemeralKeyHolder::new(&to_npk);
|
||||
let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_ipk);
|
||||
|
||||
let (output, proof) = circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&instruction_data,
|
||||
&[1, 1],
|
||||
&produce_random_nonces(2),
|
||||
&[
|
||||
(from_npk.clone(), shared_secret_from.clone()),
|
||||
(to_npk.clone(), shared_secret_to.clone()),
|
||||
],
|
||||
&[
|
||||
(from_nsk.unwrap(), from_proof.unwrap()),
|
||||
(to_nsk.unwrap(), to_proof),
|
||||
],
|
||||
&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(),
|
||||
),
|
||||
(
|
||||
to_npk.clone(),
|
||||
to_ipk.clone(),
|
||||
eph_holder_to.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, shared_secret_to],
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) async fn private_tx_two_accs_receiver_uninit(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to: AccountId,
|
||||
instruction_data: InstructionData,
|
||||
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
|
||||
program: Program,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let AccountPreparedData {
|
||||
nsk: from_nsk,
|
||||
npk: from_npk,
|
||||
ipk: from_ipk,
|
||||
auth_acc: sender_pre,
|
||||
proof: from_proof,
|
||||
} = self.private_acc_preparation(from, true, true).await?;
|
||||
|
||||
let AccountPreparedData {
|
||||
nsk: _,
|
||||
npk: to_npk,
|
||||
ipk: to_ipk,
|
||||
auth_acc: recipient_pre,
|
||||
proof: _,
|
||||
} = self.private_acc_preparation(to, false, false).await?;
|
||||
|
||||
tx_pre_check(&sender_pre.account, &recipient_pre.account)?;
|
||||
|
||||
let eph_holder_from = EphemeralKeyHolder::new(&from_npk);
|
||||
let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk);
|
||||
|
||||
let eph_holder_to = EphemeralKeyHolder::new(&to_npk);
|
||||
let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_ipk);
|
||||
|
||||
let (output, proof) = circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&instruction_data,
|
||||
&[1, 2],
|
||||
&produce_random_nonces(2),
|
||||
&[
|
||||
(from_npk.clone(), shared_secret_from.clone()),
|
||||
(to_npk.clone(), shared_secret_to.clone()),
|
||||
],
|
||||
&[(from_nsk.unwrap(), from_proof.unwrap())],
|
||||
&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(),
|
||||
),
|
||||
(
|
||||
to_npk.clone(),
|
||||
to_ipk.clone(),
|
||||
eph_holder_to.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, shared_secret_to],
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) async fn private_tx_two_accs_receiver_outer(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to_npk: NullifierPublicKey,
|
||||
to_ipk: IncomingViewingPublicKey,
|
||||
instruction_data: InstructionData,
|
||||
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
|
||||
program: Program,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let AccountPreparedData {
|
||||
nsk: from_nsk,
|
||||
npk: from_npk,
|
||||
ipk: from_ipk,
|
||||
auth_acc: sender_pre,
|
||||
proof: from_proof,
|
||||
} = self.private_acc_preparation(from, true, true).await?;
|
||||
|
||||
let to_acc = nssa_core::account::Account::default();
|
||||
|
||||
tx_pre_check(&sender_pre.account, &to_acc)?;
|
||||
|
||||
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk);
|
||||
|
||||
let eph_holder = EphemeralKeyHolder::new(&to_npk);
|
||||
|
||||
let shared_secret_from = eph_holder.calculate_shared_secret_sender(&from_ipk);
|
||||
let shared_secret_to = eph_holder.calculate_shared_secret_sender(&to_ipk);
|
||||
|
||||
let (output, proof) = circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&instruction_data,
|
||||
&[1, 2],
|
||||
&produce_random_nonces(2),
|
||||
&[
|
||||
(from_npk.clone(), shared_secret_from.clone()),
|
||||
(to_npk.clone(), shared_secret_to.clone()),
|
||||
],
|
||||
&[(from_nsk.unwrap(), from_proof.unwrap())],
|
||||
&program,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let message = Message::try_from_circuit_output(
|
||||
vec![],
|
||||
vec![],
|
||||
vec![
|
||||
(
|
||||
from_npk.clone(),
|
||||
from_ipk.clone(),
|
||||
eph_holder.generate_ephemeral_public_key(),
|
||||
),
|
||||
(
|
||||
to_npk.clone(),
|
||||
to_ipk.clone(),
|
||||
eph_holder.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, shared_secret_to],
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) async fn deshielded_tx_two_accs(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to: AccountId,
|
||||
instruction_data: InstructionData,
|
||||
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
|
||||
program: Program,
|
||||
) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 1]), ExecutionFailureKind> {
|
||||
let AccountPreparedData {
|
||||
nsk: from_nsk,
|
||||
npk: from_npk,
|
||||
ipk: from_ipk,
|
||||
auth_acc: sender_pre,
|
||||
proof: from_proof,
|
||||
} = self.private_acc_preparation(from, true, true).await?;
|
||||
|
||||
let Ok(to_acc) = self.get_account_public(to).await else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
tx_pre_check(&sender_pre.account, &to_acc)?;
|
||||
|
||||
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, to);
|
||||
|
||||
let eph_holder = EphemeralKeyHolder::new(&from_npk);
|
||||
let shared_secret = eph_holder.calculate_shared_secret_sender(&from_ipk);
|
||||
|
||||
let (output, proof) = circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&instruction_data,
|
||||
&[1, 0],
|
||||
&produce_random_nonces(1),
|
||||
&[(from_npk.clone(), shared_secret.clone())],
|
||||
&[(from_nsk.unwrap(), from_proof.unwrap())],
|
||||
&program,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let message = Message::try_from_circuit_output(
|
||||
vec![to],
|
||||
vec![],
|
||||
vec![(
|
||||
from_npk.clone(),
|
||||
from_ipk.clone(),
|
||||
eph_holder.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],
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) async fn shielded_two_accs_all_init(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to: AccountId,
|
||||
instruction_data: InstructionData,
|
||||
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
|
||||
program: Program,
|
||||
to_proof: MembershipProof,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
|
||||
let Ok(from_acc) = self.get_account_public(from).await else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let AccountPreparedData {
|
||||
nsk: to_nsk,
|
||||
npk: to_npk,
|
||||
ipk: to_ipk,
|
||||
auth_acc: recipient_pre,
|
||||
proof: _,
|
||||
} = self.private_acc_preparation(to, true, false).await?;
|
||||
|
||||
tx_pre_check(&from_acc, &recipient_pre.account)?;
|
||||
|
||||
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from);
|
||||
|
||||
let eph_holder = EphemeralKeyHolder::new(&to_npk);
|
||||
let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk);
|
||||
|
||||
let (output, proof) = circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&instruction_data,
|
||||
&[0, 1],
|
||||
&produce_random_nonces(1),
|
||||
&[(to_npk.clone(), shared_secret.clone())],
|
||||
&[(to_nsk.unwrap(), to_proof)],
|
||||
&program,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let message = Message::try_from_circuit_output(
|
||||
vec![from],
|
||||
vec![from_acc.nonce],
|
||||
vec![(
|
||||
to_npk.clone(),
|
||||
to_ipk.clone(),
|
||||
eph_holder.generate_ephemeral_public_key(),
|
||||
)],
|
||||
output,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let signing_key = self.storage.user_data.get_pub_account_signing_key(&from);
|
||||
|
||||
let Some(signing_key) = signing_key else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]);
|
||||
|
||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||
|
||||
Ok((
|
||||
self.sequencer_client.send_tx_private(tx).await?,
|
||||
[shared_secret],
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) async fn shielded_two_accs_receiver_uninit(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to: AccountId,
|
||||
instruction_data: InstructionData,
|
||||
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
|
||||
program: Program,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
|
||||
let Ok(from_acc) = self.get_account_public(from).await else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let AccountPreparedData {
|
||||
nsk: _,
|
||||
npk: to_npk,
|
||||
ipk: to_ipk,
|
||||
auth_acc: recipient_pre,
|
||||
proof: _,
|
||||
} = self.private_acc_preparation(to, false, false).await?;
|
||||
|
||||
tx_pre_check(&from_acc, &recipient_pre.account)?;
|
||||
|
||||
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from);
|
||||
|
||||
let eph_holder = EphemeralKeyHolder::new(&to_npk);
|
||||
let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk);
|
||||
|
||||
let (output, proof) = circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&instruction_data,
|
||||
&[0, 2],
|
||||
&produce_random_nonces(1),
|
||||
&[(to_npk.clone(), shared_secret.clone())],
|
||||
&[],
|
||||
&program,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let message = Message::try_from_circuit_output(
|
||||
vec![from],
|
||||
vec![from_acc.nonce],
|
||||
vec![(
|
||||
to_npk.clone(),
|
||||
to_ipk.clone(),
|
||||
eph_holder.generate_ephemeral_public_key(),
|
||||
)],
|
||||
output,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let signing_key = self.storage.user_data.get_pub_account_signing_key(&from);
|
||||
|
||||
let Some(signing_key) = signing_key else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]);
|
||||
|
||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||
|
||||
Ok((
|
||||
self.sequencer_client.send_tx_private(tx).await?,
|
||||
[shared_secret],
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) async fn shielded_two_accs_receiver_outer(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to_npk: NullifierPublicKey,
|
||||
to_ipk: IncomingViewingPublicKey,
|
||||
instruction_data: InstructionData,
|
||||
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
|
||||
program: Program,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let Ok(from_acc) = self.get_account_public(from).await else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let to_acc = Account::default();
|
||||
|
||||
tx_pre_check(&from_acc, &to_acc)?;
|
||||
|
||||
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from);
|
||||
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk);
|
||||
|
||||
let eph_holder = EphemeralKeyHolder::new(&to_npk);
|
||||
let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk);
|
||||
|
||||
let (output, proof) = circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&instruction_data,
|
||||
&[0, 2],
|
||||
&produce_random_nonces(1),
|
||||
&[(to_npk.clone(), shared_secret.clone())],
|
||||
&[],
|
||||
&program,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let message = Message::try_from_circuit_output(
|
||||
vec![from],
|
||||
vec![from_acc.nonce],
|
||||
vec![(
|
||||
to_npk.clone(),
|
||||
to_ipk.clone(),
|
||||
eph_holder.generate_ephemeral_public_key(),
|
||||
)],
|
||||
output,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let signing_key = self.storage.user_data.get_pub_account_signing_key(&from);
|
||||
|
||||
let Some(signing_key) = signing_key else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]);
|
||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self.sequencer_client.send_tx_private(tx).await?)
|
||||
}
|
||||
|
||||
pub async fn register_account_under_authenticated_transfers_programs_private(
|
||||
&self,
|
||||
from: AccountId,
|
||||
) -> 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],
|
||||
))
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user