fix: public execution finalized

This commit is contained in:
Pravdyvy 2025-12-18 11:44:38 +02:00
parent cde11e75d6
commit c1283d4a0c
9 changed files with 752 additions and 946 deletions

View File

@ -2224,30 +2224,18 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
.account;
assert_eq!(
user_holding_a_acc.data.as_ref(),
&[
1, 216, 180, 23, 229, 146, 37, 77, 185, 234, 186, 245, 33, 228, 197, 251, 244, 10,
137, 115, 157, 2, 246, 137, 52, 234, 64, 155, 199, 101, 15, 43, 83, 4, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
]
u128::from_le_bytes(user_holding_a_acc.data[33..].try_into().unwrap()),
4
);
assert_eq!(
user_holding_b_acc.data.as_ref(),
&[
1, 244, 191, 88, 67, 111, 12, 245, 25, 212, 169, 62, 209, 159, 73, 107, 101, 173,
88, 13, 55, 71, 91, 113, 88, 208, 91, 136, 222, 139, 2, 97, 110, 4, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
]
u128::from_le_bytes(user_holding_b_acc.data[33..].try_into().unwrap()),
4
);
assert_eq!(
user_holding_lp_acc.data.as_ref(),
&[
1, 16, 61, 24, 200, 168, 141, 91, 149, 164, 35, 114, 25, 6, 40, 204, 181, 95, 39,
59, 56, 56, 96, 222, 157, 226, 48, 111, 53, 30, 1, 41, 94, 3, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
]
u128::from_le_bytes(user_holding_lp_acc.data[33..].try_into().unwrap()),
3
);
info!("=================== AMM DEFINITION FINISHED ===============");
@ -2287,30 +2275,173 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
.account;
assert_eq!(
user_holding_a_acc.data.as_ref(),
&[
1, 216, 180, 23, 229, 146, 37, 77, 185, 234, 186, 245, 33, 228, 197, 251, 244, 10,
137, 115, 157, 2, 246, 137, 52, 234, 64, 155, 199, 101, 15, 43, 83, 2, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
]
u128::from_le_bytes(user_holding_a_acc.data[33..].try_into().unwrap()),
2
);
assert_eq!(
user_holding_b_acc.data.as_ref(),
&[
1, 244, 191, 88, 67, 111, 12, 245, 25, 212, 169, 62, 209, 159, 73, 107, 101, 173,
88, 13, 55, 71, 91, 113, 88, 208, 91, 136, 222, 139, 2, 97, 110, 5, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
]
u128::from_le_bytes(user_holding_b_acc.data[33..].try_into().unwrap()),
5
);
assert_eq!(
user_holding_lp_acc.data.as_ref(),
&[
1, 16, 61, 24, 200, 168, 141, 91, 149, 164, 35, 114, 25, 6, 40, 204, 181, 95, 39,
59, 56, 56, 96, 222, 157, 226, 48, 111, 53, 30, 1, 41, 94, 3, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
]
u128::from_le_bytes(user_holding_lp_acc.data[33..].try_into().unwrap()),
3
);
info!("=================== FIRST SWAP FINISHED ===============");
// Make swap
let subcommand = AmmProgramAgnosticSubcommand::Swap {
user_holding_a: make_public_account_input_from_str(&recipient_account_id_1.to_string()),
user_holding_b: make_public_account_input_from_str(&recipient_account_id_2.to_string()),
amount_in: 2,
min_amount_out: 1,
token_definition: definition_account_id_2.to_string(),
};
wallet::cli::execute_subcommand(Command::AMM(subcommand))
.await
.unwrap();
info!("Waiting for next block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
let user_holding_a_acc = seq_client
.get_account(recipient_account_id_1.to_string())
.await
.unwrap()
.account;
let user_holding_b_acc = seq_client
.get_account(recipient_account_id_2.to_string())
.await
.unwrap()
.account;
let user_holding_lp_acc = seq_client
.get_account(user_holding_lp.to_string())
.await
.unwrap()
.account;
assert_eq!(
u128::from_le_bytes(user_holding_a_acc.data[33..].try_into().unwrap()),
4
);
assert_eq!(
u128::from_le_bytes(user_holding_b_acc.data[33..].try_into().unwrap()),
3
);
assert_eq!(
u128::from_le_bytes(user_holding_lp_acc.data[33..].try_into().unwrap()),
3
);
info!("=================== SECOND SWAP FINISHED ===============");
// Add liquidity
let subcommand = AmmProgramAgnosticSubcommand::AddLiquidity {
user_holding_a: make_public_account_input_from_str(&recipient_account_id_1.to_string()),
user_holding_b: make_public_account_input_from_str(&recipient_account_id_2.to_string()),
user_holding_lp: make_public_account_input_from_str(&user_holding_lp.to_string()),
min_amount_lp: 1,
max_amount_a: 2,
max_amount_b: 2,
};
wallet::cli::execute_subcommand(Command::AMM(subcommand))
.await
.unwrap();
info!("Waiting for next block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
let user_holding_a_acc = seq_client
.get_account(recipient_account_id_1.to_string())
.await
.unwrap()
.account;
let user_holding_b_acc = seq_client
.get_account(recipient_account_id_2.to_string())
.await
.unwrap()
.account;
let user_holding_lp_acc = seq_client
.get_account(user_holding_lp.to_string())
.await
.unwrap()
.account;
assert_eq!(
u128::from_le_bytes(user_holding_a_acc.data[33..].try_into().unwrap()),
3
);
assert_eq!(
u128::from_le_bytes(user_holding_b_acc.data[33..].try_into().unwrap()),
1
);
assert_eq!(
u128::from_le_bytes(user_holding_lp_acc.data[33..].try_into().unwrap()),
4
);
info!("=================== ADD LIQ FINISHED ===============");
// Remove liquidity
let subcommand = AmmProgramAgnosticSubcommand::RemoveLiquidity {
user_holding_a: make_public_account_input_from_str(&recipient_account_id_1.to_string()),
user_holding_b: make_public_account_input_from_str(&recipient_account_id_2.to_string()),
user_holding_lp: make_public_account_input_from_str(&user_holding_lp.to_string()),
balance_lp: 2,
max_amount_a: 1,
max_amount_b: 1,
};
wallet::cli::execute_subcommand(Command::AMM(subcommand))
.await
.unwrap();
info!("Waiting for next block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
let user_holding_a_acc = seq_client
.get_account(recipient_account_id_1.to_string())
.await
.unwrap()
.account;
let user_holding_b_acc = seq_client
.get_account(recipient_account_id_2.to_string())
.await
.unwrap()
.account;
let user_holding_lp_acc = seq_client
.get_account(user_holding_lp.to_string())
.await
.unwrap()
.account;
assert_eq!(
u128::from_le_bytes(user_holding_a_acc.data[33..].try_into().unwrap()),
5
);
assert_eq!(
u128::from_le_bytes(user_holding_b_acc.data[33..].try_into().unwrap()),
4
);
assert_eq!(
u128::from_le_bytes(user_holding_lp_acc.data[33..].try_into().unwrap()),
2
);
info!("Success!");

View File

@ -1,10 +1,11 @@
use anyhow::Result;
use clap::Subcommand;
use nssa::AccountId;
use crate::{
PrivacyPreservingAccount, WalletCore,
WalletCore,
cli::{SubcommandReturnValue, WalletSubcommand},
helperfunctions::parse_addr_with_privacy_prefix,
helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix},
program_facades::amm::AMM,
};
@ -14,6 +15,8 @@ pub enum AmmProgramAgnosticSubcommand {
/// Produce a new token
///
/// user_holding_a and user_holding_b must be owned.
///
/// Only public execution allowed
New {
/// user_holding_a - valid 32 byte base58 string with privacy prefix
#[arg(long)]
@ -32,6 +35,8 @@ pub enum AmmProgramAgnosticSubcommand {
/// Swap with variable privacy
///
/// The account associated with swapping token must be owned
///
/// Only public execution allowed
Swap {
/// user_holding_a - valid 32 byte base58 string with privacy prefix
#[arg(long)]
@ -50,19 +55,9 @@ pub enum AmmProgramAgnosticSubcommand {
/// Add liquidity with variable privacy
///
/// user_holding_a and user_holding_b must be owned.
///
/// Only public execution allowed
AddLiquidity {
/// amm_pool - valid 32 byte base58 string with privacy prefix
#[arg(long)]
amm_pool: String,
/// vault_holding_a - valid 32 byte base58 string with privacy prefix
#[arg(long)]
vault_holding_a: String,
/// vault_holding_b - valid 32 byte base58 string with privacy prefix
#[arg(long)]
vault_holding_b: String,
/// pool_lp - valid 32 byte base58 string with privacy prefix
#[arg(long)]
pool_lp: String,
/// user_holding_a - valid 32 byte base58 string with privacy prefix
#[arg(long)]
user_holding_a: String,
@ -82,19 +77,9 @@ pub enum AmmProgramAgnosticSubcommand {
/// Remove liquidity with variable privacy
///
/// user_holding_lp must be owned.
///
/// Only public execution allowed
RemoveLiquidity {
/// amm_pool - valid 32 byte base58 string with privacy prefix
#[arg(long)]
amm_pool: String,
/// vault_holding_a - valid 32 byte base58 string with privacy prefix
#[arg(long)]
vault_holding_a: String,
/// vault_holding_b - valid 32 byte base58 string with privacy prefix
#[arg(long)]
vault_holding_b: String,
/// pool_lp - valid 32 byte base58 string with privacy prefix
#[arg(long)]
pool_lp: String,
/// user_holding_a - valid 32 byte base58 string with privacy prefix
#[arg(long)]
user_holding_a: String,
@ -126,43 +111,43 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
balance_a,
balance_b,
} => {
let user_holding_a = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&user_holding_a)?,
)?;
let user_holding_b = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&user_holding_b)?,
)?;
let user_holding_lp = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&user_holding_lp)?,
)?;
let (user_holding_a, user_holding_a_privacy) =
parse_addr_with_privacy_prefix(&user_holding_a)?;
let (user_holding_b, user_holding_b_privacy) =
parse_addr_with_privacy_prefix(&user_holding_b)?;
let (user_holding_lp, user_holding_lp_privacy) =
parse_addr_with_privacy_prefix(&user_holding_lp)?;
let is_public_tx = [&user_holding_a, &user_holding_b, &user_holding_lp]
.into_iter()
.all(|acc| acc.is_public());
let user_holding_a: AccountId = user_holding_a.parse()?;
let user_holding_b: AccountId = user_holding_b.parse()?;
let user_holding_lp: AccountId = user_holding_lp.parse()?;
if is_public_tx {
AMM(wallet_core)
.send_new_amm_definition(
user_holding_a,
user_holding_b,
user_holding_lp,
balance_a,
balance_b,
)
.await?;
Ok(SubcommandReturnValue::Empty)
} else {
AMM(wallet_core)
.send_new_amm_definition_privacy_preserving(
user_holding_a,
user_holding_b,
user_holding_lp,
balance_a,
balance_b,
)
.await?;
// ToDo: change into correct return value
Ok(SubcommandReturnValue::Empty)
match (
user_holding_a_privacy,
user_holding_b_privacy,
user_holding_lp_privacy,
) {
(
AccountPrivacyKind::Public,
AccountPrivacyKind::Public,
AccountPrivacyKind::Public,
) => {
AMM(wallet_core)
.send_new_amm_definition(
user_holding_a,
user_holding_b,
user_holding_lp,
balance_a,
balance_b,
)
.await?;
Ok(SubcommandReturnValue::Empty)
}
_ => {
// ToDo: Implement after private multi-chain calls is available
anyhow::bail!("Only public execution allowed for AMM calls");
}
}
}
AmmProgramAgnosticSubcommand::Swap {
@ -172,47 +157,35 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
min_amount_out,
token_definition,
} => {
let user_holding_a = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&user_holding_a)?,
)?;
let user_holding_b = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&user_holding_b)?,
)?;
let (user_holding_a, user_holding_a_privacy) =
parse_addr_with_privacy_prefix(&user_holding_a)?;
let (user_holding_b, user_holding_b_privacy) =
parse_addr_with_privacy_prefix(&user_holding_b)?;
let is_public_tx = [&user_holding_a, &user_holding_b]
.into_iter()
.all(|acc| acc.is_public());
let user_holding_a: AccountId = user_holding_a.parse()?;
let user_holding_b: AccountId = user_holding_b.parse()?;
if is_public_tx {
AMM(wallet_core)
.send_swap(
user_holding_a,
user_holding_b,
amount_in,
min_amount_out,
token_definition.parse()?,
)
.await?;
Ok(SubcommandReturnValue::Empty)
} else {
AMM(wallet_core)
.send_swap_privacy_preserving(
user_holding_a,
user_holding_b,
amount_in,
min_amount_out,
token_definition.parse()?,
)
.await?;
// ToDo: change into correct return value
Ok(SubcommandReturnValue::Empty)
match (user_holding_a_privacy, user_holding_b_privacy) {
(AccountPrivacyKind::Public, AccountPrivacyKind::Public) => {
AMM(wallet_core)
.send_swap(
user_holding_a,
user_holding_b,
amount_in,
min_amount_out,
token_definition.parse()?,
)
.await?;
Ok(SubcommandReturnValue::Empty)
}
_ => {
// ToDo: Implement after private multi-chain calls is available
anyhow::bail!("Only public execution allowed for AMM calls");
}
}
}
AmmProgramAgnosticSubcommand::AddLiquidity {
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
@ -220,80 +193,47 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
max_amount_a,
max_amount_b,
} => {
let amm_pool = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&amm_pool)?,
)?;
let vault_holding_a = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&vault_holding_a)?,
)?;
let vault_holding_b = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&vault_holding_b)?,
)?;
let pool_lp = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&pool_lp)?,
)?;
let user_holding_a = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&user_holding_a)?,
)?;
let user_holding_b = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&user_holding_b)?,
)?;
let user_holding_lp = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&user_holding_lp)?,
)?;
let (user_holding_a, user_holding_a_privacy) =
parse_addr_with_privacy_prefix(&user_holding_a)?;
let (user_holding_b, user_holding_b_privacy) =
parse_addr_with_privacy_prefix(&user_holding_b)?;
let (user_holding_lp, user_holding_lp_privacy) =
parse_addr_with_privacy_prefix(&user_holding_lp)?;
let is_public_tx = [
&amm_pool,
&vault_holding_a,
&vault_holding_b,
&pool_lp,
&user_holding_a,
&user_holding_b,
&user_holding_lp,
]
.into_iter()
.all(|acc| acc.is_public());
let user_holding_a: AccountId = user_holding_a.parse()?;
let user_holding_b: AccountId = user_holding_b.parse()?;
let user_holding_lp: AccountId = user_holding_lp.parse()?;
if is_public_tx {
AMM(wallet_core)
.send_add_liq(
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
min_amount_lp,
max_amount_a,
max_amount_b,
)
.await?;
Ok(SubcommandReturnValue::Empty)
} else {
AMM(wallet_core)
.send_add_liq_privacy_preserving(
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
min_amount_lp,
max_amount_a,
max_amount_b,
)
.await?;
// ToDo: change into correct return value
Ok(SubcommandReturnValue::Empty)
match (
user_holding_a_privacy,
user_holding_b_privacy,
user_holding_lp_privacy,
) {
(
AccountPrivacyKind::Public,
AccountPrivacyKind::Public,
AccountPrivacyKind::Public,
) => {
AMM(wallet_core)
.send_add_liq(
user_holding_a,
user_holding_b,
user_holding_lp,
min_amount_lp,
max_amount_a,
max_amount_b,
)
.await?;
Ok(SubcommandReturnValue::Empty)
}
_ => {
// ToDo: Implement after private multi-chain calls is available
anyhow::bail!("Only public execution allowed for AMM calls");
}
}
}
AmmProgramAgnosticSubcommand::RemoveLiquidity {
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
@ -301,73 +241,44 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
max_amount_a,
max_amount_b,
} => {
let amm_pool = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&amm_pool)?,
)?;
let vault_holding_a = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&vault_holding_a)?,
)?;
let vault_holding_b = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&vault_holding_b)?,
)?;
let pool_lp = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&pool_lp)?,
)?;
let user_holding_a = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&user_holding_a)?,
)?;
let user_holding_b = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&user_holding_b)?,
)?;
let user_holding_lp = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&user_holding_lp)?,
)?;
let (user_holding_a, user_holding_a_privacy) =
parse_addr_with_privacy_prefix(&user_holding_a)?;
let (user_holding_b, user_holding_b_privacy) =
parse_addr_with_privacy_prefix(&user_holding_b)?;
let (user_holding_lp, user_holding_lp_privacy) =
parse_addr_with_privacy_prefix(&user_holding_lp)?;
let is_public_tx = [
&amm_pool,
&vault_holding_a,
&vault_holding_b,
&pool_lp,
&user_holding_a,
&user_holding_b,
&user_holding_lp,
]
.into_iter()
.all(|acc| acc.is_public());
let user_holding_a: AccountId = user_holding_a.parse()?;
let user_holding_b: AccountId = user_holding_b.parse()?;
let user_holding_lp: AccountId = user_holding_lp.parse()?;
if is_public_tx {
AMM(wallet_core)
.send_remove_liq(
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
balance_lp,
max_amount_a,
max_amount_b,
)
.await?;
Ok(SubcommandReturnValue::Empty)
} else {
AMM(wallet_core)
.send_remove_liq_privacy_preserving(
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
balance_lp,
max_amount_a,
max_amount_b,
)
.await?;
// ToDo: change into correct return value
Ok(SubcommandReturnValue::Empty)
match (
user_holding_a_privacy,
user_holding_b_privacy,
user_holding_lp_privacy,
) {
(
AccountPrivacyKind::Public,
AccountPrivacyKind::Public,
AccountPrivacyKind::Public,
) => {
AMM(wallet_core)
.send_remove_liq(
user_holding_a,
user_holding_b,
user_holding_lp,
balance_lp,
max_amount_a,
max_amount_b,
)
.await?;
Ok(SubcommandReturnValue::Empty)
}
_ => {
// ToDo: Implement after private multi-chain calls is available
anyhow::bail!("Only public execution allowed for AMM calls");
}
}
}
}

View File

@ -4,6 +4,7 @@ use common::transaction::NSSATransaction;
use nssa::AccountId;
use crate::{
AccDecodeData::Decode,
WalletCore,
cli::{SubcommandReturnValue, WalletSubcommand},
helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix},
@ -87,7 +88,7 @@ impl WalletSubcommand for AuthTransferSubcommand {
.await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![(secret, account_id)];
let acc_decode_data = vec![Decode(secret, account_id)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
tx,
@ -328,7 +329,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
.await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![(secret_from, from), (secret_to, to)];
let acc_decode_data = vec![Decode(secret_from, from), Decode(secret_to, to)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
tx,
@ -372,7 +373,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
.await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![(secret_from, from)];
let acc_decode_data = vec![Decode(secret_from, from)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
tx,
@ -412,7 +413,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
.await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![(secret, to)];
let acc_decode_data = vec![Decode(secret, to)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
tx,
@ -491,7 +492,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
.await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![(secret, from)];
let acc_decode_data = vec![Decode(secret, from)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
tx,

View File

@ -3,6 +3,7 @@ use clap::Subcommand;
use common::{PINATA_BASE58, transaction::NSSATransaction};
use crate::{
AccDecodeData::Decode,
WalletCore,
cli::{SubcommandReturnValue, WalletSubcommand},
helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix},
@ -159,7 +160,7 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate {
println!("Transaction data is {transfer_tx:?}");
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![(secret_winner, winner_account_id)];
let acc_decode_data = vec![Decode(secret_winner, winner_account_id)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
tx,

View File

@ -4,6 +4,7 @@ use common::transaction::NSSATransaction;
use nssa::AccountId;
use crate::{
AccDecodeData::Decode,
WalletCore,
cli::{SubcommandReturnValue, WalletSubcommand},
helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix},
@ -421,8 +422,8 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![
(secret_sender, sender_account_id),
(secret_recipient, recipient_account_id),
Decode(secret_sender, sender_account_id),
Decode(secret_recipient, recipient_account_id),
];
wallet_core.decode_insert_privacy_preserving_transaction_results(
@ -473,7 +474,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
.await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![(secret_sender, sender_account_id)];
let acc_decode_data = vec![Decode(secret_sender, sender_account_id)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
tx,
@ -521,7 +522,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded {
.await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![(secret_sender, sender_account_id)];
let acc_decode_data = vec![Decode(secret_sender, sender_account_id)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
tx,
@ -614,7 +615,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
.await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![(secret_recipient, recipient_account_id)];
let acc_decode_data = vec![Decode(secret_recipient, recipient_account_id)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
tx,
@ -673,8 +674,8 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand {
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![
(secret_definition, definition_account_id),
(secret_supply, supply_account_id),
Decode(secret_definition, definition_account_id),
Decode(secret_supply, supply_account_id),
];
wallet_core.decode_insert_privacy_preserving_transaction_results(
@ -723,7 +724,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand {
.await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![(secret_definition, definition_account_id)];
let acc_decode_data = vec![Decode(secret_definition, definition_account_id)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
tx,
@ -771,7 +772,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand {
.await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![(secret_supply, supply_account_id)];
let acc_decode_data = vec![Decode(secret_supply, supply_account_id)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
tx,

View File

@ -38,6 +38,11 @@ pub mod poller;
mod privacy_preserving_tx;
pub mod program_facades;
pub enum AccDecodeData {
Skip,
Decode(nssa_core::SharedSecretKey, AccountId),
}
pub struct WalletCore {
pub storage: WalletChainStore,
pub poller: TxPoller,
@ -218,28 +223,32 @@ impl WalletCore {
pub fn decode_insert_privacy_preserving_transaction_results(
&mut self,
tx: nssa::privacy_preserving_transaction::PrivacyPreservingTransaction,
acc_decode_data: &[(nssa_core::SharedSecretKey, AccountId)],
acc_decode_mask: &[AccDecodeData],
) -> Result<()> {
for (output_index, (secret, acc_account_id)) in acc_decode_data.iter().enumerate() {
let acc_ead = tx.message.encrypted_private_post_states[output_index].clone();
let acc_comm = tx.message.new_commitments[output_index].clone();
for (output_index, acc_decode_data) in acc_decode_mask.iter().enumerate() {
match acc_decode_data {
AccDecodeData::Decode(secret, acc_account_id) => {
let acc_ead = tx.message.encrypted_private_post_states[output_index].clone();
let acc_comm = tx.message.new_commitments[output_index].clone();
let res_acc = nssa_core::EncryptionScheme::decrypt(
&acc_ead.ciphertext,
secret,
&acc_comm,
output_index as u32,
)
.unwrap();
let res_acc = nssa_core::EncryptionScheme::decrypt(
&acc_ead.ciphertext,
secret,
&acc_comm,
output_index as u32,
)
.unwrap();
println!("Received new acc {res_acc:#?}");
println!("Received new acc {res_acc:#?}");
self.storage
.insert_private_account_data(*acc_account_id, res_acc);
self.storage
.insert_private_account_data(*acc_account_id, res_acc);
}
AccDecodeData::Skip => {}
}
}
println!("Transaction data is {:?}", tx.message);
Ok(())
}

View File

@ -8,7 +8,7 @@ use nssa_core::{
encryption::{EphemeralPublicKey, IncomingViewingPublicKey},
};
use crate::{WalletCore, helperfunctions::AccountPrivacyKind};
use crate::WalletCore;
#[derive(Clone)]
pub enum PrivacyPreservingAccount {
@ -21,15 +21,6 @@ pub enum PrivacyPreservingAccount {
}
impl PrivacyPreservingAccount {
pub fn parse_with_privacy(input: (String, AccountPrivacyKind)) -> Result<Self> {
let acc_id: AccountId = input.0.parse()?;
match input.1 {
AccountPrivacyKind::Public => Ok(Self::Public(acc_id)),
AccountPrivacyKind::Private => Ok(Self::PrivateOwned(acc_id)),
}
}
pub fn is_public(&self) -> bool {
matches!(&self, Self::Public(_))
}

View File

@ -1,279 +1,108 @@
use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse};
use nssa::{AccountId, ProgramId, program::Program};
use nssa_core::{SharedSecretKey, program::PdaSeed};
use serde::{Serialize, ser::SerializeSeq};
use nssa::{AccountId, program::Program};
use crate::{PrivacyPreservingAccount, WalletCore, cli::account::TokenHolding};
fn compute_pool_pda(
amm_program_id: ProgramId,
definition_token_a_id: AccountId,
definition_token_b_id: AccountId,
) -> AccountId {
AccountId::from((
&amm_program_id,
&compute_pool_pda_seed(definition_token_a_id, definition_token_b_id),
))
}
fn compute_pool_pda_seed(
definition_token_a_id: AccountId,
definition_token_b_id: AccountId,
) -> PdaSeed {
use risc0_zkvm::sha::{Impl, Sha256};
let mut i: usize = 0;
let (token_1, token_2) = loop {
if definition_token_a_id.value()[i] > definition_token_b_id.value()[i] {
let token_1 = definition_token_a_id;
let token_2 = definition_token_b_id;
break (token_1, token_2);
} else if definition_token_a_id.value()[i] < definition_token_b_id.value()[i] {
let token_1 = definition_token_b_id;
let token_2 = definition_token_a_id;
break (token_1, token_2);
}
if i == 32 {
panic!("Definitions match");
} else {
i += 1;
}
};
let mut bytes = [0; 64];
bytes[0..32].copy_from_slice(&token_1.to_bytes());
bytes[32..].copy_from_slice(&token_2.to_bytes());
PdaSeed::new(
Impl::hash_bytes(&bytes)
.as_bytes()
.try_into()
.expect("Hash output must be exactly 32 bytes long"),
)
}
fn compute_vault_pda(
amm_program_id: ProgramId,
pool_id: AccountId,
definition_token_id: AccountId,
) -> AccountId {
AccountId::from((
&amm_program_id,
&compute_vault_pda_seed(pool_id, definition_token_id),
))
}
fn compute_vault_pda_seed(pool_id: AccountId, definition_token_id: AccountId) -> PdaSeed {
use risc0_zkvm::sha::{Impl, Sha256};
let mut bytes = [0; 64];
bytes[0..32].copy_from_slice(&pool_id.to_bytes());
bytes[32..].copy_from_slice(&definition_token_id.to_bytes());
PdaSeed::new(
Impl::hash_bytes(&bytes)
.as_bytes()
.try_into()
.expect("Hash output must be exactly 32 bytes long"),
)
}
fn compute_liquidity_token_pda(amm_program_id: ProgramId, pool_id: AccountId) -> AccountId {
AccountId::from((&amm_program_id, &compute_liquidity_token_pda_seed(pool_id)))
}
fn compute_liquidity_token_pda_seed(pool_id: AccountId) -> PdaSeed {
use risc0_zkvm::sha::{Impl, Sha256};
let mut bytes = [0; 64];
bytes[0..32].copy_from_slice(&pool_id.to_bytes());
bytes[32..].copy_from_slice(&[0; 32]);
PdaSeed::new(
Impl::hash_bytes(&bytes)
.as_bytes()
.try_into()
.expect("Hash output must be exactly 32 bytes long"),
)
}
struct OrphanHack65BytesInput([u32; 65]);
impl OrphanHack65BytesInput {
fn expand(orig: [u8; 65]) -> Self {
let mut res = [0u32; 65];
for (idx, val) in orig.into_iter().enumerate() {
res[idx] = val as u32;
}
Self(res)
}
}
impl Serialize for OrphanHack65BytesInput {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut seq = serializer.serialize_seq(Some(65))?;
for word in self.0 {
seq.serialize_element(&word)?;
}
seq.end()
}
}
struct OrphanHack49BytesInput([u32; 49]);
impl OrphanHack49BytesInput {
fn expand(orig: [u8; 49]) -> Self {
let mut res = [0u32; 49];
for (idx, val) in orig.into_iter().enumerate() {
res[idx] = val as u32;
}
Self(res)
}
fn words(&self) -> Vec<u32> {
self.0.to_vec()
}
}
impl Serialize for OrphanHack49BytesInput {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut seq = serializer.serialize_seq(Some(49))?;
for word in self.0 {
seq.serialize_element(&word)?;
}
seq.end()
}
}
use crate::{
WalletCore,
cli::account::TokenHolding,
program_facades::{
OrphanHack49BytesInput, OrphanHack65BytesInput, compute_liquidity_token_pda,
compute_pool_pda, compute_vault_pda,
},
};
pub struct AMM<'w>(pub &'w WalletCore);
impl AMM<'_> {
#[allow(clippy::too_many_arguments)]
pub async fn send_new_amm_definition(
&self,
user_holding_a: PrivacyPreservingAccount,
user_holding_b: PrivacyPreservingAccount,
user_holding_lp: PrivacyPreservingAccount,
user_holding_a: AccountId,
user_holding_b: AccountId,
user_holding_lp: AccountId,
balance_a: u128,
balance_b: u128,
) -> Result<SendTxResponse, ExecutionFailureKind> {
let (instruction, program) = amm_program_preparation_definition(balance_a, balance_b);
match (user_holding_a, user_holding_b, user_holding_lp) {
(
PrivacyPreservingAccount::Public(user_holding_a),
PrivacyPreservingAccount::Public(user_holding_b),
PrivacyPreservingAccount::Public(user_holding_lp),
) => {
let amm_program_id = Program::amm().id();
let amm_program_id = Program::amm().id();
let Ok(user_a_acc) = self.0.get_account_public(user_holding_a).await else {
return Err(ExecutionFailureKind::SequencerError);
};
let Ok(user_b_acc) = self.0.get_account_public(user_holding_b).await else {
return Err(ExecutionFailureKind::SequencerError);
};
let Ok(user_a_acc) = self.0.get_account_public(user_holding_a).await else {
return Err(ExecutionFailureKind::SequencerError);
};
let Ok(user_b_acc) = self.0.get_account_public(user_holding_b).await else {
return Err(ExecutionFailureKind::SequencerError);
};
let definition_token_a_id = TokenHolding::parse(&user_a_acc.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id;
let definition_token_b_id = TokenHolding::parse(&user_b_acc.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id;
let definition_token_a_id = TokenHolding::parse(&user_a_acc.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id;
let definition_token_b_id = TokenHolding::parse(&user_b_acc.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id;
let amm_pool =
compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id);
let vault_holding_a =
compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
let vault_holding_b =
compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
let pool_lp = compute_liquidity_token_pda(amm_program_id, amm_pool);
let amm_pool =
compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id);
let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
let pool_lp = compute_liquidity_token_pda(amm_program_id, amm_pool);
let account_ids = vec![
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
];
let account_ids = vec![
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
];
let Ok(nonces) = self
.0
.get_accounts_nonces(vec![user_holding_a, user_holding_b])
.await
else {
return Err(ExecutionFailureKind::SequencerError);
};
let Ok(nonces) = self
.0
.get_accounts_nonces(vec![user_holding_a, user_holding_b])
.await
else {
return Err(ExecutionFailureKind::SequencerError);
};
let Some(signing_key_a) = self
.0
.storage
.user_data
.get_pub_account_signing_key(&user_holding_a)
else {
return Err(ExecutionFailureKind::KeyNotFoundError);
};
let Some(signing_key_a) = self
.0
.storage
.user_data
.get_pub_account_signing_key(&user_holding_a)
else {
return Err(ExecutionFailureKind::KeyNotFoundError);
};
let Some(signing_key_b) = self
.0
.storage
.user_data
.get_pub_account_signing_key(&user_holding_b)
else {
return Err(ExecutionFailureKind::KeyNotFoundError);
};
let Some(signing_key_b) = self
.0
.storage
.user_data
.get_pub_account_signing_key(&user_holding_b)
else {
return Err(ExecutionFailureKind::KeyNotFoundError);
};
let message = nssa::public_transaction::Message::try_new(
program.id(),
account_ids,
nonces,
instruction,
)
.unwrap();
let message = nssa::public_transaction::Message::try_new(
program.id(),
account_ids,
nonces,
instruction,
)
.unwrap();
let witness_set = nssa::public_transaction::WitnessSet::for_message(
&message,
&[signing_key_a, signing_key_b],
);
let witness_set = nssa::public_transaction::WitnessSet::for_message(
&message,
&[signing_key_a, signing_key_b],
);
let tx = nssa::PublicTransaction::new(message, witness_set);
let tx = nssa::PublicTransaction::new(message, witness_set);
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
}
_ => unreachable!(),
}
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
}
#[allow(clippy::too_many_arguments)]
pub async fn send_new_amm_definition_privacy_preserving(
&self,
_user_holding_a: PrivacyPreservingAccount,
_user_holding_b: PrivacyPreservingAccount,
_user_holding_lp: PrivacyPreservingAccount,
_balance_a: u128,
_balance_b: u128,
) -> Result<(SendTxResponse, [Option<SharedSecretKey>; 3]), ExecutionFailureKind> {
todo!()
}
#[allow(clippy::too_many_arguments)]
pub async fn send_swap(
&self,
user_holding_a: PrivacyPreservingAccount,
user_holding_b: PrivacyPreservingAccount,
user_holding_a: AccountId,
user_holding_b: AccountId,
amount_in: u128,
min_amount_out: u128,
token_definition_id: AccountId,
@ -281,162 +110,96 @@ impl AMM<'_> {
let (instruction, program) =
amm_program_preparation_swap(amount_in, min_amount_out, token_definition_id);
match (user_holding_a, user_holding_b) {
(
PrivacyPreservingAccount::Public(user_holding_a),
PrivacyPreservingAccount::Public(user_holding_b),
) => {
let amm_program_id = Program::amm().id();
let amm_program_id = Program::amm().id();
let Ok(user_a_acc) = self.0.get_account_public(user_holding_a).await else {
return Err(ExecutionFailureKind::SequencerError);
};
let Ok(user_b_acc) = self.0.get_account_public(user_holding_b).await else {
return Err(ExecutionFailureKind::SequencerError);
};
let Ok(user_a_acc) = self.0.get_account_public(user_holding_a).await else {
return Err(ExecutionFailureKind::SequencerError);
};
let Ok(user_b_acc) = self.0.get_account_public(user_holding_b).await else {
return Err(ExecutionFailureKind::SequencerError);
};
let definition_token_a_id = TokenHolding::parse(&user_a_acc.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id;
let definition_token_b_id = TokenHolding::parse(&user_b_acc.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id;
let definition_token_a_id = TokenHolding::parse(&user_a_acc.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id;
let definition_token_b_id = TokenHolding::parse(&user_b_acc.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id;
let amm_pool =
compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id);
let vault_holding_a =
compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
let vault_holding_b =
compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
let amm_pool =
compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id);
let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
let account_ids = vec![
amm_pool,
vault_holding_a,
vault_holding_b,
user_holding_a,
user_holding_b,
];
let account_ids = vec![
amm_pool,
vault_holding_a,
vault_holding_b,
user_holding_a,
user_holding_b,
];
let account_id_auth;
let account_id_auth;
// Checking, which account are associated with TokenDefinition
let token_holder_acc_a = self
.0
.get_account_public(user_holding_a)
.await
.map_err(|_| ExecutionFailureKind::SequencerError)?;
let token_holder_acc_b = self
.0
.get_account_public(user_holding_b)
.await
.map_err(|_| ExecutionFailureKind::SequencerError)?;
// Checking, which account are associated with TokenDefinition
let token_holder_acc_a = self
.0
.get_account_public(user_holding_a)
.await
.map_err(|_| ExecutionFailureKind::SequencerError)?;
let token_holder_acc_b = self
.0
.get_account_public(user_holding_b)
.await
.map_err(|_| ExecutionFailureKind::SequencerError)?;
let token_holder_a = TokenHolding::parse(&token_holder_acc_a.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))?;
let token_holder_b = TokenHolding::parse(&token_holder_acc_b.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_b))?;
let token_holder_a = TokenHolding::parse(&token_holder_acc_a.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))?;
let token_holder_b = TokenHolding::parse(&token_holder_acc_b.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_b))?;
if token_holder_a.definition_id == token_definition_id {
account_id_auth = user_holding_a;
} else if token_holder_b.definition_id == token_definition_id {
account_id_auth = user_holding_b;
} else {
return Err(ExecutionFailureKind::AccountDataError(token_definition_id));
}
let Ok(nonces) = self.0.get_accounts_nonces(vec![account_id_auth]).await else {
return Err(ExecutionFailureKind::SequencerError);
};
let Some(signing_key) = self
.0
.storage
.user_data
.get_pub_account_signing_key(&account_id_auth)
else {
return Err(ExecutionFailureKind::KeyNotFoundError);
};
let message = nssa::public_transaction::Message::try_new(
program.id(),
account_ids,
nonces,
instruction,
)
.unwrap();
let witness_set =
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
let tx = nssa::PublicTransaction::new(message, witness_set);
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
}
_ => unreachable!(),
if token_holder_a.definition_id == token_definition_id {
account_id_auth = user_holding_a;
} else if token_holder_b.definition_id == token_definition_id {
account_id_auth = user_holding_b;
} else {
return Err(ExecutionFailureKind::AccountDataError(token_definition_id));
}
let Ok(nonces) = self.0.get_accounts_nonces(vec![account_id_auth]).await else {
return Err(ExecutionFailureKind::SequencerError);
};
let Some(signing_key) = self
.0
.storage
.user_data
.get_pub_account_signing_key(&account_id_auth)
else {
return Err(ExecutionFailureKind::KeyNotFoundError);
};
let message = nssa::public_transaction::Message::try_new(
program.id(),
account_ids,
nonces,
instruction,
)
.unwrap();
let witness_set =
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
let tx = nssa::PublicTransaction::new(message, witness_set);
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
}
#[allow(clippy::too_many_arguments)]
pub async fn send_swap_privacy_preserving(
&self,
_user_holding_a: PrivacyPreservingAccount,
_user_holding_b: PrivacyPreservingAccount,
_amount_in: u128,
_min_amount_out: u128,
_token_definition_id: AccountId,
) -> Result<(SendTxResponse, [Option<SharedSecretKey>; 5]), ExecutionFailureKind> {
todo!()
// let (instruction_data, program) =
// amm_program_preparation_swap(amount_in, min_amount_out, token_definition_id);
// self.0
// .send_privacy_preserving_tx(
// vec![
// amm_pool.clone(),
// vault_holding_1.clone(),
// vault_holding_2.clone(),
// user_holding_a.clone(),
// user_holding_b.clone(),
// ],
// &instruction_data.words(),
// &program,
// )
// .await
// .map(|(resp, secrets)| {
// let mut secrets = secrets.into_iter();
// let mut secrets_res = [None; 5];
// for acc_id in [
// amm_pool,
// vault_holding_1,
// vault_holding_2,
// user_holding_a,
// user_holding_b,
// ]
// .iter()
// .enumerate()
// {
// if acc_id.1.is_private() {
// let secret = secrets.next().expect("expected next secret");
// secrets_res[acc_id.0] = Some(secret);
// }
// }
// (resp, secrets_res)
// })
}
#[allow(clippy::too_many_arguments)]
pub async fn send_add_liq(
&self,
amm_pool: PrivacyPreservingAccount,
vault_holding_a: PrivacyPreservingAccount,
vault_holding_b: PrivacyPreservingAccount,
pool_lp: PrivacyPreservingAccount,
user_holding_a: PrivacyPreservingAccount,
user_holding_b: PrivacyPreservingAccount,
user_holding_lp: PrivacyPreservingAccount,
user_holding_a: AccountId,
user_holding_b: AccountId,
user_holding_lp: AccountId,
min_amount_lp: u128,
max_amount_a: u128,
max_amount_b: u128,
@ -444,7 +207,29 @@ impl AMM<'_> {
let (instruction, program) =
amm_program_preparation_add_liq(min_amount_lp, max_amount_a, max_amount_b);
match (
let amm_program_id = Program::amm().id();
let Ok(user_a_acc) = self.0.get_account_public(user_holding_a).await else {
return Err(ExecutionFailureKind::SequencerError);
};
let Ok(user_b_acc) = self.0.get_account_public(user_holding_b).await else {
return Err(ExecutionFailureKind::SequencerError);
};
let definition_token_a_id = TokenHolding::parse(&user_a_acc.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id;
let definition_token_b_id = TokenHolding::parse(&user_b_acc.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id;
let amm_pool =
compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id);
let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
let pool_lp = compute_liquidity_token_pda(amm_program_id, amm_pool);
let account_ids = vec![
amm_pool,
vault_holding_a,
vault_holding_b,
@ -452,142 +237,57 @@ impl AMM<'_> {
user_holding_a,
user_holding_b,
user_holding_lp,
) {
(
PrivacyPreservingAccount::Public(amm_pool),
PrivacyPreservingAccount::Public(vault_holding_a),
PrivacyPreservingAccount::Public(vault_holding_b),
PrivacyPreservingAccount::Public(pool_lp),
PrivacyPreservingAccount::Public(user_holding_a),
PrivacyPreservingAccount::Public(user_holding_b),
PrivacyPreservingAccount::Public(user_holding_lp),
) => {
let account_ids = vec![
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
];
];
let Ok(nonces) = self
.0
.get_accounts_nonces(vec![user_holding_a, user_holding_b])
.await
else {
return Err(ExecutionFailureKind::SequencerError);
};
let Some(signing_key_a) = self
.0
.storage
.user_data
.get_pub_account_signing_key(&user_holding_a)
else {
return Err(ExecutionFailureKind::KeyNotFoundError);
};
let Some(signing_key_b) = self
.0
.storage
.user_data
.get_pub_account_signing_key(&user_holding_b)
else {
return Err(ExecutionFailureKind::KeyNotFoundError);
};
let message = nssa::public_transaction::Message::try_new(
program.id(),
account_ids,
nonces,
instruction,
)
.unwrap();
let witness_set = nssa::public_transaction::WitnessSet::for_message(
&message,
&[signing_key_a, signing_key_b],
);
let tx = nssa::PublicTransaction::new(message, witness_set);
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
}
_ => unreachable!(),
}
}
#[allow(clippy::too_many_arguments)]
pub async fn send_add_liq_privacy_preserving(
&self,
amm_pool: PrivacyPreservingAccount,
vault_holding_a: PrivacyPreservingAccount,
vault_holding_b: PrivacyPreservingAccount,
pool_lp: PrivacyPreservingAccount,
user_holding_a: PrivacyPreservingAccount,
user_holding_b: PrivacyPreservingAccount,
user_holding_lp: PrivacyPreservingAccount,
min_amount_lp: u128,
max_amount_a: u128,
max_amount_b: u128,
) -> Result<(SendTxResponse, [Option<SharedSecretKey>; 7]), ExecutionFailureKind> {
let (instruction_data, program) =
amm_program_preparation_add_liq(min_amount_lp, max_amount_a, max_amount_b);
self.0
.send_privacy_preserving_tx(
vec![
amm_pool.clone(),
vault_holding_a.clone(),
vault_holding_b.clone(),
pool_lp.clone(),
user_holding_a.clone(),
user_holding_b.clone(),
user_holding_lp.clone(),
],
&instruction_data.words(),
&program,
)
let Ok(nonces) = self
.0
.get_accounts_nonces(vec![user_holding_a, user_holding_b])
.await
.map(|(resp, secrets)| {
let mut secrets = secrets.into_iter();
let mut secrets_res = [None; 7];
else {
return Err(ExecutionFailureKind::SequencerError);
};
for acc_id in [
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
]
.iter()
.enumerate()
{
if acc_id.1.is_private() {
let secret = secrets.next().expect("expected next secret");
let Some(signing_key_a) = self
.0
.storage
.user_data
.get_pub_account_signing_key(&user_holding_a)
else {
return Err(ExecutionFailureKind::KeyNotFoundError);
};
secrets_res[acc_id.0] = Some(secret);
}
}
let Some(signing_key_b) = self
.0
.storage
.user_data
.get_pub_account_signing_key(&user_holding_b)
else {
return Err(ExecutionFailureKind::KeyNotFoundError);
};
(resp, secrets_res)
})
let message = nssa::public_transaction::Message::try_new(
program.id(),
account_ids,
nonces,
instruction,
)
.unwrap();
let witness_set = nssa::public_transaction::WitnessSet::for_message(
&message,
&[signing_key_a, signing_key_b],
);
let tx = nssa::PublicTransaction::new(message, witness_set);
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
}
#[allow(clippy::too_many_arguments)]
pub async fn send_remove_liq(
&self,
amm_pool: PrivacyPreservingAccount,
vault_holding_a: PrivacyPreservingAccount,
vault_holding_b: PrivacyPreservingAccount,
pool_lp: PrivacyPreservingAccount,
user_holding_a: PrivacyPreservingAccount,
user_holding_b: PrivacyPreservingAccount,
user_holding_lp: PrivacyPreservingAccount,
user_holding_a: AccountId,
user_holding_b: AccountId,
user_holding_lp: AccountId,
balance_lp: u128,
max_amount_a: u128,
max_amount_b: u128,
@ -595,7 +295,29 @@ impl AMM<'_> {
let (instruction, program) =
amm_program_preparation_remove_liq(balance_lp, max_amount_a, max_amount_b);
match (
let amm_program_id = Program::amm().id();
let Ok(user_a_acc) = self.0.get_account_public(user_holding_a).await else {
return Err(ExecutionFailureKind::SequencerError);
};
let Ok(user_b_acc) = self.0.get_account_public(user_holding_b).await else {
return Err(ExecutionFailureKind::SequencerError);
};
let definition_token_a_id = TokenHolding::parse(&user_a_acc.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id;
let definition_token_b_id = TokenHolding::parse(&user_b_acc.data)
.ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id;
let amm_pool =
compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id);
let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
let pool_lp = compute_liquidity_token_pda(amm_program_id, amm_pool);
let account_ids = vec![
amm_pool,
vault_holding_a,
vault_holding_b,
@ -603,134 +325,38 @@ impl AMM<'_> {
user_holding_a,
user_holding_b,
user_holding_lp,
) {
(
PrivacyPreservingAccount::Public(amm_pool),
PrivacyPreservingAccount::Public(vault_holding_a),
PrivacyPreservingAccount::Public(vault_holding_b),
PrivacyPreservingAccount::Public(pool_lp),
PrivacyPreservingAccount::Public(user_holding_a),
PrivacyPreservingAccount::Public(user_holding_b),
PrivacyPreservingAccount::Public(user_holding_lp),
) => {
let account_ids = vec![
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
];
];
let Ok(nonces) = self
.0
.get_accounts_nonces(vec![user_holding_a, user_holding_b])
.await
else {
return Err(ExecutionFailureKind::SequencerError);
};
let Ok(nonces) = self.0.get_accounts_nonces(vec![user_holding_lp]).await else {
return Err(ExecutionFailureKind::SequencerError);
};
let Some(signing_key_a) = self
.0
.storage
.user_data
.get_pub_account_signing_key(&user_holding_a)
else {
return Err(ExecutionFailureKind::KeyNotFoundError);
};
let Some(signing_key_lp) = self
.0
.storage
.user_data
.get_pub_account_signing_key(&user_holding_lp)
else {
return Err(ExecutionFailureKind::KeyNotFoundError);
};
let Some(signing_key_b) = self
.0
.storage
.user_data
.get_pub_account_signing_key(&user_holding_b)
else {
return Err(ExecutionFailureKind::KeyNotFoundError);
};
let message = nssa::public_transaction::Message::try_new(
program.id(),
account_ids,
nonces,
instruction,
)
.unwrap();
let message = nssa::public_transaction::Message::try_new(
program.id(),
account_ids,
nonces,
instruction,
)
.unwrap();
let witness_set =
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key_lp]);
let witness_set = nssa::public_transaction::WitnessSet::for_message(
&message,
&[signing_key_a, signing_key_b],
);
let tx = nssa::PublicTransaction::new(message, witness_set);
let tx = nssa::PublicTransaction::new(message, witness_set);
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
}
_ => unreachable!(),
}
}
#[allow(clippy::too_many_arguments)]
pub async fn send_remove_liq_privacy_preserving(
&self,
amm_pool: PrivacyPreservingAccount,
vault_holding_a: PrivacyPreservingAccount,
vault_holding_b: PrivacyPreservingAccount,
pool_lp: PrivacyPreservingAccount,
user_holding_a: PrivacyPreservingAccount,
user_holding_b: PrivacyPreservingAccount,
user_holding_lp: PrivacyPreservingAccount,
balance_lp: u128,
max_amount_a: u128,
max_amount_b: u128,
) -> Result<(SendTxResponse, [Option<SharedSecretKey>; 7]), ExecutionFailureKind> {
let (instruction_data, program) =
amm_program_preparation_remove_liq(balance_lp, max_amount_a, max_amount_b);
self.0
.send_privacy_preserving_tx(
vec![
amm_pool.clone(),
vault_holding_a.clone(),
vault_holding_b.clone(),
pool_lp.clone(),
user_holding_a.clone(),
user_holding_b.clone(),
user_holding_lp.clone(),
],
&instruction_data.words(),
&program,
)
.await
.map(|(resp, secrets)| {
let mut secrets = secrets.into_iter();
let mut secrets_res = [None; 7];
for acc_id in [
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
]
.iter()
.enumerate()
{
if acc_id.1.is_private() {
let secret = secrets.next().expect("expected next secret");
secrets_res[acc_id.0] = Some(secret);
}
}
(resp, secrets_res)
})
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
}
}
#[allow(unused)]
fn amm_program_preparation_definition(
balance_a: u128,
balance_b: u128,

View File

@ -1,7 +1,142 @@
//! This module contains [`WalletCore`](crate::WalletCore) facades for interacting with various
//! on-chain programs.
use nssa::{AccountId, ProgramId};
use nssa_core::program::PdaSeed;
use serde::{Serialize, ser::SerializeSeq};
pub mod amm;
pub mod native_token_transfer;
pub mod pinata;
pub mod token;
fn compute_pool_pda(
amm_program_id: ProgramId,
definition_token_a_id: AccountId,
definition_token_b_id: AccountId,
) -> AccountId {
AccountId::from((
&amm_program_id,
&compute_pool_pda_seed(definition_token_a_id, definition_token_b_id),
))
}
fn compute_pool_pda_seed(
definition_token_a_id: AccountId,
definition_token_b_id: AccountId,
) -> PdaSeed {
use risc0_zkvm::sha::{Impl, Sha256};
let mut i: usize = 0;
let (token_1, token_2) = loop {
if definition_token_a_id.value()[i] > definition_token_b_id.value()[i] {
let token_1 = definition_token_a_id;
let token_2 = definition_token_b_id;
break (token_1, token_2);
} else if definition_token_a_id.value()[i] < definition_token_b_id.value()[i] {
let token_1 = definition_token_b_id;
let token_2 = definition_token_a_id;
break (token_1, token_2);
}
if i == 32 {
panic!("Definitions match");
} else {
i += 1;
}
};
let mut bytes = [0; 64];
bytes[0..32].copy_from_slice(&token_1.to_bytes());
bytes[32..].copy_from_slice(&token_2.to_bytes());
PdaSeed::new(
Impl::hash_bytes(&bytes)
.as_bytes()
.try_into()
.expect("Hash output must be exactly 32 bytes long"),
)
}
fn compute_vault_pda(
amm_program_id: ProgramId,
pool_id: AccountId,
definition_token_id: AccountId,
) -> AccountId {
AccountId::from((
&amm_program_id,
&compute_vault_pda_seed(pool_id, definition_token_id),
))
}
fn compute_vault_pda_seed(pool_id: AccountId, definition_token_id: AccountId) -> PdaSeed {
use risc0_zkvm::sha::{Impl, Sha256};
let mut bytes = [0; 64];
bytes[0..32].copy_from_slice(&pool_id.to_bytes());
bytes[32..].copy_from_slice(&definition_token_id.to_bytes());
PdaSeed::new(
Impl::hash_bytes(&bytes)
.as_bytes()
.try_into()
.expect("Hash output must be exactly 32 bytes long"),
)
}
fn compute_liquidity_token_pda(amm_program_id: ProgramId, pool_id: AccountId) -> AccountId {
AccountId::from((&amm_program_id, &compute_liquidity_token_pda_seed(pool_id)))
}
fn compute_liquidity_token_pda_seed(pool_id: AccountId) -> PdaSeed {
use risc0_zkvm::sha::{Impl, Sha256};
let mut bytes = [0; 64];
bytes[0..32].copy_from_slice(&pool_id.to_bytes());
bytes[32..].copy_from_slice(&[0; 32]);
PdaSeed::new(
Impl::hash_bytes(&bytes)
.as_bytes()
.try_into()
.expect("Hash output must be exactly 32 bytes long"),
)
}
/// Why it is necessary:
///
/// Serialize implemented only for `[u8; N]` where `N<=32` and orphan rules would disallow custom
/// Serialize impls for them.
///
/// Additionally, RISC0 splits instructions into words of 4-byte size which glues bytes for custom
/// structs so we need to expand each byte into `u32` to preserve shape, because AMM awaits
/// `Vec<u8>` as instruction.
struct OrphanHackNBytesInput<const N: usize>([u32; N]);
impl<const N: usize> OrphanHackNBytesInput<N> {
fn expand(orig: [u8; N]) -> Self {
let mut res = [0u32; N];
for (idx, val) in orig.into_iter().enumerate() {
res[idx] = val as u32;
}
Self(res)
}
}
impl<const N: usize> Serialize for OrphanHackNBytesInput<N> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut seq = serializer.serialize_seq(Some(N))?;
for word in self.0 {
seq.serialize_element(&word)?;
}
seq.end()
}
}
type OrphanHack65BytesInput = OrphanHackNBytesInput<65>;
type OrphanHack49BytesInput = OrphanHackNBytesInput<49>;