fix: token refactor in progress

This commit is contained in:
Pravdyvy 2025-12-22 15:52:42 +02:00
parent c7c0414a32
commit 21c3d762f4
11 changed files with 951 additions and 2750 deletions

View File

@ -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,
});

View File

@ -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,
})
}
}
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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(),
)
})
}

View File

@ -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)
})
}
}

View File

@ -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(()),
)
})
}
}

View File

@ -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])
})
}
}

View File

@ -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)
})
}
}

View File

@ -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(()))
}
}