From 4f1523744661a16784acf4c6b0bd549c5f1d5d19 Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Mon, 22 Dec 2025 04:42:32 +0200 Subject: [PATCH] fix: suggestions fix --- nssa/src/public_transaction/message.rs | 2 +- wallet/src/cli/account.rs | 59 +----- wallet/src/cli/programs/amm.rs | 30 +-- wallet/src/lib.rs | 54 ++++++ wallet/src/program_facades/amm.rs | 242 +++++++++++++++++-------- wallet/src/program_facades/mod.rs | 95 ---------- 6 files changed, 240 insertions(+), 242 deletions(-) diff --git a/nssa/src/public_transaction/message.rs b/nssa/src/public_transaction/message.rs index 468b04f..d8bd2da 100644 --- a/nssa/src/public_transaction/message.rs +++ b/nssa/src/public_transaction/message.rs @@ -36,7 +36,7 @@ impl Message { program_id: ProgramId, account_ids: Vec, nonces: Vec, - instruction_data: Vec, + instruction_data: InstructionData, ) -> Self { Self { program_id, diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index 67cf8f8..7e8a005 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -3,70 +3,15 @@ use base58::ToBase58; use clap::Subcommand; use itertools::Itertools as _; use key_protocol::key_management::key_tree::chain_index::ChainIndex; -use nssa::{Account, AccountId, program::Program}; +use nssa::{Account, program::Program}; use serde::Serialize; use crate::{ - WalletCore, + TokenDefinition, TokenHolding, WalletCore, cli::{SubcommandReturnValue, WalletSubcommand}, helperfunctions::{AccountPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix}, }; -const TOKEN_DEFINITION_TYPE: u8 = 0; -const TOKEN_DEFINITION_DATA_SIZE: usize = 23; - -const TOKEN_HOLDING_TYPE: u8 = 1; -const TOKEN_HOLDING_DATA_SIZE: usize = 49; - -struct TokenDefinition { - #[allow(unused)] - account_type: u8, - name: [u8; 6], - total_supply: u128, -} - -pub struct TokenHolding { - #[allow(unused)] - account_type: u8, - pub definition_id: AccountId, - balance: u128, -} - -impl TokenDefinition { - fn parse(data: &[u8]) -> Option { - if data.len() != TOKEN_DEFINITION_DATA_SIZE || data[0] != TOKEN_DEFINITION_TYPE { - None - } else { - let account_type = data[0]; - let name = data[1..7].try_into().unwrap(); - let total_supply = u128::from_le_bytes(data[7..].try_into().unwrap()); - - Some(Self { - account_type, - name, - total_supply, - }) - } - } -} - -impl TokenHolding { - pub fn parse(data: &[u8]) -> Option { - if data.len() != TOKEN_HOLDING_DATA_SIZE || data[0] != TOKEN_HOLDING_TYPE { - None - } else { - let account_type = data[0]; - let definition_id = AccountId::new(data[1..33].try_into().unwrap()); - let balance = u128::from_le_bytes(data[33..].try_into().unwrap()); - Some(Self { - definition_id, - balance, - account_type, - }) - } - } -} - /// Represents generic chain CLI subcommand #[derive(Subcommand, Debug, Clone)] pub enum AccountSubcommand { diff --git a/wallet/src/cli/programs/amm.rs b/wallet/src/cli/programs/amm.rs index 84a31d2..ce919b7 100644 --- a/wallet/src/cli/programs/amm.rs +++ b/wallet/src/cli/programs/amm.rs @@ -6,7 +6,7 @@ use crate::{ WalletCore, cli::{SubcommandReturnValue, WalletSubcommand}, helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix}, - program_facades::amm::AMM, + program_facades::amm::Amm, }; /// Represents generic CLI subcommand for a wallet working with amm program @@ -32,7 +32,7 @@ pub enum AmmProgramAgnosticSubcommand { #[arg(long)] balance_b: u128, }, - /// Swap with variable privacy + /// Swap /// /// The account associated with swapping token must be owned /// @@ -52,7 +52,7 @@ pub enum AmmProgramAgnosticSubcommand { #[arg(long)] token_definition: String, }, - /// Add liquidity with variable privacy + /// Add liquidity /// /// user_holding_a and user_holding_b must be owned. /// @@ -74,7 +74,7 @@ pub enum AmmProgramAgnosticSubcommand { #[arg(long)] max_amount_b: u128, }, - /// Remove liquidity with variable privacy + /// Remove liquidity /// /// user_holding_lp must be owned. /// @@ -132,8 +132,8 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand { AccountPrivacyKind::Public, AccountPrivacyKind::Public, ) => { - AMM(wallet_core) - .send_new_amm_definition( + Amm(wallet_core) + .send_new_definition( user_holding_a, user_holding_b, user_holding_lp, @@ -146,7 +146,7 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand { } _ => { // ToDo: Implement after private multi-chain calls is available - anyhow::bail!("Only public execution allowed for AMM calls"); + anyhow::bail!("Only public execution allowed for Amm calls"); } } } @@ -167,7 +167,7 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand { match (user_holding_a_privacy, user_holding_b_privacy) { (AccountPrivacyKind::Public, AccountPrivacyKind::Public) => { - AMM(wallet_core) + Amm(wallet_core) .send_swap( user_holding_a, user_holding_b, @@ -181,7 +181,7 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand { } _ => { // ToDo: Implement after private multi-chain calls is available - anyhow::bail!("Only public execution allowed for AMM calls"); + anyhow::bail!("Only public execution allowed for Amm calls"); } } } @@ -214,8 +214,8 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand { AccountPrivacyKind::Public, AccountPrivacyKind::Public, ) => { - AMM(wallet_core) - .send_add_liq( + Amm(wallet_core) + .send_add_liquidity( user_holding_a, user_holding_b, user_holding_lp, @@ -229,7 +229,7 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand { } _ => { // ToDo: Implement after private multi-chain calls is available - anyhow::bail!("Only public execution allowed for AMM calls"); + anyhow::bail!("Only public execution allowed for Amm calls"); } } } @@ -262,8 +262,8 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand { AccountPrivacyKind::Public, AccountPrivacyKind::Public, ) => { - AMM(wallet_core) - .send_remove_liq( + Amm(wallet_core) + .send_remove_liquidity( user_holding_a, user_holding_b, user_holding_lp, @@ -277,7 +277,7 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand { } _ => { // ToDo: Implement after private multi-chain calls is available - anyhow::bail!("Only public execution allowed for AMM calls"); + anyhow::bail!("Only public execution allowed for Amm calls"); } } } diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 3dfc10b..639377c 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -43,6 +43,60 @@ pub enum AccDecodeData { Decode(nssa_core::SharedSecretKey, AccountId), } +const TOKEN_DEFINITION_TYPE: u8 = 0; +const TOKEN_DEFINITION_DATA_SIZE: usize = 23; + +const TOKEN_HOLDING_TYPE: u8 = 1; +const TOKEN_HOLDING_DATA_SIZE: usize = 49; + +struct TokenDefinition { + #[allow(unused)] + account_type: u8, + name: [u8; 6], + total_supply: u128, +} + +pub struct TokenHolding { + pub account_type: u8, + pub definition_id: AccountId, + pub balance: u128, +} + +impl TokenDefinition { + fn parse(data: &[u8]) -> Option { + if data.len() != TOKEN_DEFINITION_DATA_SIZE || data[0] != TOKEN_DEFINITION_TYPE { + None + } else { + let account_type = data[0]; + let name = data[1..7].try_into().unwrap(); + let total_supply = u128::from_le_bytes(data[7..].try_into().unwrap()); + + Some(Self { + account_type, + name, + total_supply, + }) + } + } +} + +impl TokenHolding { + pub fn parse(data: &[u8]) -> Option { + if data.len() != TOKEN_HOLDING_DATA_SIZE || data[0] != TOKEN_HOLDING_TYPE { + None + } else { + let account_type = data[0]; + let definition_id = AccountId::new(data[1..33].try_into().unwrap()); + let balance = u128::from_le_bytes(data[33..].try_into().unwrap()); + Some(Self { + definition_id, + balance, + account_type, + }) + } + } +} + pub struct WalletCore { pub storage: WalletChainStore, pub poller: TxPoller, diff --git a/wallet/src/program_facades/amm.rs b/wallet/src/program_facades/amm.rs index 9310c15..72ee2fe 100644 --- a/wallet/src/program_facades/amm.rs +++ b/wallet/src/program_facades/amm.rs @@ -1,19 +1,109 @@ use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse}; -use nssa::{AccountId, program::Program}; +use nssa::{AccountId, ProgramId, program::Program}; +use nssa_core::program::PdaSeed; use crate::{ - WalletCore, - cli::account::TokenHolding, - program_facades::{ - OrphanHack49BytesInput, OrphanHack65BytesInput, compute_liquidity_token_pda, - compute_pool_pda, compute_vault_pda, - }, + TokenHolding, WalletCore, + program_facades::{OrphanHack49BytesInput, OrphanHack65BytesInput}, }; -pub struct AMM<'w>(pub &'w WalletCore); +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), + )) +} -impl AMM<'_> { - pub async fn send_new_amm_definition( +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"), + ) +} + +pub struct Amm<'w>(pub &'w WalletCore); + +impl Amm<'_> { + pub async fn send_new_definition( &self, user_holding_a: AccountId, user_holding_b: AccountId, @@ -25,12 +115,16 @@ impl AMM<'_> { 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 user_a_acc = self + .0 + .get_account_public(user_holding_a) + .await + .map_err(|_| ExecutionFailureKind::SequencerError)?; + let user_b_acc = self + .0 + .get_account_public(user_holding_b) + .await + .map_err(|_| ExecutionFailureKind::SequencerError)?; let definition_token_a_id = TokenHolding::parse(&user_a_acc.data) .ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))? @@ -55,31 +149,25 @@ impl AMM<'_> { user_holding_lp, ]; - let Ok(nonces) = self + let nonces = self .0 .get_accounts_nonces(vec![user_holding_a, user_holding_b]) .await - else { - return Err(ExecutionFailureKind::SequencerError); - }; + .map_err(|_| ExecutionFailureKind::SequencerError)?; - let Some(signing_key_a) = self + let signing_key_a = self .0 .storage .user_data .get_pub_account_signing_key(&user_holding_a) - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - let Some(signing_key_b) = self + let signing_key_b = self .0 .storage .user_data .get_pub_account_signing_key(&user_holding_b) - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + .ok_or(ExecutionFailureKind::KeyNotFoundError)?; let message = nssa::public_transaction::Message::try_new( program.id(), @@ -112,12 +200,16 @@ impl AMM<'_> { 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 user_a_acc = self + .0 + .get_account_public(user_holding_a) + .await + .map_err(|_| ExecutionFailureKind::SequencerError)?; + let user_b_acc = self + .0 + .get_account_public(user_holding_b) + .await + .map_err(|_| ExecutionFailureKind::SequencerError)?; let definition_token_a_id = TokenHolding::parse(&user_a_acc.data) .ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))? @@ -166,18 +258,18 @@ impl AMM<'_> { 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 nonces = self + .0 + .get_accounts_nonces(vec![account_id_auth]) + .await + .map_err(|_| ExecutionFailureKind::SequencerError)?; - let Some(signing_key) = self + let signing_key = self .0 .storage .user_data .get_pub_account_signing_key(&account_id_auth) - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + .ok_or(ExecutionFailureKind::KeyNotFoundError)?; let message = nssa::public_transaction::Message::try_new( program.id(), @@ -195,7 +287,7 @@ impl AMM<'_> { Ok(self.0.sequencer_client.send_tx_public(tx).await?) } - pub async fn send_add_liq( + pub async fn send_add_liquidity( &self, user_holding_a: AccountId, user_holding_b: AccountId, @@ -209,12 +301,16 @@ impl AMM<'_> { 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 user_a_acc = self + .0 + .get_account_public(user_holding_a) + .await + .map_err(|_| ExecutionFailureKind::SequencerError)?; + let user_b_acc = self + .0 + .get_account_public(user_holding_b) + .await + .map_err(|_| ExecutionFailureKind::SequencerError)?; let definition_token_a_id = TokenHolding::parse(&user_a_acc.data) .ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))? @@ -239,31 +335,25 @@ impl AMM<'_> { user_holding_lp, ]; - let Ok(nonces) = self + let nonces = self .0 .get_accounts_nonces(vec![user_holding_a, user_holding_b]) .await - else { - return Err(ExecutionFailureKind::SequencerError); - }; + .map_err(|_| ExecutionFailureKind::SequencerError)?; - let Some(signing_key_a) = self + let signing_key_a = self .0 .storage .user_data .get_pub_account_signing_key(&user_holding_a) - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - let Some(signing_key_b) = self + let signing_key_b = self .0 .storage .user_data .get_pub_account_signing_key(&user_holding_b) - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + .ok_or(ExecutionFailureKind::KeyNotFoundError)?; let message = nssa::public_transaction::Message::try_new( program.id(), @@ -283,7 +373,7 @@ impl AMM<'_> { Ok(self.0.sequencer_client.send_tx_public(tx).await?) } - pub async fn send_remove_liq( + pub async fn send_remove_liquidity( &self, user_holding_a: AccountId, user_holding_b: AccountId, @@ -297,12 +387,16 @@ impl AMM<'_> { 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 user_a_acc = self + .0 + .get_account_public(user_holding_a) + .await + .map_err(|_| ExecutionFailureKind::SequencerError)?; + let user_b_acc = self + .0 + .get_account_public(user_holding_b) + .await + .map_err(|_| ExecutionFailureKind::SequencerError)?; let definition_token_a_id = TokenHolding::parse(&user_a_acc.data) .ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))? @@ -327,18 +421,18 @@ impl AMM<'_> { user_holding_lp, ]; - let Ok(nonces) = self.0.get_accounts_nonces(vec![user_holding_lp]).await else { - return Err(ExecutionFailureKind::SequencerError); - }; + let nonces = self + .0 + .get_accounts_nonces(vec![user_holding_lp]) + .await + .map_err(|_| ExecutionFailureKind::SequencerError)?; - let Some(signing_key_lp) = self + let signing_key_lp = self .0 .storage .user_data .get_pub_account_signing_key(&user_holding_lp) - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + .ok_or(ExecutionFailureKind::KeyNotFoundError)?; let message = nssa::public_transaction::Message::try_new( program.id(), diff --git a/wallet/src/program_facades/mod.rs b/wallet/src/program_facades/mod.rs index 777a634..2b69664 100644 --- a/wallet/src/program_facades/mod.rs +++ b/wallet/src/program_facades/mod.rs @@ -1,8 +1,6 @@ //! 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; @@ -10,99 +8,6 @@ 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