From 92b5dffec273f974fb7c2266c55c0c7e3cd3945a Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Wed, 17 Dec 2025 14:21:36 +0200 Subject: [PATCH] fix: public swaps --- integration_tests/src/test_suite_map.rs | 211 ++++++++++----- nssa/core/src/program.rs | 1 - nssa/src/public_transaction/message.rs | 1 + nssa/src/state.rs | 1 + wallet/Cargo.toml | 1 + wallet/src/cli/programs/amm.rs | 89 +------ wallet/src/program_facades/amm.rs | 341 ++++++++++++++++-------- 7 files changed, 394 insertions(+), 251 deletions(-) diff --git a/integration_tests/src/test_suite_map.rs b/integration_tests/src/test_suite_map.rs index 6c78d6e..e1102dc 100644 --- a/integration_tests/src/test_suite_map.rs +++ b/integration_tests/src/test_suite_map.rs @@ -2042,7 +2042,7 @@ pub fn prepare_function_map() -> HashMap { // 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 { }; // 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 { 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 { // 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 { 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 { 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 { // 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 { // 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 { 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!"); } diff --git a/nssa/core/src/program.rs b/nssa/core/src/program.rs index 4ad0569..03fe163 100644 --- a/nssa/core/src/program.rs +++ b/nssa/core/src/program.rs @@ -124,7 +124,6 @@ pub struct ProgramOutput { pub fn read_nssa_inputs() -> (ProgramInput, InstructionData) { let pre_states: Vec = 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 { diff --git a/nssa/src/public_transaction/message.rs b/nssa/src/public_transaction/message.rs index a585c2c..468b04f 100644 --- a/nssa/src/public_transaction/message.rs +++ b/nssa/src/public_transaction/message.rs @@ -23,6 +23,7 @@ impl Message { instruction: T, ) -> Result { let instruction_data = Program::serialize_instruction(instruction)?; + Ok(Self { program_id, account_ids, diff --git a/nssa/src/state.rs b/nssa/src/state.rs index bd2ddc0..326bf14 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -99,6 +99,7 @@ impl V02State { this.insert_program(Program::authenticated_transfer_program()); this.insert_program(Program::token()); + this.insert_program(Program::amm()); this } diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 3ea6cd1..678db92 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -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" diff --git a/wallet/src/cli/programs/amm.rs b/wallet/src/cli/programs/amm.rs index 3878c94..69e3a01 100644 --- a/wallet/src/cli/programs/amm.rs +++ b/wallet/src/cli/programs/amm.rs @@ -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 { 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, diff --git a/wallet/src/program_facades/amm.rs b/wallet/src/program_facades/amm.rs index 682c8d3..a0691f6 100644 --- a/wallet/src/program_facades/amm.rs +++ b/wallet/src/program_facades/amm.rs @@ -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 { - self.0.to_vec() - } +impl Serialize for OrphanHack65BytesInput { + fn serialize(&self, serializer: S) -> Result + 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 { self.0.to_vec() - } + } +} + +impl Serialize for OrphanHack49BytesInput { + fn serialize(&self, serializer: S) -> Result + 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 { 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; 7]), ExecutionFailureKind> { + ) -> Result<(SendTxResponse, [Option; 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; 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); } }