fix: public swaps

This commit is contained in:
Pravdyvy 2025-12-17 14:21:36 +02:00
parent b3dca76b67
commit 92b5dffec2
7 changed files with 394 additions and 251 deletions

View File

@ -2042,7 +2042,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
// Create new account for the token definition
let SubcommandReturnValue::RegisterAccount {
account_id: definition_account_id,
account_id: definition_account_id_1,
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
NewSubcommand::Public { cci: None },
)))
@ -2053,7 +2053,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
};
// Create new account for the token supply holder
let SubcommandReturnValue::RegisterAccount {
account_id: supply_account_id,
account_id: supply_account_id_1,
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
NewSubcommand::Public { cci: None },
)))
@ -2073,6 +2073,28 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
else {
panic!("invalid subcommand return value");
};
// Create new account for the token definition
let SubcommandReturnValue::RegisterAccount {
account_id: definition_account_id_2,
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
NewSubcommand::Public { cci: None },
)))
.await
.unwrap()
else {
panic!("invalid subcommand return value");
};
// Create new account for the token supply holder
let SubcommandReturnValue::RegisterAccount {
account_id: supply_account_id_2,
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
NewSubcommand::Public { cci: None },
)))
.await
.unwrap()
else {
panic!("invalid subcommand return value");
};
// Create new account for receiving a token transaction
let SubcommandReturnValue::RegisterAccount {
account_id: recipient_account_id_2,
@ -2088,10 +2110,10 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
// Create new token
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_account_id: make_public_account_input_from_str(
&definition_account_id.to_string(),
&definition_account_id_1.to_string(),
),
supply_account_id: make_public_account_input_from_str(&supply_account_id.to_string()),
name: "A NAME".to_string(),
supply_account_id: make_public_account_input_from_str(&supply_account_id_1.to_string()),
name: "A NAM1".to_string(),
total_supply: 37,
};
wallet::cli::execute_subcommand(Command::Token(subcommand))
@ -2100,11 +2122,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
info!("Waiting for next block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
// Transfer 7 tokens from `supply_acc` to the account at account_id `recipient_account_id_1`
let subcommand = TokenProgramAgnosticSubcommand::Send {
from: make_public_account_input_from_str(&supply_account_id.to_string()),
from: make_public_account_input_from_str(&supply_account_id_1.to_string()),
to: Some(make_public_account_input_from_str(
&recipient_account_id_1.to_string(),
)),
@ -2119,9 +2139,26 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
info!("Waiting for next block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
// Transfer 7 tokens from `supply_acc` to the account at account_id `recipient_account_id_2`
// Create new token
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_account_id: make_public_account_input_from_str(
&definition_account_id_2.to_string(),
),
supply_account_id: make_public_account_input_from_str(&supply_account_id_2.to_string()),
name: "A NAM2".to_string(),
total_supply: 37,
};
wallet::cli::execute_subcommand(Command::Token(subcommand))
.await
.unwrap();
info!("Waiting for next block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
// Transfer 7 tokens from `supply_acc` to the account at account_id `recipient_account_id_1`
let subcommand = TokenProgramAgnosticSubcommand::Send {
from: make_public_account_input_from_str(&supply_account_id.to_string()),
from: make_public_account_input_from_str(&supply_account_id_2.to_string()),
to: Some(make_public_account_input_from_str(
&recipient_account_id_2.to_string(),
)),
@ -2141,50 +2178,6 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
// Create new AMM
// Setup accounts
// Create new account for the amm pool
let SubcommandReturnValue::RegisterAccount {
account_id: amm_pool,
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
NewSubcommand::Public { cci: None },
)))
.await
.unwrap()
else {
panic!("invalid subcommand return value");
};
// Create new account for the vault a
let SubcommandReturnValue::RegisterAccount {
account_id: vault_holding_a,
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
NewSubcommand::Public { cci: None },
)))
.await
.unwrap()
else {
panic!("invalid subcommand return value");
};
// Create new account for the vault b
let SubcommandReturnValue::RegisterAccount {
account_id: vault_holding_b,
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
NewSubcommand::Public { cci: None },
)))
.await
.unwrap()
else {
panic!("invalid subcommand return value");
};
// Create new account for the pool lp
let SubcommandReturnValue::RegisterAccount {
account_id: pool_lp,
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
NewSubcommand::Public { cci: None },
)))
.await
.unwrap()
else {
panic!("invalid subcommand return value");
};
// Create new account for the user holding lp
let SubcommandReturnValue::RegisterAccount {
account_id: user_holding_lp,
@ -2199,10 +2192,6 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
// Send creation tx
let subcommand = AmmProgramAgnosticSubcommand::New {
amm_pool: make_public_account_input_from_str(&amm_pool.to_string()),
vault_holding_a: make_public_account_input_from_str(&vault_holding_a.to_string()),
vault_holding_b: make_public_account_input_from_str(&vault_holding_b.to_string()),
pool_lp: make_public_account_input_from_str(&pool_lp.to_string()),
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()),
@ -2216,13 +2205,113 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
info!("Waiting for next block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
let amm_pool_acc = seq_client
.get_account(amm_pool.to_string())
let user_holding_a_acc = seq_client
.get_account(recipient_account_id_1.to_string())
.await
.unwrap()
.account;
info!("AMM pool is {amm_pool_acc:#?}");
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!(
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
]
);
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
]
);
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
]
);
info!("=================== AMM DEFINITION 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_1.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!(
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
]
);
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
]
);
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
]
);
info!("Success!");
}

View File

@ -124,7 +124,6 @@ pub struct ProgramOutput {
pub fn read_nssa_inputs<T: DeserializeOwned>() -> (ProgramInput<T>, InstructionData) {
let pre_states: Vec<AccountWithMetadata> = env::read();
let instruction_words: InstructionData = env::read();
println!("INSTRUCTION WORKDS IS {instruction_words:?}");
let instruction = T::deserialize(&mut Deserializer::new(instruction_words.as_ref())).unwrap();
(
ProgramInput {

View File

@ -23,6 +23,7 @@ impl Message {
instruction: T,
) -> Result<Self, NssaError> {
let instruction_data = Program::serialize_instruction(instruction)?;
Ok(Self {
program_id,
account_ids,

View File

@ -99,6 +99,7 @@ impl V02State {
this.insert_program(Program::authenticated_transfer_program());
this.insert_program(Program::token());
this.insert_program(Program::amm());
this
}

View File

@ -24,6 +24,7 @@ sha2.workspace = true
futures.workspace = true
async-stream = "0.3.6"
indicatif = { version = "0.18.3", features = ["improved_unicode"] }
risc0-zkvm = { version = "3.0.3", features = ['std'] }
[dependencies.key_protocol]
path = "../key_protocol"

View File

@ -15,18 +15,6 @@ pub enum AmmProgramAgnosticSubcommand {
///
/// user_holding_a and user_holding_b must be owned.
New {
/// 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,
@ -45,15 +33,6 @@ pub enum AmmProgramAgnosticSubcommand {
///
/// The account associated with swapping token must be owned
Swap {
/// amm_pool - valid 32 byte base58 string with privacy prefix
#[arg(long)]
amm_pool: String,
/// vault_holding_1 - valid 32 byte base58 string with privacy prefix
#[arg(long)]
vault_holding_1: String,
/// vault_holding_2 - valid 32 byte base58 string with privacy prefix
#[arg(long)]
vault_holding_2: String,
/// user_holding_a - valid 32 byte base58 string with privacy prefix
#[arg(long)]
user_holding_a: String,
@ -141,28 +120,12 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
) -> Result<SubcommandReturnValue> {
match self {
AmmProgramAgnosticSubcommand::New {
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
balance_a,
balance_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)?,
)?;
@ -173,25 +136,13 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
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 is_public_tx = [&user_holding_a, &user_holding_b, &user_holding_lp]
.into_iter()
.all(|acc| acc.is_public());
if is_public_tx {
AMM(wallet_core)
.send_new_amm_definition(
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
@ -203,10 +154,6 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
} else {
AMM(wallet_core)
.send_new_amm_definition_privacy_preserving(
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
@ -219,24 +166,12 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
}
}
AmmProgramAgnosticSubcommand::Swap {
amm_pool,
vault_holding_1,
vault_holding_2,
user_holding_a,
user_holding_b,
amount_in,
min_amount_out,
token_definition,
} => {
let amm_pool = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&amm_pool)?,
)?;
let vault_holding_1 = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&vault_holding_1)?,
)?;
let vault_holding_2 = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&vault_holding_2)?,
)?;
let user_holding_a = PrivacyPreservingAccount::parse_with_privacy(
parse_addr_with_privacy_prefix(&user_holding_a)?,
)?;
@ -244,22 +179,13 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
parse_addr_with_privacy_prefix(&user_holding_b)?,
)?;
let is_public_tx = [
&amm_pool,
&vault_holding_1,
&vault_holding_2,
&user_holding_a,
&user_holding_b,
]
.into_iter()
.all(|acc| acc.is_public());
let is_public_tx = [&user_holding_a, &user_holding_b]
.into_iter()
.all(|acc| acc.is_public());
if is_public_tx {
AMM(wallet_core)
.send_swap(
amm_pool,
vault_holding_1,
vault_holding_2,
user_holding_a,
user_holding_b,
amount_in,
@ -271,9 +197,6 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
} else {
AMM(wallet_core)
.send_swap_privacy_preserving(
amm_pool,
vault_holding_1,
vault_holding_2,
user_holding_a,
user_holding_b,
amount_in,

View File

@ -1,9 +1,103 @@
use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse};
use nssa::{AccountId, program::Program};
use nssa_core::{SharedSecretKey, program::InstructionData};
use nssa::{AccountId, ProgramId, program::Program};
use nssa_core::{SharedSecretKey, program::PdaSeed};
use serde::{Serialize, ser::SerializeSeq};
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 {
@ -16,10 +110,19 @@ impl OrphanHack65BytesInput {
Self(res)
}
}
fn words(&self) -> Vec<u32> {
self.0.to_vec()
}
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]);
@ -37,7 +140,20 @@ impl OrphanHack49BytesInput {
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()
}
}
pub struct AMM<'w>(pub &'w WalletCore);
@ -46,10 +162,6 @@ impl AMM<'_> {
#[allow(clippy::too_many_arguments)]
pub async fn send_new_amm_definition(
&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,
@ -58,24 +170,36 @@ impl AMM<'_> {
) -> Result<SendTxResponse, ExecutionFailureKind> {
let (instruction, program) = amm_program_preparation_definition(balance_a, balance_b);
match (
amm_pool,
vault_holding_a,
vault_holding_b,
pool_lp,
user_holding_a,
user_holding_b,
user_holding_lp,
) {
match (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 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,
@ -136,25 +260,18 @@ impl AMM<'_> {
#[allow(clippy::too_many_arguments)]
pub async fn send_new_amm_definition_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_a: u128,
_balance_b: u128,
) -> Result<(SendTxResponse, [Option<SharedSecretKey>; 7]), ExecutionFailureKind> {
) -> Result<(SendTxResponse, [Option<SharedSecretKey>; 3]), ExecutionFailureKind> {
todo!()
}
#[allow(clippy::too_many_arguments)]
pub async fn send_swap(
&self,
amm_pool: PrivacyPreservingAccount,
vault_holding_1: PrivacyPreservingAccount,
vault_holding_2: PrivacyPreservingAccount,
user_holding_a: PrivacyPreservingAccount,
user_holding_b: PrivacyPreservingAccount,
amount_in: u128,
@ -164,24 +281,38 @@ impl AMM<'_> {
let (instruction, program) =
amm_program_preparation_swap(amount_in, min_amount_out, token_definition_id);
match (
amm_pool,
vault_holding_1,
vault_holding_2,
user_holding_a,
user_holding_b,
) {
match (user_holding_a, user_holding_b) {
(
PrivacyPreservingAccount::Public(amm_pool),
PrivacyPreservingAccount::Public(vault_holding_1),
PrivacyPreservingAccount::Public(vault_holding_2),
PrivacyPreservingAccount::Public(user_holding_a),
PrivacyPreservingAccount::Public(user_holding_b),
) => {
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 account_ids = vec![
amm_pool,
vault_holding_1,
vault_holding_2,
vault_holding_a,
vault_holding_b,
user_holding_a,
user_holding_b,
];
@ -226,12 +357,13 @@ impl AMM<'_> {
return Err(ExecutionFailureKind::KeyNotFoundError);
};
let message = nssa::public_transaction::Message::new_preserialized(
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]);
@ -247,54 +379,52 @@ impl AMM<'_> {
#[allow(clippy::too_many_arguments)]
pub async fn send_swap_privacy_preserving(
&self,
amm_pool: PrivacyPreservingAccount,
vault_holding_1: PrivacyPreservingAccount,
vault_holding_2: PrivacyPreservingAccount,
user_holding_a: PrivacyPreservingAccount,
user_holding_b: PrivacyPreservingAccount,
amount_in: u128,
min_amount_out: u128,
token_definition_id: AccountId,
_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> {
let (instruction_data, program) =
amm_program_preparation_swap(amount_in, min_amount_out, token_definition_id);
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,
&program,
)
.await
.map(|(resp, secrets)| {
let mut secrets = secrets.into_iter();
let mut secrets_res = [None; 5];
// 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");
// 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);
}
}
// secrets_res[acc_id.0] = Some(secret);
// }
// }
(resp, secrets_res)
})
// (resp, secrets_res)
// })
}
#[allow(clippy::too_many_arguments)]
@ -417,7 +547,7 @@ impl AMM<'_> {
user_holding_b.clone(),
user_holding_lp.clone(),
],
&instruction_data,
&instruction_data.words(),
&program,
)
.await
@ -568,7 +698,7 @@ impl AMM<'_> {
user_holding_b.clone(),
user_holding_lp.clone(),
],
&instruction_data,
&instruction_data.words(),
&program,
)
.await
@ -604,11 +734,11 @@ impl AMM<'_> {
fn amm_program_preparation_definition(
balance_a: u128,
balance_b: u128,
) -> (InstructionData, Program) {
) -> (OrphanHack65BytesInput, Program) {
// An instruction data of 65-bytes, indicating the initial amm reserves' balances and
// token_program_id with the following layout:
// [0x00 || array of balances (little-endian 16 bytes) || TOKEN_PROGRAM_ID)]
let amm_program_id = Program::token().id();
// [0x00 || array of balances (little-endian 16 bytes) || AMM_PROGRAM_ID)]
let amm_program_id = Program::amm().id();
let mut instruction = [0; 65];
instruction[1..17].copy_from_slice(&balance_a.to_le_bytes());
@ -624,7 +754,7 @@ fn amm_program_preparation_definition(
instruction[57..61].copy_from_slice(&amm_program_id[6].to_le_bytes());
instruction[61..].copy_from_slice(&amm_program_id[7].to_le_bytes());
let instruction_data = OrphanHack65BytesInput::expand(instruction).words();
let instruction_data = OrphanHack65BytesInput::expand(instruction);
let program = Program::amm();
(instruction_data, program)
@ -634,19 +764,19 @@ fn amm_program_preparation_swap(
amount_in: u128,
min_amount_out: u128,
token_definition_id: AccountId,
) -> (InstructionData, Program) {
) -> (OrphanHack65BytesInput, Program) {
// An instruction data byte string of length 65, indicating which token type to swap, quantity
// of tokens put into the swap (of type TOKEN_DEFINITION_ID) and min_amount_out.
// [0x01 || amount (little-endian 16 bytes) || TOKEN_DEFINITION_ID].
let mut instruction = [0; 65];
instruction[0] = 0x01;
instruction[1..17].copy_from_slice(&amount_in.to_le_bytes());
instruction[17..33].copy_from_slice(&min_amount_out.to_le_bytes());
// This can be done less verbose, but it is better to use same way, as in amm program
instruction[33..].copy_from_slice(&token_definition_id.to_bytes());
let instruction_data =
OrphanHack65BytesInput::expand(instruction).words();
let instruction_data = OrphanHack65BytesInput::expand(instruction);
let program = Program::amm();
(instruction_data, program)
@ -656,7 +786,7 @@ fn amm_program_preparation_add_liq(
min_amount_lp: u128,
max_amount_a: u128,
max_amount_b: u128,
) -> (InstructionData, Program) {
) -> (OrphanHack49BytesInput, Program) {
// An instruction data byte string of length 49, amounts for minimum amount of liquidity from
// add (min_amount_lp), max amount added for each token (max_amount_a and max_amount_b);
// indicate [0x02 || array of of balances (little-endian 16 bytes)].
@ -667,7 +797,7 @@ fn amm_program_preparation_add_liq(
instruction[17..33].copy_from_slice(&max_amount_a.to_le_bytes());
instruction[33..49].copy_from_slice(&max_amount_b.to_le_bytes());
let instruction_data = OrphanHack49BytesInput::expand(instruction).words();
let instruction_data = OrphanHack49BytesInput::expand(instruction);
let program = Program::amm();
(instruction_data, program)
@ -677,7 +807,7 @@ fn amm_program_preparation_remove_liq(
balance_lp: u128,
max_amount_a: u128,
max_amount_b: u128,
) -> (InstructionData, Program) {
) -> (OrphanHack49BytesInput, Program) {
// An instruction data byte string of length 49, amounts for minimum amount of liquidity to
// redeem (balance_lp), minimum balance of each token to remove (min_amount_a and
// min_amount_b); indicate [0x03 || array of balances (little-endian 16 bytes)].
@ -688,7 +818,7 @@ fn amm_program_preparation_remove_liq(
instruction[17..33].copy_from_slice(&max_amount_a.to_le_bytes());
instruction[33..49].copy_from_slice(&max_amount_b.to_le_bytes());
let instruction_data = OrphanHack49BytesInput::expand(instruction).words();
let instruction_data = OrphanHack49BytesInput::expand(instruction);
let program = Program::amm();
(instruction_data, program)
@ -698,20 +828,19 @@ fn amm_program_preparation_remove_liq(
mod tests {
use crate::program_facades::amm::OrphanHack65BytesInput;
#[test]
fn test_correct_ser() {
let mut arr = [0u8; 65];
for i in 0..64 {
arr[i] = i as u8;
for (i, item) in arr.iter_mut().enumerate().take(64) {
*item = i as u8;
}
let hack = OrphanHack65BytesInput::expand(arr);
let instruction_data = hack.words();
let instruction_data = serde_json::to_string(&hack).unwrap();
println!("{instruction_data:?}");
//assert_eq!(serialization_res_1, serialization_res_2);
// assert_eq!(serialization_res_1, serialization_res_2);
}
}