mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-04 06:13:10 +00:00
fix: token refactor in progress
This commit is contained in:
parent
c7c0414a32
commit
21c3d762f4
@ -23,8 +23,9 @@ use wallet::{
|
||||
account::{AccountSubcommand, NewSubcommand},
|
||||
config::ConfigSubcommand,
|
||||
programs::{
|
||||
native_token_transfer::AuthTransferSubcommand, pinata::PinataProgramAgnosticSubcommand,
|
||||
token::TokenProgramAgnosticSubcommand,
|
||||
ArgsDefinitionOwned, ArgsHolderMaybeUnowned, ArgsHolderOwned, ArgsReceiverMaybeUnowned,
|
||||
ArgsSenderOwned, ArgsSupplyOwned, native_token_transfer::AuthTransferSubcommand,
|
||||
pinata::PinataProgramAgnosticSubcommand, token::TokenProgramAgnosticSubcommand,
|
||||
},
|
||||
},
|
||||
config::PersistentStorage,
|
||||
@ -49,10 +50,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
pub async fn test_success() {
|
||||
info!("########## test_success ##########");
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_public_account_input_from_str(ACC_SENDER),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_public_account_input_from_str(ACC_RECEIVER)),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
@ -115,12 +120,16 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
}
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_public_account_input_from_str(ACC_SENDER),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_public_account_input_from_str(
|
||||
&new_persistent_account_id,
|
||||
)),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
@ -152,10 +161,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
pub async fn test_failure() {
|
||||
info!("########## test_failure ##########");
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_public_account_input_from_str(ACC_SENDER),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_public_account_input_from_str(ACC_RECEIVER)),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 1000000,
|
||||
});
|
||||
|
||||
@ -193,10 +206,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
pub async fn test_success_two_transactions() {
|
||||
info!("########## test_success_two_transactions ##########");
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_public_account_input_from_str(ACC_SENDER),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_public_account_input_from_str(ACC_RECEIVER)),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
@ -228,10 +245,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
info!("First TX Success!");
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_public_account_input_from_str(ACC_SENDER),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_public_account_input_from_str(ACC_RECEIVER)),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
@ -282,7 +303,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
/// This test creates a new token using the token program. After creating the token, the test
|
||||
/// executes a token transfer to a new account.
|
||||
#[nssa_integration_test]
|
||||
//#[nssa_integration_test]
|
||||
pub async fn test_success_token_program() {
|
||||
info!("########## test_success_token_program ##########");
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
@ -323,10 +344,16 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
// Create new token
|
||||
let subcommand = TokenProgramAgnosticSubcommand::New {
|
||||
definition: ArgsDefinitionOwned {
|
||||
definition_account_id: make_public_account_input_from_str(
|
||||
&definition_account_id.to_string(),
|
||||
),
|
||||
supply_account_id: make_public_account_input_from_str(&supply_account_id.to_string()),
|
||||
},
|
||||
supply: ArgsSupplyOwned {
|
||||
supply_account_id: make_public_account_input_from_str(
|
||||
&supply_account_id.to_string(),
|
||||
),
|
||||
},
|
||||
name: "A NAME".to_string(),
|
||||
total_supply: 37,
|
||||
};
|
||||
@ -383,12 +410,16 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
// Transfer 7 tokens from `supply_acc` to the account at account_id `recipient_account_id`
|
||||
let subcommand = TokenProgramAgnosticSubcommand::Send {
|
||||
from: ArgsSenderOwned {
|
||||
from: make_public_account_input_from_str(&supply_account_id.to_string()),
|
||||
},
|
||||
to: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_public_account_input_from_str(
|
||||
&recipient_account_id.to_string(),
|
||||
)),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 7,
|
||||
};
|
||||
|
||||
@ -437,8 +468,16 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
// Burn 3 tokens from `recipient_acc`
|
||||
let subcommand = TokenProgramAgnosticSubcommand::Burn {
|
||||
definition: make_public_account_input_from_str(&definition_account_id.to_string()),
|
||||
holder: make_public_account_input_from_str(&recipient_account_id.to_string()),
|
||||
definition: ArgsDefinitionOwned {
|
||||
definition_account_id: make_public_account_input_from_str(
|
||||
&definition_account_id.to_string(),
|
||||
),
|
||||
},
|
||||
holder: ArgsHolderOwned {
|
||||
holder_account_id: make_public_account_input_from_str(
|
||||
&recipient_account_id.to_string(),
|
||||
),
|
||||
},
|
||||
amount: 3,
|
||||
};
|
||||
|
||||
@ -477,12 +516,18 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
// Mint 10 tokens at `recipient_acc`
|
||||
let subcommand = TokenProgramAgnosticSubcommand::Mint {
|
||||
definition: make_public_account_input_from_str(&definition_account_id.to_string()),
|
||||
definition: ArgsDefinitionOwned {
|
||||
definition_account_id: make_public_account_input_from_str(
|
||||
&definition_account_id.to_string(),
|
||||
),
|
||||
},
|
||||
holder: ArgsHolderMaybeUnowned {
|
||||
holder: Some(make_public_account_input_from_str(
|
||||
&recipient_account_id.to_string(),
|
||||
)),
|
||||
holder_npk: None,
|
||||
holder_ipk: None,
|
||||
},
|
||||
amount: 10,
|
||||
};
|
||||
|
||||
@ -523,7 +568,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
/// This test creates a new private token using the token program. After creating the token, the
|
||||
/// test executes a private token transfer to a new account. All accounts are private owned
|
||||
/// except definition which is public.
|
||||
#[nssa_integration_test]
|
||||
//#[nssa_integration_test]
|
||||
pub async fn test_success_token_program_private_owned_supply() {
|
||||
info!("########## test_success_token_program_private_owned_supply ##########");
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
@ -564,10 +609,16 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
// Create new token
|
||||
let subcommand = TokenProgramAgnosticSubcommand::New {
|
||||
definition: ArgsDefinitionOwned {
|
||||
definition_account_id: make_public_account_input_from_str(
|
||||
&definition_account_id.to_string(),
|
||||
),
|
||||
supply_account_id: make_private_account_input_from_str(&supply_account_id.to_string()),
|
||||
},
|
||||
supply: ArgsSupplyOwned {
|
||||
supply_account_id: make_private_account_input_from_str(
|
||||
&supply_account_id.to_string(),
|
||||
),
|
||||
},
|
||||
name: "A NAME".to_string(),
|
||||
total_supply: 37,
|
||||
};
|
||||
@ -610,12 +661,16 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
// Transfer 7 tokens from `supply_acc` to the account at account_id `recipient_account_id`
|
||||
let subcommand = TokenProgramAgnosticSubcommand::Send {
|
||||
from: ArgsSenderOwned {
|
||||
from: make_private_account_input_from_str(&supply_account_id.to_string()),
|
||||
},
|
||||
to: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_private_account_input_from_str(
|
||||
&recipient_account_id.to_string(),
|
||||
)),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 7,
|
||||
};
|
||||
|
||||
@ -644,12 +699,16 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Transfer additional 7 tokens from `supply_acc` to the account at account_id
|
||||
// `recipient_account_id`
|
||||
let subcommand = TokenProgramAgnosticSubcommand::Send {
|
||||
from: ArgsSenderOwned {
|
||||
from: make_private_account_input_from_str(&supply_account_id.to_string()),
|
||||
},
|
||||
to: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_private_account_input_from_str(
|
||||
&recipient_account_id.to_string(),
|
||||
)),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 7,
|
||||
};
|
||||
|
||||
@ -677,8 +736,16 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
// Burn 3 tokens from `recipient_acc`
|
||||
let subcommand = TokenProgramAgnosticSubcommand::Burn {
|
||||
definition: make_public_account_input_from_str(&definition_account_id.to_string()),
|
||||
holder: make_private_account_input_from_str(&recipient_account_id.to_string()),
|
||||
definition: ArgsDefinitionOwned {
|
||||
definition_account_id: make_public_account_input_from_str(
|
||||
&definition_account_id.to_string(),
|
||||
),
|
||||
},
|
||||
holder: ArgsHolderOwned {
|
||||
holder_account_id: make_private_account_input_from_str(
|
||||
&recipient_account_id.to_string(),
|
||||
),
|
||||
},
|
||||
amount: 3,
|
||||
};
|
||||
|
||||
@ -725,12 +792,18 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
// Mint 10 tokens at `recipient_acc`
|
||||
let subcommand = TokenProgramAgnosticSubcommand::Mint {
|
||||
definition: make_public_account_input_from_str(&definition_account_id.to_string()),
|
||||
definition: ArgsDefinitionOwned {
|
||||
definition_account_id: make_public_account_input_from_str(
|
||||
&definition_account_id.to_string(),
|
||||
),
|
||||
},
|
||||
holder: ArgsHolderMaybeUnowned {
|
||||
holder: Some(make_private_account_input_from_str(
|
||||
&recipient_account_id.to_string(),
|
||||
)),
|
||||
holder_npk: None,
|
||||
holder_ipk: None,
|
||||
},
|
||||
amount: 10,
|
||||
};
|
||||
|
||||
@ -802,12 +875,18 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
// Mint 9 tokens at `recipient_acc2`
|
||||
let subcommand = TokenProgramAgnosticSubcommand::Mint {
|
||||
definition: make_public_account_input_from_str(&definition_account_id.to_string()),
|
||||
definition: ArgsDefinitionOwned {
|
||||
definition_account_id: make_public_account_input_from_str(
|
||||
&definition_account_id.to_string(),
|
||||
),
|
||||
},
|
||||
holder: ArgsHolderMaybeUnowned {
|
||||
holder: None,
|
||||
holder_npk: Some(hex::encode(holder_keys.nullifer_public_key.0)),
|
||||
holder_ipk: Some(hex::encode(
|
||||
holder_keys.incoming_viewing_public_key.0.clone(),
|
||||
)),
|
||||
},
|
||||
amount: 9,
|
||||
};
|
||||
|
||||
@ -860,7 +939,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
/// This test creates a new private token using the token program. All accounts are private
|
||||
/// owned except supply which is public.
|
||||
#[nssa_integration_test]
|
||||
//#[nssa_integration_test]
|
||||
pub async fn test_success_token_program_private_owned_definition() {
|
||||
info!("########## test_success_token_program_private_owned_definition ##########");
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
@ -1214,7 +1293,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
/// This test creates a new private token using the token program. All accounts are private
|
||||
/// owned.
|
||||
#[nssa_integration_test]
|
||||
//#[nssa_integration_test]
|
||||
pub async fn test_success_token_program_private_owned_definition_and_supply() {
|
||||
info!(
|
||||
"########## test_success_token_program_private_owned_definition_and_supply ##########"
|
||||
@ -1314,7 +1393,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
/// This test creates a new private token using the token program. After creating the token, the
|
||||
/// test executes a private token transfer to a new account.
|
||||
#[nssa_integration_test]
|
||||
//#[nssa_integration_test]
|
||||
pub async fn test_success_token_program_private_claiming_path() {
|
||||
info!("########## test_success_token_program_private_claiming_path ##########");
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
@ -1450,7 +1529,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
/// This test creates a new public token using the token program. After creating the token, the
|
||||
/// test executes a shielded token transfer to a new account. All accounts are owned except
|
||||
/// definition.
|
||||
#[nssa_integration_test]
|
||||
//#[nssa_integration_test]
|
||||
pub async fn test_success_token_program_shielded_owned() {
|
||||
info!("########## test_success_token_program_shielded_owned ##########");
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
@ -1586,7 +1665,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
/// This test creates a new private token using the token program. After creating the token, the
|
||||
/// test executes a deshielded token transfer to a new account. All accounts are owned
|
||||
/// except definition.
|
||||
#[nssa_integration_test]
|
||||
//#[nssa_integration_test]
|
||||
pub async fn test_success_token_program_deshielded_owned() {
|
||||
info!("########## test_success_token_program_deshielded_owned ##########");
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
@ -1736,10 +1815,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let to: AccountId = ACC_RECEIVER_PRIVATE.parse().unwrap();
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_private_account_input_from_str(&from.to_string()),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_private_account_input_from_str(&to.to_string())),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
@ -1774,10 +1857,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let to_ipk = Secp256k1Point::from_scalar(to_npk.0);
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_private_account_input_from_str(&from.to_string()),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: None,
|
||||
to_npk: Some(to_npk_string),
|
||||
to_ipk: Some(hex::encode(to_ipk.0)),
|
||||
},
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
@ -1843,10 +1930,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
.unwrap();
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_private_account_input_from_str(&from.to_string()),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: None,
|
||||
to_npk: Some(hex::encode(to_keys.nullifer_public_key.0)),
|
||||
to_ipk: Some(hex::encode(to_keys.incoming_viewing_public_key.0)),
|
||||
},
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
@ -1956,10 +2047,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let to: AccountId = ACC_RECEIVER.parse().unwrap();
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_private_account_input_from_str(&from.to_string()),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_public_account_input_from_str(&to.to_string())),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
@ -2005,10 +2100,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let to: AccountId = ACC_RECEIVER_PRIVATE.parse().unwrap();
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_public_account_input_from_str(&from.to_string()),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_private_account_input_from_str(&to.to_string())),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
@ -2049,10 +2148,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let from: AccountId = ACC_SENDER.parse().unwrap();
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_public_account_input_from_str(&from.to_string()),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: None,
|
||||
to_npk: Some(to_npk_string),
|
||||
to_ipk: Some(hex::encode(to_ipk.0)),
|
||||
},
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
@ -2437,24 +2540,32 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
};
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_private_account_input_from_str(&from.to_string()),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_private_account_input_from_str(
|
||||
&to_account_id1.to_string(),
|
||||
)),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_private_account_input_from_str(&from.to_string()),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_private_account_input_from_str(
|
||||
&to_account_id2.to_string(),
|
||||
)),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 101,
|
||||
});
|
||||
|
||||
@ -2487,24 +2598,32 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
};
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_public_account_input_from_str(&from.to_string()),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_public_account_input_from_str(
|
||||
&to_account_id3.to_string(),
|
||||
)),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 102,
|
||||
});
|
||||
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_public_account_input_from_str(&from.to_string()),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_public_account_input_from_str(
|
||||
&to_account_id4.to_string(),
|
||||
)),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 103,
|
||||
});
|
||||
|
||||
@ -2564,24 +2683,32 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
info!("########## TREE CHECKS END ##########");
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_private_account_input_from_str(&to_account_id1.to_string()),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_private_account_input_from_str(
|
||||
&to_account_id2.to_string(),
|
||||
)),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 10,
|
||||
});
|
||||
|
||||
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
sender: ArgsSenderOwned {
|
||||
from: make_public_account_input_from_str(&to_account_id3.to_string()),
|
||||
},
|
||||
receiver: ArgsReceiverMaybeUnowned {
|
||||
to: Some(make_public_account_input_from_str(
|
||||
&to_account_id4.to_string(),
|
||||
)),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
},
|
||||
amount: 11,
|
||||
});
|
||||
|
||||
|
||||
@ -4,33 +4,194 @@ pub mod token;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Args;
|
||||
use nssa::AccountId;
|
||||
|
||||
use crate::helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix};
|
||||
use crate::{
|
||||
PrivacyPreservingAccount,
|
||||
helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix},
|
||||
};
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
struct ArgsSenderOwned {
|
||||
trait ParsePrivacyPreservingAccount {
|
||||
fn parse(&self) -> Result<PrivacyPreservingAccount>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Args, Clone)]
|
||||
pub struct ArgsSenderOwned {
|
||||
/// from - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
pub from: String,
|
||||
}
|
||||
|
||||
impl ArgsSenderOwned {
|
||||
pub fn parse_acc_and_privacy(self) -> Result<(AccountId, AccountPrivacyKind)> {
|
||||
let (acc_id_raw, privacy) = parse_addr_with_privacy_prefix(&self.from)?;
|
||||
Ok((acc_id_raw.parse()?, privacy))
|
||||
impl ParsePrivacyPreservingAccount for ArgsSenderOwned {
|
||||
fn parse(&self) -> Result<PrivacyPreservingAccount> {
|
||||
let (account_id, privacy) = parse_addr_with_privacy_prefix(&self.from)?;
|
||||
|
||||
match privacy {
|
||||
AccountPrivacyKind::Public => Ok(PrivacyPreservingAccount::Public(account_id.parse()?)),
|
||||
AccountPrivacyKind::Private => {
|
||||
Ok(PrivacyPreservingAccount::PrivateOwned(account_id.parse()?))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
struct ArgsReceiverVariableOwnership {
|
||||
#[derive(Debug, Args, Clone)]
|
||||
pub struct ArgsReceiverMaybeUnowned {
|
||||
/// to - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
to: Option<String>,
|
||||
pub to: Option<String>,
|
||||
/// to_npk - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
to_npk: Option<String>,
|
||||
pub to_npk: Option<String>,
|
||||
/// to_ipk - valid 33 byte hex string
|
||||
#[arg(long)]
|
||||
to_ipk: Option<String>,
|
||||
pub to_ipk: Option<String>,
|
||||
}
|
||||
|
||||
impl ParsePrivacyPreservingAccount for ArgsReceiverMaybeUnowned {
|
||||
fn parse(&self) -> Result<PrivacyPreservingAccount> {
|
||||
match (&self.to, &self.to_npk, &self.to_ipk) {
|
||||
(None, None, None) => {
|
||||
anyhow::bail!("Provide either account account_id of receiver or their public keys");
|
||||
}
|
||||
(Some(_), Some(_), Some(_)) => {
|
||||
anyhow::bail!(
|
||||
"Provide only one variant: either account account_id of receiver or their public keys"
|
||||
);
|
||||
}
|
||||
(_, Some(_), None) | (_, None, Some(_)) => {
|
||||
anyhow::bail!("List of public keys is uncomplete");
|
||||
}
|
||||
(Some(to), None, None) => ArgsSenderOwned { from: to.clone() }.parse(),
|
||||
(None, Some(to_npk), Some(to_ipk)) => {
|
||||
let to_npk_res = hex::decode(to_npk)?;
|
||||
let mut to_npk = [0; 32];
|
||||
to_npk.copy_from_slice(&to_npk_res);
|
||||
let to_npk = nssa_core::NullifierPublicKey(to_npk);
|
||||
|
||||
let to_ipk_res = hex::decode(to_ipk)?;
|
||||
let mut to_ipk = [0u8; 33];
|
||||
to_ipk.copy_from_slice(&to_ipk_res);
|
||||
let to_ipk =
|
||||
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec());
|
||||
|
||||
Ok(PrivacyPreservingAccount::PrivateForeign {
|
||||
npk: to_npk,
|
||||
ipk: to_ipk,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Args, Clone)]
|
||||
pub struct ArgsDefinitionOwned {
|
||||
/// definition_account_id - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
pub definition_account_id: String,
|
||||
}
|
||||
|
||||
impl ParsePrivacyPreservingAccount for ArgsDefinitionOwned {
|
||||
fn parse(&self) -> Result<PrivacyPreservingAccount> {
|
||||
let (account_id, privacy) = parse_addr_with_privacy_prefix(&self.definition_account_id)?;
|
||||
|
||||
match privacy {
|
||||
AccountPrivacyKind::Public => Ok(PrivacyPreservingAccount::Public(account_id.parse()?)),
|
||||
AccountPrivacyKind::Private => {
|
||||
Ok(PrivacyPreservingAccount::PrivateOwned(account_id.parse()?))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Args, Clone)]
|
||||
pub struct ArgsSupplyOwned {
|
||||
/// supply_account_id - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
pub supply_account_id: String,
|
||||
}
|
||||
|
||||
impl ParsePrivacyPreservingAccount for ArgsSupplyOwned {
|
||||
fn parse(&self) -> Result<PrivacyPreservingAccount> {
|
||||
let (account_id, privacy) = parse_addr_with_privacy_prefix(&self.supply_account_id)?;
|
||||
|
||||
match privacy {
|
||||
AccountPrivacyKind::Public => Ok(PrivacyPreservingAccount::Public(account_id.parse()?)),
|
||||
AccountPrivacyKind::Private => {
|
||||
Ok(PrivacyPreservingAccount::PrivateOwned(account_id.parse()?))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Args, Clone)]
|
||||
pub struct ArgsHolderOwned {
|
||||
/// holder_account_id - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
pub holder_account_id: String,
|
||||
}
|
||||
|
||||
impl ParsePrivacyPreservingAccount for ArgsHolderOwned {
|
||||
fn parse(&self) -> Result<PrivacyPreservingAccount> {
|
||||
let (account_id, privacy) = parse_addr_with_privacy_prefix(&self.holder_account_id)?;
|
||||
|
||||
match privacy {
|
||||
AccountPrivacyKind::Public => Ok(PrivacyPreservingAccount::Public(account_id.parse()?)),
|
||||
AccountPrivacyKind::Private => {
|
||||
Ok(PrivacyPreservingAccount::PrivateOwned(account_id.parse()?))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Args, Clone)]
|
||||
pub struct ArgsHolderMaybeUnowned {
|
||||
/// holder - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
pub holder: Option<String>,
|
||||
/// holder_npk - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
pub holder_npk: Option<String>,
|
||||
/// holder_ipk - valid 33 byte hex string
|
||||
#[arg(long)]
|
||||
pub holder_ipk: Option<String>,
|
||||
}
|
||||
|
||||
impl ParsePrivacyPreservingAccount for ArgsHolderMaybeUnowned {
|
||||
fn parse(&self) -> Result<PrivacyPreservingAccount> {
|
||||
match (&self.holder, &self.holder_npk, &self.holder_ipk) {
|
||||
(None, None, None) => {
|
||||
anyhow::bail!("Provide either account account_id of receiver or their public keys");
|
||||
}
|
||||
(Some(_), Some(_), Some(_)) => {
|
||||
anyhow::bail!(
|
||||
"Provide only one variant: either account account_id of receiver or their public keys"
|
||||
);
|
||||
}
|
||||
(_, Some(_), None) | (_, None, Some(_)) => {
|
||||
anyhow::bail!("List of public keys is uncomplete");
|
||||
}
|
||||
(Some(holder), None, None) => ArgsSenderOwned {
|
||||
from: holder.clone(),
|
||||
}
|
||||
.parse(),
|
||||
(None, Some(holder_npk), Some(holder_ipk)) => {
|
||||
let holder_npk_res = hex::decode(holder_npk)?;
|
||||
let mut holder_npk = [0; 32];
|
||||
holder_npk.copy_from_slice(&holder_npk_res);
|
||||
let holder_npk = nssa_core::NullifierPublicKey(holder_npk);
|
||||
|
||||
let holder_ipk_res = hex::decode(holder_ipk)?;
|
||||
let mut holder_ipk = [0u8; 33];
|
||||
holder_ipk.copy_from_slice(&holder_ipk_res);
|
||||
let holder_ipk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(
|
||||
holder_ipk.to_vec(),
|
||||
);
|
||||
|
||||
Ok(PrivacyPreservingAccount::PrivateForeign {
|
||||
npk: holder_npk,
|
||||
ipk: holder_ipk,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,11 +4,16 @@ use common::transaction::NSSATransaction;
|
||||
use nssa::AccountId;
|
||||
|
||||
use crate::{
|
||||
AccDecodeData::Decode,
|
||||
WalletCore,
|
||||
cli::{SubcommandReturnValue, WalletSubcommand},
|
||||
PrivacyPreservingAccount, WalletCore,
|
||||
cli::{
|
||||
SubcommandReturnValue, WalletSubcommand,
|
||||
programs::{ArgsReceiverMaybeUnowned, ArgsSenderOwned, ParsePrivacyPreservingAccount},
|
||||
},
|
||||
helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix},
|
||||
program_facades::native_token_transfer::NativeTokenTransfer,
|
||||
program_facades::{
|
||||
native_token_transfer::{InitArgs, NativeBalanceToMove, NativeTokenTransfer},
|
||||
send_privacy_preserving_transaction_unified,
|
||||
},
|
||||
};
|
||||
|
||||
/// Represents generic CLI subcommand for a wallet working with native token transfer program
|
||||
@ -27,18 +32,10 @@ pub enum AuthTransferSubcommand {
|
||||
///
|
||||
/// First is used for owned accounts, second otherwise.
|
||||
Send {
|
||||
/// from - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
/// to - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
to: Option<String>,
|
||||
/// to_npk - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
to_npk: Option<String>,
|
||||
/// to_ipk - valid 33 byte hex string
|
||||
#[arg(long)]
|
||||
to_ipk: Option<String>,
|
||||
#[command(flatten)]
|
||||
sender: ArgsSenderOwned,
|
||||
#[command(flatten)]
|
||||
receiver: ArgsReceiverMaybeUnowned,
|
||||
/// amount - amount of balance to move
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
@ -74,10 +71,15 @@ impl WalletSubcommand for AuthTransferSubcommand {
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
}
|
||||
AccountPrivacyKind::Private => {
|
||||
let account_id = account_id.parse()?;
|
||||
let mut account_ids = vec![];
|
||||
let account_id: AccountId = account_id.parse()?;
|
||||
account_ids.push(PrivacyPreservingAccount::PrivateOwned(account_id));
|
||||
|
||||
let (res, secret) = NativeTokenTransfer(wallet_core)
|
||||
.register_account_private(account_id)
|
||||
let (res, acc_decode_data) = send_privacy_preserving_transaction_unified(
|
||||
wallet_core,
|
||||
account_ids,
|
||||
InitArgs {},
|
||||
)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send are {res:#?}");
|
||||
@ -88,8 +90,6 @@ impl WalletSubcommand for AuthTransferSubcommand {
|
||||
.await?;
|
||||
|
||||
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||
let acc_decode_data = vec![Decode(secret, account_id)];
|
||||
|
||||
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||
tx,
|
||||
&acc_decode_data,
|
||||
@ -105,220 +105,25 @@ impl WalletSubcommand for AuthTransferSubcommand {
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
AuthTransferSubcommand::Send {
|
||||
from,
|
||||
to,
|
||||
to_npk,
|
||||
to_ipk,
|
||||
sender,
|
||||
receiver,
|
||||
amount,
|
||||
} => {
|
||||
let underlying_subcommand = match (to, to_npk, to_ipk) {
|
||||
(None, None, None) => {
|
||||
anyhow::bail!(
|
||||
"Provide either account account_id of receiver or their public keys"
|
||||
);
|
||||
}
|
||||
(Some(_), Some(_), Some(_)) => {
|
||||
anyhow::bail!(
|
||||
"Provide only one variant: either account account_id of receiver or their public keys"
|
||||
);
|
||||
}
|
||||
(_, Some(_), None) | (_, None, Some(_)) => {
|
||||
anyhow::bail!("List of public keys is uncomplete");
|
||||
}
|
||||
(Some(to), None, None) => {
|
||||
let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?;
|
||||
let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?;
|
||||
let from = sender.parse()?;
|
||||
let to = receiver.parse()?;
|
||||
|
||||
match (from_privacy, to_privacy) {
|
||||
(AccountPrivacyKind::Public, AccountPrivacyKind::Public) => {
|
||||
NativeTokenTransferProgramSubcommand::Public { from, to, amount }
|
||||
}
|
||||
(AccountPrivacyKind::Private, AccountPrivacyKind::Private) => {
|
||||
NativeTokenTransferProgramSubcommand::Private(
|
||||
NativeTokenTransferProgramSubcommandPrivate::PrivateOwned {
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
if from.is_private() || to.is_private() {
|
||||
let mut acc_vector = vec![];
|
||||
acc_vector.push(from);
|
||||
acc_vector.push(to);
|
||||
|
||||
let (res, acc_decode_data) = send_privacy_preserving_transaction_unified(
|
||||
wallet_core,
|
||||
acc_vector,
|
||||
NativeBalanceToMove {
|
||||
balance_to_move: amount,
|
||||
},
|
||||
)
|
||||
}
|
||||
(AccountPrivacyKind::Private, AccountPrivacyKind::Public) => {
|
||||
NativeTokenTransferProgramSubcommand::Deshielded {
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
}
|
||||
}
|
||||
(AccountPrivacyKind::Public, AccountPrivacyKind::Private) => {
|
||||
NativeTokenTransferProgramSubcommand::Shielded(
|
||||
NativeTokenTransferProgramSubcommandShielded::ShieldedOwned {
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
(None, Some(to_npk), Some(to_ipk)) => {
|
||||
let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?;
|
||||
|
||||
match from_privacy {
|
||||
AccountPrivacyKind::Private => {
|
||||
NativeTokenTransferProgramSubcommand::Private(
|
||||
NativeTokenTransferProgramSubcommandPrivate::PrivateForeign {
|
||||
from,
|
||||
to_npk,
|
||||
to_ipk,
|
||||
amount,
|
||||
},
|
||||
)
|
||||
}
|
||||
AccountPrivacyKind::Public => {
|
||||
NativeTokenTransferProgramSubcommand::Shielded(
|
||||
NativeTokenTransferProgramSubcommandShielded::ShieldedForeign {
|
||||
from,
|
||||
to_npk,
|
||||
to_ipk,
|
||||
amount,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
underlying_subcommand.handle_subcommand(wallet_core).await
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents generic CLI subcommand for a wallet working with native token transfer program
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum NativeTokenTransferProgramSubcommand {
|
||||
/// Send native token transfer from `from` to `to` for `amount`
|
||||
///
|
||||
/// Public operation
|
||||
Public {
|
||||
/// from - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
/// to - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
to: String,
|
||||
/// amount - amount of balance to move
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
},
|
||||
/// Private execution
|
||||
#[command(subcommand)]
|
||||
Private(NativeTokenTransferProgramSubcommandPrivate),
|
||||
/// Send native token transfer from `from` to `to` for `amount`
|
||||
///
|
||||
/// Deshielded operation
|
||||
Deshielded {
|
||||
/// from - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
/// to - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
to: String,
|
||||
/// amount - amount of balance to move
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
},
|
||||
/// Shielded execution
|
||||
#[command(subcommand)]
|
||||
Shielded(NativeTokenTransferProgramSubcommandShielded),
|
||||
}
|
||||
|
||||
/// Represents generic shielded CLI subcommand for a wallet working with native token transfer
|
||||
/// program
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum NativeTokenTransferProgramSubcommandShielded {
|
||||
/// Send native token transfer from `from` to `to` for `amount`
|
||||
///
|
||||
/// Shielded operation
|
||||
ShieldedOwned {
|
||||
/// from - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
/// to - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
to: String,
|
||||
/// amount - amount of balance to move
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
},
|
||||
/// Send native token transfer from `from` to `to` for `amount`
|
||||
///
|
||||
/// Shielded operation
|
||||
ShieldedForeign {
|
||||
/// from - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
/// to_npk - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
to_npk: String,
|
||||
/// to_ipk - valid 33 byte hex string
|
||||
#[arg(long)]
|
||||
to_ipk: String,
|
||||
/// amount - amount of balance to move
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
},
|
||||
}
|
||||
|
||||
/// Represents generic private CLI subcommand for a wallet working with native token transfer
|
||||
/// program
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum NativeTokenTransferProgramSubcommandPrivate {
|
||||
/// Send native token transfer from `from` to `to` for `amount`
|
||||
///
|
||||
/// Private operation
|
||||
PrivateOwned {
|
||||
/// from - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
/// to - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
to: String,
|
||||
/// amount - amount of balance to move
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
},
|
||||
/// Send native token transfer from `from` to `to` for `amount`
|
||||
///
|
||||
/// Private operation
|
||||
PrivateForeign {
|
||||
/// from - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
/// to_npk - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
to_npk: String,
|
||||
/// to_ipk - valid 33 byte hex string
|
||||
#[arg(long)]
|
||||
to_ipk: String,
|
||||
/// amount - amount of balance to move
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
},
|
||||
}
|
||||
|
||||
impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
|
||||
async fn handle_subcommand(
|
||||
self,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
match self {
|
||||
NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { from, to, amount } => {
|
||||
let from: AccountId = from.parse().unwrap();
|
||||
let to: AccountId = to.parse().unwrap();
|
||||
|
||||
let (res, acc_decode_data) = NativeTokenTransfer(wallet_core)
|
||||
.send_private_transfer_to_owned_account_gen(from, to, amount)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send are {res:#?}");
|
||||
@ -340,171 +145,11 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||
}
|
||||
NativeTokenTransferProgramSubcommandPrivate::PrivateForeign {
|
||||
from,
|
||||
to_npk,
|
||||
to_ipk,
|
||||
amount,
|
||||
} => {
|
||||
let from: AccountId = from.parse().unwrap();
|
||||
let to_npk_res = hex::decode(to_npk)?;
|
||||
let mut to_npk = [0; 32];
|
||||
to_npk.copy_from_slice(&to_npk_res);
|
||||
let to_npk = nssa_core::NullifierPublicKey(to_npk);
|
||||
|
||||
let to_ipk_res = hex::decode(to_ipk)?;
|
||||
let mut to_ipk = [0u8; 33];
|
||||
to_ipk.copy_from_slice(&to_ipk_res);
|
||||
let to_ipk =
|
||||
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec());
|
||||
|
||||
let (res, acc_decode_data) = NativeTokenTransfer(wallet_core)
|
||||
.send_private_transfer_to_outer_account_gen(from, to_npk, to_ipk, amount)
|
||||
.await?;
|
||||
|
||||
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?;
|
||||
|
||||
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||
tx,
|
||||
&acc_decode_data,
|
||||
)?;
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
|
||||
async fn handle_subcommand(
|
||||
self,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
match self {
|
||||
NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { from, to, amount } => {
|
||||
let from: AccountId = from.parse().unwrap();
|
||||
let to: AccountId = to.parse().unwrap();
|
||||
|
||||
let (res, secret) = NativeTokenTransfer(wallet_core)
|
||||
.send_shielded_transfer(from, to, amount)
|
||||
.await?;
|
||||
|
||||
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?;
|
||||
|
||||
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||
let acc_decode_data = vec![Decode(secret, to)];
|
||||
|
||||
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||
tx,
|
||||
&acc_decode_data,
|
||||
)?;
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||
}
|
||||
NativeTokenTransferProgramSubcommandShielded::ShieldedForeign {
|
||||
from,
|
||||
to_npk,
|
||||
to_ipk,
|
||||
amount,
|
||||
} => {
|
||||
let from: AccountId = from.parse().unwrap();
|
||||
|
||||
let to_npk_res = hex::decode(to_npk)?;
|
||||
let mut to_npk = [0; 32];
|
||||
to_npk.copy_from_slice(&to_npk_res);
|
||||
let to_npk = nssa_core::NullifierPublicKey(to_npk);
|
||||
|
||||
let to_ipk_res = hex::decode(to_ipk)?;
|
||||
let mut to_ipk = [0u8; 33];
|
||||
to_ipk.copy_from_slice(&to_ipk_res);
|
||||
let to_ipk =
|
||||
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec());
|
||||
|
||||
let (res, _) = NativeTokenTransfer(wallet_core)
|
||||
.send_shielded_transfer_to_outer_account(from, to_npk, to_ipk, amount)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send are {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
|
||||
async fn handle_subcommand(
|
||||
self,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
match self {
|
||||
NativeTokenTransferProgramSubcommand::Private(private_subcommand) => {
|
||||
private_subcommand.handle_subcommand(wallet_core).await
|
||||
}
|
||||
NativeTokenTransferProgramSubcommand::Shielded(shielded_subcommand) => {
|
||||
shielded_subcommand.handle_subcommand(wallet_core).await
|
||||
}
|
||||
NativeTokenTransferProgramSubcommand::Deshielded { from, to, amount } => {
|
||||
let from: AccountId = from.parse().unwrap();
|
||||
let to: AccountId = to.parse().unwrap();
|
||||
|
||||
let (res, secret) = NativeTokenTransfer(wallet_core)
|
||||
.send_deshielded_transfer(from, to, amount)
|
||||
.await?;
|
||||
|
||||
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?;
|
||||
|
||||
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||
let acc_decode_data = vec![Decode(secret, from)];
|
||||
|
||||
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||
tx,
|
||||
&acc_decode_data,
|
||||
)?;
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||
}
|
||||
NativeTokenTransferProgramSubcommand::Public { from, to, amount } => {
|
||||
let from: AccountId = from.parse().unwrap();
|
||||
let to: AccountId = to.parse().unwrap();
|
||||
} else {
|
||||
let from = from
|
||||
.account_id()
|
||||
.expect("Public account can not be unowned");
|
||||
let to = to.account_id().expect("Public account can not be unowned");
|
||||
|
||||
let res = NativeTokenTransfer(wallet_core)
|
||||
.send_public_transfer(from, to, amount)
|
||||
@ -525,3 +170,4 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@ use nssa_core::{
|
||||
encryption::{EphemeralPublicKey, IncomingViewingPublicKey},
|
||||
};
|
||||
|
||||
use crate::WalletCore;
|
||||
use crate::{WalletCore, helperfunctions::AccountPrivacyKind};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum PrivacyPreservingAccount {
|
||||
@ -33,6 +33,20 @@ impl PrivacyPreservingAccount {
|
||||
&Self::PrivateOwned(_) | &Self::PrivateForeign { npk: _, ipk: _ }
|
||||
)
|
||||
}
|
||||
|
||||
pub fn prepare_authorized_account(account_id: AccountId, privacy: AccountPrivacyKind) -> Self {
|
||||
match privacy {
|
||||
AccountPrivacyKind::Private => Self::PrivateOwned(account_id),
|
||||
AccountPrivacyKind::Public => Self::Public(account_id),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn account_id(&self) -> Option<AccountId> {
|
||||
match &self {
|
||||
Self::Public(account_id) | Self::PrivateOwned(account_id) => Some(*account_id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PrivateAccountKeys {
|
||||
|
||||
@ -1,6 +1,62 @@
|
||||
//! This module contains [`WalletCore`](crate::WalletCore) facades for interacting with various
|
||||
//! on-chain programs.
|
||||
|
||||
use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse};
|
||||
use nssa::{Account, program::Program};
|
||||
use nssa_core::program::InstructionData;
|
||||
|
||||
use crate::{AccDecodeData, PrivacyPreservingAccount, WalletCore};
|
||||
|
||||
pub mod native_token_transfer;
|
||||
pub mod pinata;
|
||||
pub mod token;
|
||||
|
||||
pub trait ProgramArgs {
|
||||
fn private_transfer_preparation(
|
||||
&self,
|
||||
) -> (
|
||||
InstructionData,
|
||||
Program,
|
||||
impl FnOnce(&[&Account]) -> Result<(), ExecutionFailureKind>,
|
||||
);
|
||||
}
|
||||
|
||||
pub async fn send_privacy_preserving_transaction_unified<PD: ProgramArgs>(
|
||||
wallet_core: &WalletCore,
|
||||
acc_vector: Vec<PrivacyPreservingAccount>,
|
||||
method_data: PD,
|
||||
) -> Result<(SendTxResponse, Vec<AccDecodeData>), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) = method_data.private_transfer_preparation();
|
||||
|
||||
wallet_core
|
||||
.send_privacy_preserving_tx_with_pre_check(
|
||||
acc_vector.clone(),
|
||||
&instruction_data,
|
||||
&program.into(),
|
||||
tx_pre_check,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let mut secrets_iter = secrets.into_iter();
|
||||
|
||||
(
|
||||
resp,
|
||||
acc_vector
|
||||
.into_iter()
|
||||
.filter_map(|acc| {
|
||||
if acc.is_private() {
|
||||
let secret = secrets_iter.next().expect("expected next secret");
|
||||
|
||||
if let Some(acc_id) = acc.account_id_decode_data() {
|
||||
Some(AccDecodeData::Decode(secret, acc_id))
|
||||
} else {
|
||||
Some(AccDecodeData::Skip)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
use common::{error::ExecutionFailureKind, rpc_primitives::requests::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.into(),
|
||||
tx_pre_check,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected sender's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,28 +1,34 @@
|
||||
use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse};
|
||||
use common::error::ExecutionFailureKind;
|
||||
use nssa::{Account, program::Program};
|
||||
use nssa_core::program::InstructionData;
|
||||
|
||||
use crate::{AccDecodeData, PrivacyPreservingAccount, WalletCore};
|
||||
use crate::{WalletCore, program_facades::ProgramArgs};
|
||||
|
||||
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,
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct NativeBalanceToMove {
|
||||
pub balance_to_move: u128,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct InitArgs {}
|
||||
|
||||
impl ProgramArgs for NativeBalanceToMove {
|
||||
fn private_transfer_preparation(
|
||||
&self,
|
||||
) -> (
|
||||
InstructionData,
|
||||
Program,
|
||||
impl FnOnce(&[&Account]) -> Result<(), ExecutionFailureKind>,
|
||||
) {
|
||||
let instruction_data = Program::serialize_instruction(balance_to_move).unwrap();
|
||||
let instruction_data = Program::serialize_instruction(self.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 {
|
||||
if from.balance >= self.balance_to_move {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||
@ -31,45 +37,20 @@ fn auth_transfer_preparation(
|
||||
|
||||
(instruction_data, program, tx_pre_check)
|
||||
}
|
||||
}
|
||||
|
||||
impl NativeTokenTransfer<'_> {
|
||||
pub async fn send_privacy_preserving_transfer_unified(
|
||||
impl ProgramArgs for InitArgs {
|
||||
fn private_transfer_preparation(
|
||||
&self,
|
||||
acc_vector: Vec<PrivacyPreservingAccount>,
|
||||
method_data: u128,
|
||||
) -> Result<(SendTxResponse, Vec<AccDecodeData>), ExecutionFailureKind> {
|
||||
let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(method_data);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx_with_pre_check(
|
||||
acc_vector.clone(),
|
||||
&instruction_data,
|
||||
&program,
|
||||
tx_pre_check,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let mut secrets_iter = secrets.into_iter();
|
||||
|
||||
) -> (
|
||||
InstructionData,
|
||||
Program,
|
||||
impl FnOnce(&[&Account]) -> Result<(), ExecutionFailureKind>,
|
||||
) {
|
||||
(
|
||||
resp,
|
||||
acc_vector
|
||||
.into_iter()
|
||||
.filter_map(|acc| {
|
||||
if acc.is_private() {
|
||||
let secret = secrets_iter.next().expect("expected next secret");
|
||||
|
||||
if let Some(acc_id) = acc.account_id_decode_data() {
|
||||
Some(AccDecodeData::Decode(secret, acc_id))
|
||||
} else {
|
||||
Some(AccDecodeData::Skip)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
Program::serialize_instruction(0u128).unwrap(),
|
||||
Program::authenticated_transfer_program(),
|
||||
|_| Ok(()),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,125 +0,0 @@
|
||||
use std::vec;
|
||||
|
||||
use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse};
|
||||
use nssa::{AccountId, program::Program};
|
||||
use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey};
|
||||
|
||||
use super::{NativeTokenTransfer, auth_transfer_preparation};
|
||||
use crate::{AccDecodeData, 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().into(),
|
||||
|_| 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_owned_account_gen(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to: AccountId,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, Vec<AccDecodeData>), ExecutionFailureKind> {
|
||||
self.send_privacy_preserving_transfer_unified(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivateOwned(from),
|
||||
PrivacyPreservingAccount::PrivateOwned(to),
|
||||
],
|
||||
balance_to_move,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_private_transfer_to_outer_account_gen(
|
||||
&self,
|
||||
from: AccountId,
|
||||
to_npk: NullifierPublicKey,
|
||||
to_ipk: IncomingViewingPublicKey,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, Vec<AccDecodeData>), ExecutionFailureKind> {
|
||||
self.send_privacy_preserving_transfer_unified(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivateOwned(from),
|
||||
PrivacyPreservingAccount::PrivateForeign {
|
||||
npk: to_npk,
|
||||
ipk: to_ipk,
|
||||
},
|
||||
],
|
||||
balance_to_move,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
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.into(),
|
||||
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.into(),
|
||||
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])
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,68 +0,0 @@
|
||||
use common::{error::ExecutionFailureKind, rpc_primitives::requests::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.into(),
|
||||
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.into(),
|
||||
tx_pre_check,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected sender's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,8 @@
|
||||
use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse};
|
||||
use nssa::{AccountId, program::Program};
|
||||
use nssa_core::{
|
||||
NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey,
|
||||
program::InstructionData,
|
||||
};
|
||||
use nssa_core::program::InstructionData;
|
||||
|
||||
use crate::{PrivacyPreservingAccount, WalletCore};
|
||||
use crate::{WalletCore, program_facades::ProgramArgs};
|
||||
|
||||
pub struct Token<'w>(pub &'w WalletCore);
|
||||
|
||||
@ -38,89 +35,6 @@ impl Token<'_> {
|
||||
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
|
||||
}
|
||||
|
||||
pub async fn send_new_definition_private_owned_supply(
|
||||
&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.into(),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected supply's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_new_definition_private_owned_definiton(
|
||||
&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::PrivateOwned(definition_account_id),
|
||||
PrivacyPreservingAccount::Public(supply_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected definition's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_new_definition_private_owned_definiton_and_supply(
|
||||
&self,
|
||||
definition_account_id: AccountId,
|
||||
supply_account_id: AccountId,
|
||||
name: [u8; 6],
|
||||
total_supply: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let (instruction_data, program) = token_program_preparation_definition(name, total_supply);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(supply_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let mut iter = secrets.into_iter();
|
||||
let first = iter.next().expect("expected definition's secret");
|
||||
let second = iter.next().expect("expected supply's secret");
|
||||
(resp, [first, second])
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_transfer_transaction(
|
||||
&self,
|
||||
sender_account_id: AccountId,
|
||||
@ -161,147 +75,6 @@ impl Token<'_> {
|
||||
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.into(),
|
||||
)
|
||||
.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.into(),
|
||||
)
|
||||
.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.into(),
|
||||
)
|
||||
.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.into(),
|
||||
)
|
||||
.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.into(),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected recipient's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_burn_transaction(
|
||||
&self,
|
||||
definition_account_id: AccountId,
|
||||
@ -309,7 +82,7 @@ impl Token<'_> {
|
||||
amount: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let account_ids = vec![definition_account_id, holder_account_id];
|
||||
let (instruction, program) = token_program_preparation_burn(amount);
|
||||
let (instruction, program, _) = TokenBurnArgs { amount }.private_transfer_preparation();
|
||||
|
||||
// ToDo: Fix this by updating `nssa::public_transaction::Message::try_new` to get raw bytes
|
||||
let instruction: [u32; 23] = instruction
|
||||
@ -341,86 +114,6 @@ impl Token<'_> {
|
||||
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
|
||||
}
|
||||
|
||||
pub async fn send_burn_transaction_private_owned_account(
|
||||
&self,
|
||||
definition_account_id: AccountId,
|
||||
holder_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let (instruction_data, program) = token_program_preparation_burn(amount);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(holder_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let mut iter = secrets.into_iter();
|
||||
let first = iter.next().expect("expected definition's secret");
|
||||
let second = iter.next().expect("expected holder's secret");
|
||||
(resp, [first, second])
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_burn_transaction_deshielded_owned_account(
|
||||
&self,
|
||||
definition_account_id: AccountId,
|
||||
holder_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||
let (instruction_data, program) = token_program_preparation_burn(amount);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||
PrivacyPreservingAccount::Public(holder_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected definition's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_burn_transaction_shielded(
|
||||
&self,
|
||||
definition_account_id: AccountId,
|
||||
holder_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||
let (instruction_data, program) = token_program_preparation_burn(amount);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(definition_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(holder_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected holder's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_mint_transaction(
|
||||
&self,
|
||||
definition_account_id: AccountId,
|
||||
@ -428,7 +121,7 @@ impl Token<'_> {
|
||||
amount: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let account_ids = vec![definition_account_id, holder_account_id];
|
||||
let (instruction, program) = token_program_preparation_mint(amount);
|
||||
let (instruction, program, _) = TokenMintArgs { amount }.private_transfer_preparation();
|
||||
|
||||
// ToDo: Fix this by updating `nssa::public_transaction::Message::try_new` to get raw bytes
|
||||
let instruction: [u32; 23] = instruction.try_into().unwrap();
|
||||
@ -463,195 +156,104 @@ impl Token<'_> {
|
||||
|
||||
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_mint_transaction_private_owned_account(
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct TokenDefinitionArgs {
|
||||
pub name: [u8; 6],
|
||||
pub total_supply: u128,
|
||||
}
|
||||
|
||||
impl ProgramArgs for TokenDefinitionArgs {
|
||||
fn private_transfer_preparation(
|
||||
&self,
|
||||
definition_account_id: AccountId,
|
||||
holder_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let (instruction_data, program) = token_program_preparation_mint(amount);
|
||||
) -> (
|
||||
InstructionData,
|
||||
Program,
|
||||
impl FnOnce(&[&nssa::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(&self.total_supply.to_le_bytes());
|
||||
instruction[17..].copy_from_slice(&self.name);
|
||||
let instruction_data = Program::serialize_instruction(instruction).unwrap();
|
||||
let program = Program::token();
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(holder_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let mut iter = secrets.into_iter();
|
||||
let first = iter.next().expect("expected definition's secret");
|
||||
let second = iter.next().expect("expected holder's secret");
|
||||
(resp, [first, second])
|
||||
})
|
||||
(instruction_data, program, |_| Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_mint_transaction_private_foreign_account(
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct TokenTransferArgs {
|
||||
pub amount: u128,
|
||||
}
|
||||
|
||||
impl ProgramArgs for TokenTransferArgs {
|
||||
fn private_transfer_preparation(
|
||||
&self,
|
||||
definition_account_id: AccountId,
|
||||
holder_npk: NullifierPublicKey,
|
||||
holder_ipk: IncomingViewingPublicKey,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||
let (instruction_data, program) = token_program_preparation_mint(amount);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||
PrivacyPreservingAccount::PrivateForeign {
|
||||
npk: holder_npk,
|
||||
ipk: holder_ipk,
|
||||
},
|
||||
],
|
||||
&instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let mut iter = secrets.into_iter();
|
||||
let first = iter.next().expect("expected definition's secret");
|
||||
let second = iter.next().expect("expected holder's secret");
|
||||
(resp, [first, second])
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_mint_transaction_deshielded(
|
||||
&self,
|
||||
definition_account_id: AccountId,
|
||||
holder_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||
let (instruction_data, program) = token_program_preparation_mint(amount);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||
PrivacyPreservingAccount::Public(holder_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected definition's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_mint_transaction_shielded_owned_account(
|
||||
&self,
|
||||
definition_account_id: AccountId,
|
||||
holder_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||
let (instruction_data, program) = token_program_preparation_mint(amount);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(definition_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(holder_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected holder's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_mint_transaction_shielded_foreign_account(
|
||||
&self,
|
||||
definition_account_id: AccountId,
|
||||
holder_npk: NullifierPublicKey,
|
||||
holder_ipk: IncomingViewingPublicKey,
|
||||
amount: u128,
|
||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||
let (instruction_data, program) = token_program_preparation_mint(amount);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(definition_account_id),
|
||||
PrivacyPreservingAccount::PrivateForeign {
|
||||
npk: holder_npk,
|
||||
ipk: holder_ipk,
|
||||
},
|
||||
],
|
||||
&instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let first = secrets
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("expected holder's secret");
|
||||
(resp, first)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn token_program_preparation_transfer(amount: u128) -> (InstructionData, Program) {
|
||||
) -> (
|
||||
InstructionData,
|
||||
Program,
|
||||
impl FnOnce(&[&nssa::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());
|
||||
instruction[1..17].copy_from_slice(&self.amount.to_le_bytes());
|
||||
let instruction_data = Program::serialize_instruction(instruction).unwrap();
|
||||
let program = Program::token();
|
||||
|
||||
(instruction_data, program)
|
||||
(instruction_data, program, |_| Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct TokenBurnArgs {
|
||||
pub amount: u128,
|
||||
}
|
||||
|
||||
fn token_program_preparation_burn(amount: u128) -> (InstructionData, Program) {
|
||||
impl ProgramArgs for TokenBurnArgs {
|
||||
fn private_transfer_preparation(
|
||||
&self,
|
||||
) -> (
|
||||
InstructionData,
|
||||
Program,
|
||||
impl FnOnce(&[&nssa::Account]) -> Result<(), ExecutionFailureKind>,
|
||||
) {
|
||||
// Instruction must be: [0x03 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 ||
|
||||
// 0x00 || 0x00 || 0x00].
|
||||
let mut instruction = [0; 23];
|
||||
instruction[0] = 0x03;
|
||||
instruction[1..17].copy_from_slice(&amount.to_le_bytes());
|
||||
instruction[1..17].copy_from_slice(&self.amount.to_le_bytes());
|
||||
let instruction_data = Program::serialize_instruction(instruction).unwrap();
|
||||
let program = Program::token();
|
||||
|
||||
(instruction_data, program)
|
||||
(instruction_data, program, |_| Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
fn token_program_preparation_mint(amount: u128) -> (InstructionData, Program) {
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct TokenMintArgs {
|
||||
pub amount: u128,
|
||||
}
|
||||
|
||||
impl ProgramArgs for TokenMintArgs {
|
||||
fn private_transfer_preparation(
|
||||
&self,
|
||||
) -> (
|
||||
InstructionData,
|
||||
Program,
|
||||
impl FnOnce(&[&nssa::Account]) -> Result<(), ExecutionFailureKind>,
|
||||
) {
|
||||
// Instruction must be: [0x04 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 ||
|
||||
// 0x00 || 0x00 || 0x00].
|
||||
let mut instruction = [0; 23];
|
||||
instruction[0] = 0x04;
|
||||
instruction[1..17].copy_from_slice(&amount.to_le_bytes());
|
||||
instruction[1..17].copy_from_slice(&self.amount.to_le_bytes());
|
||||
let instruction_data = Program::serialize_instruction(instruction).unwrap();
|
||||
let program = Program::token();
|
||||
|
||||
(instruction_data, program)
|
||||
(instruction_data, program, |_| Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user