diff --git a/artifacts/program_methods/amm.bin b/artifacts/program_methods/amm.bin index ab9fd71c..a8ca1f4e 100644 Binary files a/artifacts/program_methods/amm.bin and b/artifacts/program_methods/amm.bin differ diff --git a/artifacts/program_methods/authenticated_transfer.bin b/artifacts/program_methods/authenticated_transfer.bin index 30b86566..0bc3de67 100644 Binary files a/artifacts/program_methods/authenticated_transfer.bin and b/artifacts/program_methods/authenticated_transfer.bin differ diff --git a/artifacts/program_methods/pinata.bin b/artifacts/program_methods/pinata.bin index dabb1089..64aaa346 100644 Binary files a/artifacts/program_methods/pinata.bin and b/artifacts/program_methods/pinata.bin differ diff --git a/artifacts/program_methods/pinata_token.bin b/artifacts/program_methods/pinata_token.bin index 80258afd..a47d90f4 100644 Binary files a/artifacts/program_methods/pinata_token.bin and b/artifacts/program_methods/pinata_token.bin differ diff --git a/artifacts/program_methods/privacy_preserving_circuit.bin b/artifacts/program_methods/privacy_preserving_circuit.bin index 3b058fe6..8e151aa7 100644 Binary files a/artifacts/program_methods/privacy_preserving_circuit.bin and b/artifacts/program_methods/privacy_preserving_circuit.bin differ diff --git a/artifacts/program_methods/token.bin b/artifacts/program_methods/token.bin index 2ce3da03..9a1269c5 100644 Binary files a/artifacts/program_methods/token.bin and b/artifacts/program_methods/token.bin differ diff --git a/artifacts/test_program_methods/burner.bin b/artifacts/test_program_methods/burner.bin index 044ba976..b055fbdb 100644 Binary files a/artifacts/test_program_methods/burner.bin and b/artifacts/test_program_methods/burner.bin differ diff --git a/artifacts/test_program_methods/chain_caller.bin b/artifacts/test_program_methods/chain_caller.bin index dea5e67c..c650f1f9 100644 Binary files a/artifacts/test_program_methods/chain_caller.bin and b/artifacts/test_program_methods/chain_caller.bin differ diff --git a/artifacts/test_program_methods/changer_claimer.bin b/artifacts/test_program_methods/changer_claimer.bin index 474988d0..2dea3a0d 100644 Binary files a/artifacts/test_program_methods/changer_claimer.bin and b/artifacts/test_program_methods/changer_claimer.bin differ diff --git a/artifacts/test_program_methods/claimer.bin b/artifacts/test_program_methods/claimer.bin index 3cf43cb2..fb881bbc 100644 Binary files a/artifacts/test_program_methods/claimer.bin and b/artifacts/test_program_methods/claimer.bin differ diff --git a/artifacts/test_program_methods/data_changer.bin b/artifacts/test_program_methods/data_changer.bin index 484cf65c..5a7a8600 100644 Binary files a/artifacts/test_program_methods/data_changer.bin and b/artifacts/test_program_methods/data_changer.bin differ diff --git a/artifacts/test_program_methods/extra_output.bin b/artifacts/test_program_methods/extra_output.bin index f576f5d6..fc8dc194 100644 Binary files a/artifacts/test_program_methods/extra_output.bin and b/artifacts/test_program_methods/extra_output.bin differ diff --git a/artifacts/test_program_methods/malicious_authorization_changer.bin b/artifacts/test_program_methods/malicious_authorization_changer.bin index bd02c0c4..99dcd50f 100644 Binary files a/artifacts/test_program_methods/malicious_authorization_changer.bin and b/artifacts/test_program_methods/malicious_authorization_changer.bin differ diff --git a/artifacts/test_program_methods/minter.bin b/artifacts/test_program_methods/minter.bin index 585127ba..7ea603a5 100644 Binary files a/artifacts/test_program_methods/minter.bin and b/artifacts/test_program_methods/minter.bin differ diff --git a/artifacts/test_program_methods/missing_output.bin b/artifacts/test_program_methods/missing_output.bin index b40e8dce..3b2379c7 100644 Binary files a/artifacts/test_program_methods/missing_output.bin and b/artifacts/test_program_methods/missing_output.bin differ diff --git a/artifacts/test_program_methods/modified_transfer.bin b/artifacts/test_program_methods/modified_transfer.bin index cc63e67d..48900c0c 100644 Binary files a/artifacts/test_program_methods/modified_transfer.bin and b/artifacts/test_program_methods/modified_transfer.bin differ diff --git a/artifacts/test_program_methods/nonce_changer.bin b/artifacts/test_program_methods/nonce_changer.bin index c5ba2525..b5ef1b9a 100644 Binary files a/artifacts/test_program_methods/nonce_changer.bin and b/artifacts/test_program_methods/nonce_changer.bin differ diff --git a/artifacts/test_program_methods/noop.bin b/artifacts/test_program_methods/noop.bin index f4d8a6ce..c3b1d1d6 100644 Binary files a/artifacts/test_program_methods/noop.bin and b/artifacts/test_program_methods/noop.bin differ diff --git a/artifacts/test_program_methods/program_owner_changer.bin b/artifacts/test_program_methods/program_owner_changer.bin index 5266a5f8..b697cc70 100644 Binary files a/artifacts/test_program_methods/program_owner_changer.bin and b/artifacts/test_program_methods/program_owner_changer.bin differ diff --git a/artifacts/test_program_methods/simple_balance_transfer.bin b/artifacts/test_program_methods/simple_balance_transfer.bin index 6ad8889b..b54383e2 100644 Binary files a/artifacts/test_program_methods/simple_balance_transfer.bin and b/artifacts/test_program_methods/simple_balance_transfer.bin differ diff --git a/indexer/service/protocol/src/convert.rs b/indexer/service/protocol/src/convert.rs index 84258ebb..cbafa0b3 100644 --- a/indexer/service/protocol/src/convert.rs +++ b/indexer/service/protocol/src/convert.rs @@ -52,7 +52,7 @@ impl From for Account { program_owner: program_owner.into(), balance, data: data.into(), - nonce: Nonce(nonce.0), + nonce, } } } @@ -72,7 +72,7 @@ impl TryFrom for nssa_core::account::Account { program_owner: program_owner.into(), balance, data: data.try_into()?, - nonce: nssa_core::account::Nonce(nonce.0), + nonce, }) } } @@ -250,7 +250,7 @@ impl From for PublicMessage { Self { program_id: program_id.into(), account_ids: account_ids.into_iter().map(Into::into).collect(), - nonces: nonces.iter().map(|x| Nonce(x.0)).collect(), + nonces, instruction_data, } } @@ -267,10 +267,7 @@ impl From for nssa::public_transaction::Message { Self::new_preserialized( program_id.into(), account_ids.into_iter().map(Into::into).collect(), - nonces - .iter() - .map(|x| nssa_core::account::Nonce(x.0)) - .collect(), + nonces, instruction_data, ) } @@ -288,7 +285,7 @@ impl From for PrivacyPre } = value; Self { public_account_ids: public_account_ids.into_iter().map(Into::into).collect(), - nonces: nonces.iter().map(|x| Nonce(x.0)).collect(), + nonces, public_post_states: public_post_states.into_iter().map(Into::into).collect(), encrypted_private_post_states: encrypted_private_post_states .into_iter() @@ -317,10 +314,7 @@ impl TryFrom for nssa::privacy_preserving_transaction: } = value; Ok(Self { public_account_ids: public_account_ids.into_iter().map(Into::into).collect(), - nonces: nonces - .iter() - .map(|x| nssa_core::account::Nonce(x.0)) - .collect(), + nonces, public_post_states: public_post_states .into_iter() .map(TryInto::try_into) diff --git a/indexer/service/protocol/src/lib.rs b/indexer/service/protocol/src/lib.rs index 3c2e3c43..98ef5650 100644 --- a/indexer/service/protocol/src/lib.rs +++ b/indexer/service/protocol/src/lib.rs @@ -14,8 +14,6 @@ use serde_with::{DeserializeFromStr, SerializeDisplay}; #[cfg(feature = "convert")] mod convert; -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)] -pub struct Nonce(pub u128); mod base64 { use base64::prelude::{BASE64_STANDARD, Engine as _}; use serde::{Deserialize as _, Deserializer, Serialize as _, Serializer}; diff --git a/integration_tests/tests/tps.rs b/integration_tests/tests/tps.rs index 09398af1..c89ee761 100644 --- a/integration_tests/tests/tps.rs +++ b/integration_tests/tests/tps.rs @@ -27,7 +27,7 @@ use nssa::{ }; use nssa_core::{ MembershipProof, NullifierPublicKey, - account::{AccountWithMetadata, Nonce, data::Data}, + account::{AccountWithMetadata, data::Data}, encryption::ViewingPublicKey, }; use tokio::test; @@ -216,7 +216,7 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction { let sender_pre = AccountWithMetadata::new( Account { balance: 100, - nonce: Nonce(0xdeadbeef), + nonce: 0xdead_beef, program_owner: program.id(), data: Data::default(), }, @@ -250,6 +250,7 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction { vec![sender_pre, recipient_pre], Program::serialize_instruction(balance_to_move).unwrap(), vec![1, 2], + vec![0xdead_beef1, 0xdead_beef2], vec![ (sender_npk.clone(), sender_ss), (recipient_npk.clone(), recipient_ss), diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index 2b16d7a0..084b05db 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -68,6 +68,7 @@ pub fn execute_and_prove( pre_states: Vec, instruction_data: InstructionData, visibility_mask: Vec, + private_account_nonces: Vec, private_account_keys: Vec<(NullifierPublicKey, SharedSecretKey)>, private_account_nsks: Vec, private_account_membership_proofs: Vec>, @@ -126,6 +127,7 @@ pub fn execute_and_prove( let circuit_input = PrivacyPreservingCircuitInput { program_outputs, visibility_mask, + private_account_nonces, private_account_keys, private_account_nsks, private_account_membership_proofs, @@ -175,7 +177,7 @@ mod tests { use nssa_core::{ Commitment, DUMMY_COMMITMENT_HASH, EncryptionScheme, Nullifier, - account::{Account, AccountId, AccountWithMetadata, Nonce, data::Data}, + account::{Account, AccountId, AccountWithMetadata, data::Data}, }; use super::*; @@ -213,14 +215,14 @@ mod tests { let expected_sender_post = Account { program_owner: program.id(), balance: 100 - balance_to_move, - nonce: 0u128.into(), + nonce: 0, data: Data::default(), }; let expected_recipient_post = Account { program_owner: program.id(), balance: balance_to_move, - nonce: Nonce::private_account_nonce_init(&recipient_keys.npk()), + nonce: 0xdead_beef, data: Data::default(), }; @@ -233,6 +235,7 @@ mod tests { vec![sender, recipient], Program::serialize_instruction(balance_to_move).unwrap(), vec![0, 2], + vec![0xdead_beef], vec![(recipient_keys.npk(), shared_secret)], vec![], vec![None], @@ -266,11 +269,10 @@ mod tests { let sender_keys = test_private_account_keys_1(); let recipient_keys = test_private_account_keys_2(); - let sender_nonce = Nonce(0xdeadbeef); let sender_pre = AccountWithMetadata::new( Account { balance: 100, - nonce: sender_nonce, + nonce: 0xdead_beef, program_owner: program.id(), data: Data::default(), }, @@ -305,13 +307,13 @@ mod tests { let expected_private_account_1 = Account { program_owner: program.id(), balance: 100 - balance_to_move, - nonce: sender_nonce.private_account_nonce_increment(&sender_keys.nsk), + nonce: 0xdead_beef1, ..Default::default() }; let expected_private_account_2 = Account { program_owner: program.id(), balance: balance_to_move, - nonce: Nonce::private_account_nonce_init(&recipient_keys.npk()), + nonce: 0xdead_beef2, ..Default::default() }; let expected_new_commitments = vec![ diff --git a/nssa/src/state.rs b/nssa/src/state.rs index 464bb18c..c1f72b4c 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -172,7 +172,10 @@ impl V02State { for account_id in tx.signer_account_ids() { let current_account = self.get_account_by_id_mut(account_id); - current_account.nonce.public_account_nonce_increment(); + current_account.nonce = current_account + .nonce + .checked_add(1) + .ok_or(NssaError::MaxAccountNonceReached)?; } Ok(()) @@ -212,7 +215,10 @@ impl V02State { // 5. Increment nonces for public signers for account_id in tx.signer_account_ids() { let current_account = self.get_account_by_id_mut(account_id); - current_account.nonce.public_account_nonce_increment(); + current_account.nonce = current_account + .nonce + .checked_add(1) + .ok_or(NssaError::MaxAccountNonceReached)?; } Ok(()) @@ -297,7 +303,7 @@ impl V02State { balance: 1_500_000, // Difficulty: 3 data: vec![3; 33].try_into().expect("should fit"), - nonce: 0u128.into(), + nonce: 0, }, ); } @@ -317,6 +323,13 @@ impl V02State { } } +#[cfg(any(test, feature = "test-utils"))] +impl V02State { + pub fn force_insert_account(&mut self, account_id: AccountId, account: Account) { + self.public_state.insert(account_id, account); + } +} + #[cfg(test)] pub mod tests { #![expect( @@ -327,14 +340,12 @@ pub mod tests { use std::collections::HashMap; - use amm_core::PoolDefinition; use nssa_core::{ Commitment, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey, account::{Account, AccountId, AccountWithMetadata, Nonce, data::Data}, encryption::{EphemeralPublicKey, Scalar, ViewingPublicKey}, program::{PdaSeed, ProgramId}, }; - use token_core::{TokenDefinition, TokenHolding}; use crate::{ PublicKey, PublicTransaction, V02State, @@ -353,10 +364,6 @@ pub mod tests { }; impl V02State { - pub fn force_insert_account(&mut self, account_id: AccountId, account: Account) { - self.public_state.insert(account_id, account); - } - /// Include test programs in the builtin programs map. #[must_use] pub fn with_test_programs(mut self) -> Self { @@ -382,7 +389,7 @@ pub mod tests { ..Account::default() }; let account_with_default_values_except_nonce = Account { - nonce: 37u128.into(), + nonce: 37, ..Account::default() }; let account_with_default_values_except_data = Account { @@ -448,828 +455,6 @@ pub mod tests { } } - struct PrivateKeysForTests; - - impl PrivateKeysForTests { - fn user_token_a_key() -> PrivateKey { - PrivateKey::try_new([31; 32]).expect("Keys constructor expects valid private key") - } - - fn user_token_b_key() -> PrivateKey { - PrivateKey::try_new([32; 32]).expect("Keys constructor expects valid private key") - } - - fn user_token_lp_key() -> PrivateKey { - PrivateKey::try_new([33; 32]).expect("Keys constructor expects valid private key") - } - } - - struct BalanceForTests; - - impl BalanceForTests { - fn user_token_a_holding_init() -> u128 { - 10_000 - } - - fn user_token_b_holding_init() -> u128 { - 10_000 - } - - fn user_token_lp_holding_init() -> u128 { - 2_000 - } - - fn vault_a_balance_init() -> u128 { - 5_000 - } - - fn vault_b_balance_init() -> u128 { - 2_500 - } - - fn pool_lp_supply_init() -> u128 { - 5_000 - } - - fn token_a_supply() -> u128 { - 100_000 - } - - fn token_b_supply() -> u128 { - 100_000 - } - - fn token_lp_supply() -> u128 { - 5_000 - } - - fn remove_lp() -> u128 { - 1_000 - } - - fn remove_min_amount_a() -> u128 { - 500 - } - - fn remove_min_amount_b() -> u128 { - 500 - } - - fn add_min_amount_lp() -> u128 { - 1_000 - } - - fn add_max_amount_a() -> u128 { - 2_000 - } - - fn add_max_amount_b() -> u128 { - 1_000 - } - - fn swap_amount_in() -> u128 { - 1_000 - } - - fn swap_min_amount_out() -> u128 { - 200 - } - - fn vault_a_balance_swap_1() -> u128 { - 3_572 - } - - fn vault_b_balance_swap_1() -> u128 { - 3_500 - } - - fn user_token_a_holding_swap_1() -> u128 { - 11_428 - } - - fn user_token_b_holding_swap_1() -> u128 { - 9_000 - } - - fn vault_a_balance_swap_2() -> u128 { - 6_000 - } - - fn vault_b_balance_swap_2() -> u128 { - 2_084 - } - - fn user_token_a_holding_swap_2() -> u128 { - 9_000 - } - - fn user_token_b_holding_swap_2() -> u128 { - 10_416 - } - - fn vault_a_balance_add() -> u128 { - 7_000 - } - - fn vault_b_balance_add() -> u128 { - 3_500 - } - - fn user_token_a_holding_add() -> u128 { - 8_000 - } - - fn user_token_b_holding_add() -> u128 { - 9_000 - } - - fn user_token_lp_holding_add() -> u128 { - 4_000 - } - - fn token_lp_supply_add() -> u128 { - 7_000 - } - - fn vault_a_balance_remove() -> u128 { - 4_000 - } - - fn vault_b_balance_remove() -> u128 { - 2_000 - } - - fn user_token_a_holding_remove() -> u128 { - 11_000 - } - - fn user_token_b_holding_remove() -> u128 { - 10_500 - } - - fn user_token_lp_holding_remove() -> u128 { - 1_000 - } - - fn token_lp_supply_remove() -> u128 { - 4_000 - } - - fn user_token_a_holding_new_definition() -> u128 { - 5_000 - } - - fn user_token_b_holding_new_definition() -> u128 { - 7_500 - } - - fn lp_supply_init() -> u128 { - // isqrt(vault_a_balance_init * vault_b_balance_init) = isqrt(5_000 * 2_500) = 3535 - (Self::vault_a_balance_init() * Self::vault_b_balance_init()).isqrt() - } - } - - struct IdForTests; - - impl IdForTests { - fn pool_definition_id() -> AccountId { - amm_core::compute_pool_pda( - Program::amm().id(), - Self::token_a_definition_id(), - Self::token_b_definition_id(), - ) - } - - fn token_lp_definition_id() -> AccountId { - amm_core::compute_liquidity_token_pda(Program::amm().id(), Self::pool_definition_id()) - } - - fn token_a_definition_id() -> AccountId { - AccountId::new([3; 32]) - } - - fn token_b_definition_id() -> AccountId { - AccountId::new([4; 32]) - } - - fn user_token_a_id() -> AccountId { - AccountId::from(&PublicKey::new_from_private_key( - &PrivateKeysForTests::user_token_a_key(), - )) - } - - fn user_token_b_id() -> AccountId { - AccountId::from(&PublicKey::new_from_private_key( - &PrivateKeysForTests::user_token_b_key(), - )) - } - - fn user_token_lp_id() -> AccountId { - AccountId::from(&PublicKey::new_from_private_key( - &PrivateKeysForTests::user_token_lp_key(), - )) - } - - fn vault_a_id() -> AccountId { - amm_core::compute_vault_pda( - Program::amm().id(), - Self::pool_definition_id(), - Self::token_a_definition_id(), - ) - } - - fn vault_b_id() -> AccountId { - amm_core::compute_vault_pda( - Program::amm().id(), - Self::pool_definition_id(), - Self::token_b_definition_id(), - ) - } - } - - struct AccountForTests; - - impl AccountForTests { - fn user_token_a_holding() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_a_definition_id(), - balance: BalanceForTests::user_token_a_holding_init(), - }), - nonce: 0u128.into(), - } - } - - fn user_token_b_holding() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_b_definition_id(), - balance: BalanceForTests::user_token_b_holding_init(), - }), - nonce: 0u128.into(), - } - } - - fn pool_definition_init() -> Account { - Account { - program_owner: Program::amm().id(), - balance: 0_u128, - data: Data::from(&PoolDefinition { - definition_token_a_id: IdForTests::token_a_definition_id(), - definition_token_b_id: IdForTests::token_b_definition_id(), - vault_a_id: IdForTests::vault_a_id(), - vault_b_id: IdForTests::vault_b_id(), - liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::pool_lp_supply_init(), - reserve_a: BalanceForTests::vault_a_balance_init(), - reserve_b: BalanceForTests::vault_b_balance_init(), - fees: 0_u128, - active: true, - }), - nonce: 0u128.into(), - } - } - - fn token_a_definition_account() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenDefinition::Fungible { - name: String::from("test"), - total_supply: BalanceForTests::token_a_supply(), - metadata_id: None, - }), - nonce: 0u128.into(), - } - } - - fn token_b_definition_acc() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenDefinition::Fungible { - name: String::from("test"), - total_supply: BalanceForTests::token_b_supply(), - metadata_id: None, - }), - nonce: 0u128.into(), - } - } - - fn token_lp_definition_acc() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenDefinition::Fungible { - name: String::from("LP Token"), - total_supply: BalanceForTests::token_lp_supply(), - metadata_id: None, - }), - nonce: 0u128.into(), - } - } - - fn vault_a_init() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_a_definition_id(), - balance: BalanceForTests::vault_a_balance_init(), - }), - nonce: 0u128.into(), - } - } - - fn vault_b_init() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_b_definition_id(), - balance: BalanceForTests::vault_b_balance_init(), - }), - nonce: 0u128.into(), - } - } - - fn user_token_lp_holding() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_lp_definition_id(), - balance: BalanceForTests::user_token_lp_holding_init(), - }), - nonce: 0u128.into(), - } - } - - fn vault_a_swap_1() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_a_definition_id(), - balance: BalanceForTests::vault_a_balance_swap_1(), - }), - nonce: 0u128.into(), - } - } - - fn vault_b_swap_1() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_b_definition_id(), - balance: BalanceForTests::vault_b_balance_swap_1(), - }), - nonce: 0u128.into(), - } - } - - fn pool_definition_swap_1() -> Account { - Account { - program_owner: Program::amm().id(), - balance: 0_u128, - data: Data::from(&PoolDefinition { - definition_token_a_id: IdForTests::token_a_definition_id(), - definition_token_b_id: IdForTests::token_b_definition_id(), - vault_a_id: IdForTests::vault_a_id(), - vault_b_id: IdForTests::vault_b_id(), - liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::pool_lp_supply_init(), - reserve_a: BalanceForTests::vault_a_balance_swap_1(), - reserve_b: BalanceForTests::vault_b_balance_swap_1(), - fees: 0_u128, - active: true, - }), - nonce: 0u128.into(), - } - } - - fn user_token_a_holding_swap_1() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_a_definition_id(), - balance: BalanceForTests::user_token_a_holding_swap_1(), - }), - nonce: 0u128.into(), - } - } - - fn user_token_b_holding_swap_1() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_b_definition_id(), - balance: BalanceForTests::user_token_b_holding_swap_1(), - }), - nonce: 1u128.into(), - } - } - - fn vault_a_swap_2() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_a_definition_id(), - balance: BalanceForTests::vault_a_balance_swap_2(), - }), - nonce: 0u128.into(), - } - } - - fn vault_b_swap_2() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_b_definition_id(), - balance: BalanceForTests::vault_b_balance_swap_2(), - }), - nonce: 0u128.into(), - } - } - - fn pool_definition_swap_2() -> Account { - Account { - program_owner: Program::amm().id(), - balance: 0_u128, - data: Data::from(&PoolDefinition { - definition_token_a_id: IdForTests::token_a_definition_id(), - definition_token_b_id: IdForTests::token_b_definition_id(), - vault_a_id: IdForTests::vault_a_id(), - vault_b_id: IdForTests::vault_b_id(), - liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::pool_lp_supply_init(), - reserve_a: BalanceForTests::vault_a_balance_swap_2(), - reserve_b: BalanceForTests::vault_b_balance_swap_2(), - fees: 0_u128, - active: true, - }), - nonce: 0u128.into(), - } - } - - fn user_token_a_holding_swap_2() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_a_definition_id(), - balance: BalanceForTests::user_token_a_holding_swap_2(), - }), - nonce: 1u128.into(), - } - } - - fn user_token_b_holding_swap_2() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_b_definition_id(), - balance: BalanceForTests::user_token_b_holding_swap_2(), - }), - nonce: 0u128.into(), - } - } - - fn vault_a_add() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_a_definition_id(), - balance: BalanceForTests::vault_a_balance_add(), - }), - nonce: 0u128.into(), - } - } - - fn vault_b_add() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_b_definition_id(), - balance: BalanceForTests::vault_b_balance_add(), - }), - nonce: 0u128.into(), - } - } - - fn pool_definition_add() -> Account { - Account { - program_owner: Program::amm().id(), - balance: 0_u128, - data: Data::from(&PoolDefinition { - definition_token_a_id: IdForTests::token_a_definition_id(), - definition_token_b_id: IdForTests::token_b_definition_id(), - vault_a_id: IdForTests::vault_a_id(), - vault_b_id: IdForTests::vault_b_id(), - liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::token_lp_supply_add(), - reserve_a: BalanceForTests::vault_a_balance_add(), - reserve_b: BalanceForTests::vault_b_balance_add(), - fees: 0_u128, - active: true, - }), - nonce: 0u128.into(), - } - } - - fn user_token_a_holding_add() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_a_definition_id(), - balance: BalanceForTests::user_token_a_holding_add(), - }), - nonce: 1u128.into(), - } - } - - fn user_token_b_holding_add() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_b_definition_id(), - balance: BalanceForTests::user_token_b_holding_add(), - }), - nonce: 1u128.into(), - } - } - - fn user_token_lp_holding_add() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_lp_definition_id(), - balance: BalanceForTests::user_token_lp_holding_add(), - }), - nonce: 0u128.into(), - } - } - - fn token_lp_definition_add() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenDefinition::Fungible { - name: String::from("LP Token"), - total_supply: BalanceForTests::token_lp_supply_add(), - metadata_id: None, - }), - nonce: 0u128.into(), - } - } - - fn vault_a_remove() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_a_definition_id(), - balance: BalanceForTests::vault_a_balance_remove(), - }), - nonce: 0u128.into(), - } - } - - fn vault_b_remove() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_b_definition_id(), - balance: BalanceForTests::vault_b_balance_remove(), - }), - nonce: 0u128.into(), - } - } - - fn pool_definition_remove() -> Account { - Account { - program_owner: Program::amm().id(), - balance: 0_u128, - data: Data::from(&PoolDefinition { - definition_token_a_id: IdForTests::token_a_definition_id(), - definition_token_b_id: IdForTests::token_b_definition_id(), - vault_a_id: IdForTests::vault_a_id(), - vault_b_id: IdForTests::vault_b_id(), - liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::token_lp_supply_remove(), - reserve_a: BalanceForTests::vault_a_balance_remove(), - reserve_b: BalanceForTests::vault_b_balance_remove(), - fees: 0_u128, - active: true, - }), - nonce: 0u128.into(), - } - } - - fn user_token_a_holding_remove() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_a_definition_id(), - balance: BalanceForTests::user_token_a_holding_remove(), - }), - nonce: 0u128.into(), - } - } - - fn user_token_b_holding_remove() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_b_definition_id(), - balance: BalanceForTests::user_token_b_holding_remove(), - }), - nonce: 0u128.into(), - } - } - - fn user_token_lp_holding_remove() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_lp_definition_id(), - balance: BalanceForTests::user_token_lp_holding_remove(), - }), - nonce: 1u128.into(), - } - } - - fn token_lp_definition_remove() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenDefinition::Fungible { - name: String::from("LP Token"), - total_supply: BalanceForTests::token_lp_supply_remove(), - metadata_id: None, - }), - nonce: 0u128.into(), - } - } - - fn token_lp_definition_init_inactive() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenDefinition::Fungible { - name: String::from("LP Token"), - total_supply: 0, - metadata_id: None, - }), - nonce: 0u128.into(), - } - } - - fn vault_a_init_inactive() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_a_definition_id(), - balance: 0, - }), - nonce: 0u128.into(), - } - } - - fn vault_b_init_inactive() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_b_definition_id(), - balance: 0, - }), - nonce: 0u128.into(), - } - } - - fn pool_definition_inactive() -> Account { - Account { - program_owner: Program::amm().id(), - balance: 0_u128, - data: Data::from(&PoolDefinition { - definition_token_a_id: IdForTests::token_a_definition_id(), - definition_token_b_id: IdForTests::token_b_definition_id(), - vault_a_id: IdForTests::vault_a_id(), - vault_b_id: IdForTests::vault_b_id(), - liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: 0, - reserve_a: 0, - reserve_b: 0, - fees: 0_u128, - active: false, - }), - nonce: 0u128.into(), - } - } - - fn user_token_a_holding_new_init() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_a_definition_id(), - balance: BalanceForTests::user_token_a_holding_new_definition(), - }), - nonce: 1u128.into(), - } - } - - fn user_token_b_holding_new_init() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_b_definition_id(), - balance: BalanceForTests::user_token_b_holding_new_definition(), - }), - nonce: 1u128.into(), - } - } - - fn user_token_lp_holding_new_init() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_lp_definition_id(), - balance: BalanceForTests::lp_supply_init(), - }), - nonce: 0u128.into(), - } - } - - fn token_lp_definition_new_init() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenDefinition::Fungible { - name: String::from("LP Token"), - total_supply: BalanceForTests::lp_supply_init(), - metadata_id: None, - }), - nonce: 0u128.into(), - } - } - - fn pool_definition_new_init() -> Account { - Account { - program_owner: Program::amm().id(), - balance: 0_u128, - data: Data::from(&PoolDefinition { - definition_token_a_id: IdForTests::token_a_definition_id(), - definition_token_b_id: IdForTests::token_b_definition_id(), - vault_a_id: IdForTests::vault_a_id(), - vault_b_id: IdForTests::vault_b_id(), - liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::lp_supply_init(), - reserve_a: BalanceForTests::vault_a_balance_init(), - reserve_b: BalanceForTests::vault_b_balance_init(), - fees: 0_u128, - active: true, - }), - nonce: 0u128.into(), - } - } - - fn user_token_lp_holding_init_zero() -> Account { - Account { - program_owner: Program::token().id(), - balance: 0_u128, - data: Data::from(&TokenHolding::Fungible { - definition_id: IdForTests::token_lp_definition_id(), - balance: 0, - }), - nonce: 0u128.into(), - } - } - } - fn transfer_transaction( from: AccountId, from_key: &PrivateKey, @@ -3176,526 +2361,6 @@ pub mod tests { )); } - fn state_for_amm_tests() -> V02State { - let initial_data = []; - let mut state = - V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); - state.force_insert_account( - IdForTests::pool_definition_id(), - AccountForTests::pool_definition_init(), - ); - state.force_insert_account( - IdForTests::token_a_definition_id(), - AccountForTests::token_a_definition_account(), - ); - state.force_insert_account( - IdForTests::token_b_definition_id(), - AccountForTests::token_b_definition_acc(), - ); - state.force_insert_account( - IdForTests::token_lp_definition_id(), - AccountForTests::token_lp_definition_acc(), - ); - state.force_insert_account( - IdForTests::user_token_a_id(), - AccountForTests::user_token_a_holding(), - ); - state.force_insert_account( - IdForTests::user_token_b_id(), - AccountForTests::user_token_b_holding(), - ); - state.force_insert_account( - IdForTests::user_token_lp_id(), - AccountForTests::user_token_lp_holding(), - ); - state.force_insert_account(IdForTests::vault_a_id(), AccountForTests::vault_a_init()); - state.force_insert_account(IdForTests::vault_b_id(), AccountForTests::vault_b_init()); - - state - } - - fn state_for_amm_tests_with_new_def() -> V02State { - let initial_data = []; - let mut state = - V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); - state.force_insert_account( - IdForTests::token_a_definition_id(), - AccountForTests::token_a_definition_account(), - ); - state.force_insert_account( - IdForTests::token_b_definition_id(), - AccountForTests::token_b_definition_acc(), - ); - state.force_insert_account( - IdForTests::user_token_a_id(), - AccountForTests::user_token_a_holding(), - ); - state.force_insert_account( - IdForTests::user_token_b_id(), - AccountForTests::user_token_b_holding(), - ); - state - } - - #[test] - fn simple_amm_remove() { - let mut state = state_for_amm_tests(); - - let instruction = amm_core::Instruction::RemoveLiquidity { - remove_liquidity_amount: BalanceForTests::remove_lp(), - min_amount_to_remove_token_a: BalanceForTests::remove_min_amount_a(), - min_amount_to_remove_token_b: BalanceForTests::remove_min_amount_b(), - }; - - let message = public_transaction::Message::try_new( - Program::amm().id(), - vec![ - IdForTests::pool_definition_id(), - IdForTests::vault_a_id(), - IdForTests::vault_b_id(), - IdForTests::token_lp_definition_id(), - IdForTests::user_token_a_id(), - IdForTests::user_token_b_id(), - IdForTests::user_token_lp_id(), - ], - vec![0u128.into()], - instruction, - ) - .unwrap(); - - let witness_set = public_transaction::WitnessSet::for_message( - &message, - &[&PrivateKeysForTests::user_token_lp_key()], - ); - - let tx = PublicTransaction::new(message, witness_set); - state.transition_from_public_transaction(&tx).unwrap(); - - let pool_post = state.get_account_by_id(IdForTests::pool_definition_id()); - let vault_a_post = state.get_account_by_id(IdForTests::vault_a_id()); - let vault_b_post = state.get_account_by_id(IdForTests::vault_b_id()); - let token_lp_post = state.get_account_by_id(IdForTests::token_lp_definition_id()); - let user_token_a_post = state.get_account_by_id(IdForTests::user_token_a_id()); - let user_token_b_post = state.get_account_by_id(IdForTests::user_token_b_id()); - let user_token_lp_post = state.get_account_by_id(IdForTests::user_token_lp_id()); - - let expected_pool = AccountForTests::pool_definition_remove(); - let expected_vault_a = AccountForTests::vault_a_remove(); - let expected_vault_b = AccountForTests::vault_b_remove(); - let expected_token_lp = AccountForTests::token_lp_definition_remove(); - let expected_user_token_a = AccountForTests::user_token_a_holding_remove(); - let expected_user_token_b = AccountForTests::user_token_b_holding_remove(); - let expected_user_token_lp = AccountForTests::user_token_lp_holding_remove(); - - assert_eq!(pool_post, expected_pool); - assert_eq!(vault_a_post, expected_vault_a); - assert_eq!(vault_b_post, expected_vault_b); - assert_eq!(token_lp_post, expected_token_lp); - assert_eq!(user_token_a_post, expected_user_token_a); - assert_eq!(user_token_b_post, expected_user_token_b); - assert_eq!(user_token_lp_post, expected_user_token_lp); - } - - #[test] - fn simple_amm_new_definition_inactive_initialized_pool_and_uninit_user_lp() { - let mut state = state_for_amm_tests_with_new_def(); - - // Uninitialized in constructor - state.force_insert_account( - IdForTests::vault_a_id(), - AccountForTests::vault_a_init_inactive(), - ); - state.force_insert_account( - IdForTests::vault_b_id(), - AccountForTests::vault_b_init_inactive(), - ); - state.force_insert_account( - IdForTests::pool_definition_id(), - AccountForTests::pool_definition_inactive(), - ); - state.force_insert_account( - IdForTests::token_lp_definition_id(), - AccountForTests::token_lp_definition_init_inactive(), - ); - - let instruction = amm_core::Instruction::NewDefinition { - token_a_amount: BalanceForTests::vault_a_balance_init(), - token_b_amount: BalanceForTests::vault_b_balance_init(), - amm_program_id: Program::amm().id(), - }; - - let message = public_transaction::Message::try_new( - Program::amm().id(), - vec![ - IdForTests::pool_definition_id(), - IdForTests::vault_a_id(), - IdForTests::vault_b_id(), - IdForTests::token_lp_definition_id(), - IdForTests::user_token_a_id(), - IdForTests::user_token_b_id(), - IdForTests::user_token_lp_id(), - ], - vec![0u128.into(), 0u128.into()], - instruction, - ) - .unwrap(); - - let witness_set = public_transaction::WitnessSet::for_message( - &message, - &[ - &PrivateKeysForTests::user_token_a_key(), - &PrivateKeysForTests::user_token_b_key(), - ], - ); - - let tx = PublicTransaction::new(message, witness_set); - state.transition_from_public_transaction(&tx).unwrap(); - - let pool_post = state.get_account_by_id(IdForTests::pool_definition_id()); - let vault_a_post = state.get_account_by_id(IdForTests::vault_a_id()); - let vault_b_post = state.get_account_by_id(IdForTests::vault_b_id()); - let token_lp_post = state.get_account_by_id(IdForTests::token_lp_definition_id()); - let user_token_a_post = state.get_account_by_id(IdForTests::user_token_a_id()); - let user_token_b_post = state.get_account_by_id(IdForTests::user_token_b_id()); - let user_token_lp_post = state.get_account_by_id(IdForTests::user_token_lp_id()); - - let expected_pool = AccountForTests::pool_definition_new_init(); - let expected_vault_a = AccountForTests::vault_a_init(); - let expected_vault_b = AccountForTests::vault_b_init(); - let expected_token_lp = AccountForTests::token_lp_definition_new_init(); - let expected_user_token_a = AccountForTests::user_token_a_holding_new_init(); - let expected_user_token_b = AccountForTests::user_token_b_holding_new_init(); - let expected_user_token_lp = AccountForTests::user_token_lp_holding_new_init(); - - assert_eq!(pool_post, expected_pool); - assert_eq!(vault_a_post, expected_vault_a); - assert_eq!(vault_b_post, expected_vault_b); - assert_eq!(token_lp_post, expected_token_lp); - assert_eq!(user_token_a_post, expected_user_token_a); - assert_eq!(user_token_b_post, expected_user_token_b); - assert_eq!(user_token_lp_post, expected_user_token_lp); - } - - #[test] - fn simple_amm_new_definition_inactive_initialized_pool_init_user_lp() { - let mut state = state_for_amm_tests_with_new_def(); - - // Uninitialized in constructor - state.force_insert_account( - IdForTests::vault_a_id(), - AccountForTests::vault_a_init_inactive(), - ); - state.force_insert_account( - IdForTests::vault_b_id(), - AccountForTests::vault_b_init_inactive(), - ); - state.force_insert_account( - IdForTests::pool_definition_id(), - AccountForTests::pool_definition_inactive(), - ); - state.force_insert_account( - IdForTests::token_lp_definition_id(), - AccountForTests::token_lp_definition_init_inactive(), - ); - state.force_insert_account( - IdForTests::user_token_lp_id(), - AccountForTests::user_token_lp_holding_init_zero(), - ); - - let instruction = amm_core::Instruction::NewDefinition { - token_a_amount: BalanceForTests::vault_a_balance_init(), - token_b_amount: BalanceForTests::vault_b_balance_init(), - amm_program_id: Program::amm().id(), - }; - - let message = public_transaction::Message::try_new( - Program::amm().id(), - vec![ - IdForTests::pool_definition_id(), - IdForTests::vault_a_id(), - IdForTests::vault_b_id(), - IdForTests::token_lp_definition_id(), - IdForTests::user_token_a_id(), - IdForTests::user_token_b_id(), - IdForTests::user_token_lp_id(), - ], - vec![0u128.into(), 0u128.into()], - instruction, - ) - .unwrap(); - - let witness_set = public_transaction::WitnessSet::for_message( - &message, - &[ - &PrivateKeysForTests::user_token_a_key(), - &PrivateKeysForTests::user_token_b_key(), - ], - ); - - let tx = PublicTransaction::new(message, witness_set); - state.transition_from_public_transaction(&tx).unwrap(); - - let pool_post = state.get_account_by_id(IdForTests::pool_definition_id()); - let vault_a_post = state.get_account_by_id(IdForTests::vault_a_id()); - let vault_b_post = state.get_account_by_id(IdForTests::vault_b_id()); - let token_lp_post = state.get_account_by_id(IdForTests::token_lp_definition_id()); - let user_token_a_post = state.get_account_by_id(IdForTests::user_token_a_id()); - let user_token_b_post = state.get_account_by_id(IdForTests::user_token_b_id()); - let user_token_lp_post = state.get_account_by_id(IdForTests::user_token_lp_id()); - - let expected_pool = AccountForTests::pool_definition_new_init(); - let expected_vault_a = AccountForTests::vault_a_init(); - let expected_vault_b = AccountForTests::vault_b_init(); - let expected_token_lp = AccountForTests::token_lp_definition_new_init(); - let expected_user_token_a = AccountForTests::user_token_a_holding_new_init(); - let expected_user_token_b = AccountForTests::user_token_b_holding_new_init(); - let expected_user_token_lp = AccountForTests::user_token_lp_holding_new_init(); - - assert_eq!(pool_post, expected_pool); - assert_eq!(vault_a_post, expected_vault_a); - assert_eq!(vault_b_post, expected_vault_b); - assert_eq!(token_lp_post, expected_token_lp); - assert_eq!(user_token_a_post, expected_user_token_a); - assert_eq!(user_token_b_post, expected_user_token_b); - assert_eq!(user_token_lp_post, expected_user_token_lp); - } - - #[test] - fn simple_amm_new_definition_uninitialized_pool() { - let mut state = state_for_amm_tests_with_new_def(); - - // Uninitialized in constructor - state.force_insert_account( - IdForTests::vault_a_id(), - AccountForTests::vault_a_init_inactive(), - ); - state.force_insert_account( - IdForTests::vault_b_id(), - AccountForTests::vault_b_init_inactive(), - ); - - let instruction = amm_core::Instruction::NewDefinition { - token_a_amount: BalanceForTests::vault_a_balance_init(), - token_b_amount: BalanceForTests::vault_b_balance_init(), - amm_program_id: Program::amm().id(), - }; - - let message = public_transaction::Message::try_new( - Program::amm().id(), - vec![ - IdForTests::pool_definition_id(), - IdForTests::vault_a_id(), - IdForTests::vault_b_id(), - IdForTests::token_lp_definition_id(), - IdForTests::user_token_a_id(), - IdForTests::user_token_b_id(), - IdForTests::user_token_lp_id(), - ], - vec![0u128.into(), 0u128.into()], - instruction, - ) - .unwrap(); - - let witness_set = public_transaction::WitnessSet::for_message( - &message, - &[ - &PrivateKeysForTests::user_token_a_key(), - &PrivateKeysForTests::user_token_b_key(), - ], - ); - - let tx = PublicTransaction::new(message, witness_set); - state.transition_from_public_transaction(&tx).unwrap(); - - let pool_post = state.get_account_by_id(IdForTests::pool_definition_id()); - let vault_a_post = state.get_account_by_id(IdForTests::vault_a_id()); - let vault_b_post = state.get_account_by_id(IdForTests::vault_b_id()); - let token_lp_post = state.get_account_by_id(IdForTests::token_lp_definition_id()); - let user_token_a_post = state.get_account_by_id(IdForTests::user_token_a_id()); - let user_token_b_post = state.get_account_by_id(IdForTests::user_token_b_id()); - let user_token_lp_post = state.get_account_by_id(IdForTests::user_token_lp_id()); - - let expected_pool = AccountForTests::pool_definition_new_init(); - let expected_vault_a = AccountForTests::vault_a_init(); - let expected_vault_b = AccountForTests::vault_b_init(); - let expected_token_lp = AccountForTests::token_lp_definition_new_init(); - let expected_user_token_a = AccountForTests::user_token_a_holding_new_init(); - let expected_user_token_b = AccountForTests::user_token_b_holding_new_init(); - let expected_user_token_lp = AccountForTests::user_token_lp_holding_new_init(); - - assert_eq!(pool_post, expected_pool); - assert_eq!(vault_a_post, expected_vault_a); - assert_eq!(vault_b_post, expected_vault_b); - assert_eq!(token_lp_post, expected_token_lp); - assert_eq!(user_token_a_post, expected_user_token_a); - assert_eq!(user_token_b_post, expected_user_token_b); - assert_eq!(user_token_lp_post, expected_user_token_lp); - } - - #[test] - fn simple_amm_add() { - env_logger::init(); - let mut state = state_for_amm_tests(); - - let instruction = amm_core::Instruction::AddLiquidity { - min_amount_liquidity: BalanceForTests::add_min_amount_lp(), - max_amount_to_add_token_a: BalanceForTests::add_max_amount_a(), - max_amount_to_add_token_b: BalanceForTests::add_max_amount_b(), - }; - - let message = public_transaction::Message::try_new( - Program::amm().id(), - vec![ - IdForTests::pool_definition_id(), - IdForTests::vault_a_id(), - IdForTests::vault_b_id(), - IdForTests::token_lp_definition_id(), - IdForTests::user_token_a_id(), - IdForTests::user_token_b_id(), - IdForTests::user_token_lp_id(), - ], - vec![0u128.into(), 0u128.into()], - instruction, - ) - .unwrap(); - - let witness_set = public_transaction::WitnessSet::for_message( - &message, - &[ - &PrivateKeysForTests::user_token_a_key(), - &PrivateKeysForTests::user_token_b_key(), - ], - ); - - let tx = PublicTransaction::new(message, witness_set); - state.transition_from_public_transaction(&tx).unwrap(); - - let pool_post = state.get_account_by_id(IdForTests::pool_definition_id()); - let vault_a_post = state.get_account_by_id(IdForTests::vault_a_id()); - let vault_b_post = state.get_account_by_id(IdForTests::vault_b_id()); - let token_lp_post = state.get_account_by_id(IdForTests::token_lp_definition_id()); - let user_token_a_post = state.get_account_by_id(IdForTests::user_token_a_id()); - let user_token_b_post = state.get_account_by_id(IdForTests::user_token_b_id()); - let user_token_lp_post = state.get_account_by_id(IdForTests::user_token_lp_id()); - - let expected_pool = AccountForTests::pool_definition_add(); - let expected_vault_a = AccountForTests::vault_a_add(); - let expected_vault_b = AccountForTests::vault_b_add(); - let expected_token_lp = AccountForTests::token_lp_definition_add(); - let expected_user_token_a = AccountForTests::user_token_a_holding_add(); - let expected_user_token_b = AccountForTests::user_token_b_holding_add(); - let expected_user_token_lp = AccountForTests::user_token_lp_holding_add(); - - assert_eq!(pool_post, expected_pool); - assert_eq!(vault_a_post, expected_vault_a); - assert_eq!(vault_b_post, expected_vault_b); - assert_eq!(token_lp_post, expected_token_lp); - assert_eq!(user_token_a_post, expected_user_token_a); - assert_eq!(user_token_b_post, expected_user_token_b); - assert_eq!(user_token_lp_post, expected_user_token_lp); - } - - #[test] - fn simple_amm_swap_1() { - let mut state = state_for_amm_tests(); - - let instruction = amm_core::Instruction::Swap { - swap_amount_in: BalanceForTests::swap_amount_in(), - min_amount_out: BalanceForTests::swap_min_amount_out(), - token_definition_id_in: IdForTests::token_b_definition_id(), - }; - - let message = public_transaction::Message::try_new( - Program::amm().id(), - vec![ - IdForTests::pool_definition_id(), - IdForTests::vault_a_id(), - IdForTests::vault_b_id(), - IdForTests::user_token_a_id(), - IdForTests::user_token_b_id(), - ], - vec![0u128.into()], - instruction, - ) - .unwrap(); - - let witness_set = public_transaction::WitnessSet::for_message( - &message, - &[&PrivateKeysForTests::user_token_b_key()], - ); - - let tx = PublicTransaction::new(message, witness_set); - state.transition_from_public_transaction(&tx).unwrap(); - - let pool_post = state.get_account_by_id(IdForTests::pool_definition_id()); - let vault_a_post = state.get_account_by_id(IdForTests::vault_a_id()); - let vault_b_post = state.get_account_by_id(IdForTests::vault_b_id()); - let user_token_a_post = state.get_account_by_id(IdForTests::user_token_a_id()); - let user_token_b_post = state.get_account_by_id(IdForTests::user_token_b_id()); - - let expected_pool = AccountForTests::pool_definition_swap_1(); - let expected_vault_a = AccountForTests::vault_a_swap_1(); - let expected_vault_b = AccountForTests::vault_b_swap_1(); - let expected_user_token_a = AccountForTests::user_token_a_holding_swap_1(); - let expected_user_token_b = AccountForTests::user_token_b_holding_swap_1(); - - assert_eq!(pool_post, expected_pool); - assert_eq!(vault_a_post, expected_vault_a); - assert_eq!(vault_b_post, expected_vault_b); - assert_eq!(user_token_a_post, expected_user_token_a); - assert_eq!(user_token_b_post, expected_user_token_b); - } - - #[test] - fn simple_amm_swap_2() { - let mut state = state_for_amm_tests(); - - let instruction = amm_core::Instruction::Swap { - swap_amount_in: BalanceForTests::swap_amount_in(), - min_amount_out: BalanceForTests::swap_min_amount_out(), - token_definition_id_in: IdForTests::token_a_definition_id(), - }; - let message = public_transaction::Message::try_new( - Program::amm().id(), - vec![ - IdForTests::pool_definition_id(), - IdForTests::vault_a_id(), - IdForTests::vault_b_id(), - IdForTests::user_token_a_id(), - IdForTests::user_token_b_id(), - ], - vec![0u128.into()], - instruction, - ) - .unwrap(); - - let witness_set = public_transaction::WitnessSet::for_message( - &message, - &[&PrivateKeysForTests::user_token_a_key()], - ); - - let tx = PublicTransaction::new(message, witness_set); - state.transition_from_public_transaction(&tx).unwrap(); - - let pool_post = state.get_account_by_id(IdForTests::pool_definition_id()); - let vault_a_post = state.get_account_by_id(IdForTests::vault_a_id()); - let vault_b_post = state.get_account_by_id(IdForTests::vault_b_id()); - let user_token_a_post = state.get_account_by_id(IdForTests::user_token_a_id()); - let user_token_b_post = state.get_account_by_id(IdForTests::user_token_b_id()); - - let expected_pool = AccountForTests::pool_definition_swap_2(); - let expected_vault_a = AccountForTests::vault_a_swap_2(); - let expected_vault_b = AccountForTests::vault_b_swap_2(); - let expected_user_token_a = AccountForTests::user_token_a_holding_swap_2(); - let expected_user_token_b = AccountForTests::user_token_b_holding_swap_2(); - - assert_eq!(pool_post, expected_pool); - assert_eq!(vault_a_post, expected_vault_a); - assert_eq!(vault_b_post, expected_vault_b); - assert_eq!(user_token_a_post, expected_user_token_a); - assert_eq!(user_token_b_post, expected_user_token_b); - } - #[test] fn execution_that_requires_authentication_of_a_program_derived_account_id_succeeds() { let chain_caller = Program::chain_caller(); @@ -3779,7 +2444,7 @@ pub mod tests { chain_caller.id(), vec![to, from], // The chain_caller program permutes the account order in the chain // call - vec![0u128.into()], + vec![0], instruction, ) .unwrap(); @@ -3849,8 +2514,8 @@ pub mod tests { dependencies.insert(auth_transfers.id(), auth_transfers); let program_with_deps = ProgramWithDependencies::new(chain_caller, dependencies); - let from_new_nonce = Nonce::default().private_account_nonce_increment(&from_keys.nsk); - let to_new_nonce = Nonce::default().private_account_nonce_increment(&to_keys.nsk); + let from_new_nonce = 0xdead_beef1; + let to_new_nonce = 0xdead_beef2; let from_expected_post = Account { balance: initial_balance - u128::from(number_of_calls) * amount, @@ -3871,6 +2536,7 @@ pub mod tests { vec![to_account, from_account], Program::serialize_instruction(instruction).unwrap(), vec![1, 1], + vec![from_new_nonce, to_new_nonce], vec![(from_keys.npk(), to_ss), (to_keys.npk(), from_ss)], vec![from_keys.nsk, to_keys.nsk], vec![ @@ -4066,14 +2732,14 @@ pub mod tests { let expected_sender_post = { let mut this = state.get_account_by_id(sender_id); this.balance = sender_init_balance; - this.nonce = 0u128.into(); + this.nonce = 0; this }; let expected_recipient_post = { let mut this = state.get_account_by_id(sender_id); this.balance = recipient_init_balance; - this.nonce = 0u128.into(); + this.nonce = 0; this }; @@ -4102,11 +2768,14 @@ pub mod tests { // Balance to initialize the account with (0 for a new account) let balance: u128 = 0; + let nonce = 0xdead_beef1; + // Execute and prove the circuit with the authorized account but no commitment proof let (output, proof) = execute_and_prove( vec![authorized_account], Program::serialize_instruction(balance).unwrap(), vec![1], + vec![nonce], vec![(private_keys.npk(), shared_secret)], vec![private_keys.nsk], vec![None], @@ -4152,12 +2821,14 @@ pub mod tests { let epk = EphemeralPublicKey::from_scalar(esk); let balance: u128 = 0; + let nonce = 0xdead_beef1; // Step 2: Execute claimer program to claim the account with authentication let (output, proof) = execute_and_prove( vec![authorized_account.clone()], Program::serialize_instruction(balance).unwrap(), vec![1], + vec![nonce], vec![(private_keys.npk(), shared_secret)], vec![private_keys.nsk], vec![None], @@ -4198,11 +2869,14 @@ pub mod tests { let esk2 = [4; 32]; let shared_secret2 = SharedSecretKey::new(&esk2, &private_keys.vpk()); + let nonce2 = 0xdead_beef2; + // Step 3: Try to execute noop program with authentication but without initialization let res = execute_and_prove( vec![account_metadata], Program::serialize_instruction(()).unwrap(), vec![1], + vec![nonce2], vec![(private_keys.npk(), shared_secret2)], vec![private_keys.nsk], vec![None], @@ -4272,6 +2946,7 @@ pub mod tests { vec![private_account], Program::serialize_instruction(instruction).unwrap(), vec![1], + vec![2], vec![( sender_keys.npk(), SharedSecretKey::new(&[3; 32], &sender_keys.vpk()), @@ -4299,6 +2974,7 @@ pub mod tests { vec![private_account], Program::serialize_instruction(instruction).unwrap(), vec![1], + vec![2], vec![( sender_keys.npk(), SharedSecretKey::new(&[3; 32], &sender_keys.vpk()), @@ -4350,11 +3026,14 @@ pub mod tests { dependencies.insert(auth_transfers.id(), auth_transfers); let program_with_deps = ProgramWithDependencies::new(malicious_program, dependencies); + let recipient_new_nonce = 0xdead_beef1; + // Act - execute the malicious program - this should fail during proving let result = execute_and_prove( vec![sender_account, recipient_account], Program::serialize_instruction(instruction).unwrap(), vec![0, 1], + vec![recipient_new_nonce], vec![(recipient_keys.npk(), recipient)], vec![recipient_keys.nsk], vec![state.get_proof_for_commitment(&recipient_commitment)], diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 216ab337..63e14bb6 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -28,6 +28,7 @@ base58.workspace = true base64.workspace = true borsh.workspace = true hex.workspace = true +rand.workspace = true itertools.workspace = true sha2.workspace = true futures.workspace = true diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index 026a6df5..c7be5811 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -1,9 +1,11 @@ -use std::{collections::HashMap, path::PathBuf, str::FromStr}; +use std::{collections::HashMap, path::PathBuf, str::FromStr as _}; -use anyhow::Result; -use base58::ToBase58; +use anyhow::{Context as _, Result}; +use base58::ToBase58 as _; use key_protocol::key_protocol_core::NSSAUserData; use nssa::Account; +use nssa_core::account::Nonce; +use rand::{RngCore as _, rngs::OsRng}; use serde::Serialize; use crate::{ @@ -14,6 +16,39 @@ use crate::{ }, }; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AccountPrivacyKind { + Public, + Private, +} + +/// Human-readable representation of an account. +#[derive(Serialize)] +pub(crate) struct HumanReadableAccount { + balance: u128, + program_owner: String, + data: String, + nonce: u128, +} + +impl From for HumanReadableAccount { + fn from(account: Account) -> Self { + let program_owner = account + .program_owner + .iter() + .flat_map(|n| n.to_le_bytes()) + .collect::>() + .to_base58(); + let data = hex::encode(account.data); + Self { + balance: account.balance, + program_owner, + data, + nonce: account.nonce, + } + } +} + /// Get home dir for wallet. Env var `NSSA_WALLET_HOME_DIR` must be set before execution to succeed. fn get_home_nssa_var() -> Result { Ok(PathBuf::from_str(&std::env::var(HOME_DIR_ENV_VAR)?)?) @@ -23,26 +58,22 @@ fn get_home_nssa_var() -> Result { fn get_home_default_path() -> Result { std::env::home_dir() .map(|path| path.join(".nssa").join("wallet")) - .ok_or(anyhow::anyhow!("Failed to get HOME")) + .context("Failed to get HOME") } /// Get home dir for wallet. pub fn get_home() -> Result { - if let Ok(home) = get_home_nssa_var() { - Ok(home) - } else { - get_home_default_path() - } + get_home_nssa_var().or_else(|_| get_home_default_path()) } -/// Fetch config path from default home +/// Fetch config path from default home. pub fn fetch_config_path() -> Result { let home = get_home()?; let config_path = home.join("wallet_config.json"); Ok(config_path) } -/// Fetch path to data storage from default home +/// Fetch path to data storage from default home. /// /// File must be created through setup beforehand. pub fn fetch_persistent_storage_path() -> Result { @@ -51,7 +82,8 @@ pub fn fetch_persistent_storage_path() -> Result { Ok(accs_path) } -/// Produces data for storage +/// Produces data for storage. +#[must_use] pub fn produce_data_for_storage( user_data: &NSSAUserData, last_synced_block: u64, @@ -92,18 +124,18 @@ pub fn produce_data_for_storage( pub_sign_key: key.clone(), }) .into(), - ) + ); } for (account_id, (key_chain, account)) in &user_data.default_user_private_accounts { vec_for_storage.push( - InitialAccountData::Private(InitialAccountDataPrivate { + InitialAccountData::Private(Box::new(InitialAccountDataPrivate { account_id: *account_id, account: account.clone(), key_chain: key_chain.clone(), - }) + })) .into(), - ) + ); } PersistentStorage { @@ -113,10 +145,12 @@ pub fn produce_data_for_storage( } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum AccountPrivacyKind { - Public, - Private, +pub(crate) fn produce_random_nonces(size: usize) -> Vec { + let mut result = vec![[0; 16]; size]; + for bytes in &mut result { + OsRng.fill_bytes(bytes); + } + result.into_iter().map(Nonce::from_le_bytes).collect() } pub(crate) fn parse_addr_with_privacy_prefix( @@ -124,12 +158,12 @@ pub(crate) fn parse_addr_with_privacy_prefix( ) -> Result<(String, AccountPrivacyKind)> { if account_base58.starts_with("Public/") { Ok(( - account_base58.strip_prefix("Public/").unwrap().to_string(), + account_base58.strip_prefix("Public/").unwrap().to_owned(), AccountPrivacyKind::Public, )) } else if account_base58.starts_with("Private/") { Ok(( - account_base58.strip_prefix("Private/").unwrap().to_string(), + account_base58.strip_prefix("Private/").unwrap().to_owned(), AccountPrivacyKind::Private, )) } else { @@ -137,54 +171,12 @@ pub(crate) fn parse_addr_with_privacy_prefix( } } -/// Human-readable representation of an account. -#[derive(Serialize)] -pub(crate) struct HumanReadableAccount { - balance: u128, - program_owner: String, - data: String, - nonce: u128, -} - -impl From for HumanReadableAccount { - fn from(account: Account) -> Self { - let program_owner = account - .program_owner - .iter() - .flat_map(|n| n.to_le_bytes()) - .collect::>() - .to_base58(); - let data = hex::encode(account.data); - Self { - balance: account.balance, - program_owner, - data, - nonce: account.nonce.0, - } - } -} - #[cfg(test)] mod tests { use super::*; #[test] - fn test_get_home_get_env_var() { - unsafe { - std::env::set_var(HOME_DIR_ENV_VAR, "/path/to/configs"); - } - - let home = get_home().unwrap(); - - assert_eq!(PathBuf::from_str("/path/to/configs").unwrap(), home); - - unsafe { - std::env::remove_var(HOME_DIR_ENV_VAR); - } - } - - #[test] - fn test_addr_parse_with_privacy() { + fn addr_parse_with_privacy() { let addr_base58 = "Public/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy"; let (_, addr_kind) = parse_addr_with_privacy_prefix(addr_base58).unwrap(); diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index c253797b..a3c58a97 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -32,7 +32,7 @@ use tokio::io::AsyncWriteExt as _; use crate::{ config::{PersistentStorage, WalletConfigOverrides}, - helperfunctions::produce_data_for_storage, + helperfunctions::{produce_data_for_storage, produce_random_nonces}, poller::TxPoller, }; @@ -364,6 +364,7 @@ impl WalletCore { pre_states, instruction_data, acc_manager.visibility_mask().to_vec(), + produce_random_nonces(private_account_keys.len()), private_account_keys .iter() .map(|keys| (keys.npk.clone(), keys.ssk)) diff --git a/wallet/src/program_facades/amm.rs b/wallet/src/program_facades/amm.rs index 19a51f29..251970bc 100644 --- a/wallet/src/program_facades/amm.rs +++ b/wallet/src/program_facades/amm.rs @@ -80,10 +80,7 @@ impl Amm<'_> { let message = nssa::public_transaction::Message::try_new( program.id(), account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), + nonces, instruction, ) .unwrap(); @@ -190,10 +187,7 @@ impl Amm<'_> { let message = nssa::public_transaction::Message::try_new( program.id(), account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), + nonces, instruction, ) .unwrap(); @@ -280,10 +274,7 @@ impl Amm<'_> { let message = nssa::public_transaction::Message::try_new( program.id(), account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), + nonces, instruction, ) .unwrap(); @@ -365,10 +356,7 @@ impl Amm<'_> { let message = nssa::public_transaction::Message::try_new( program.id(), account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), + nonces, instruction, ) .unwrap(); diff --git a/wallet/src/program_facades/native_token_transfer/public.rs b/wallet/src/program_facades/native_token_transfer/public.rs index eefaa1fe..eb2adc9a 100644 --- a/wallet/src/program_facades/native_token_transfer/public.rs +++ b/wallet/src/program_facades/native_token_transfer/public.rs @@ -29,16 +29,8 @@ impl NativeTokenTransfer<'_> { let account_ids = vec![from, to]; let program_id = Program::authenticated_transfer_program().id(); - let message = Message::try_new( - program_id, - account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), - balance_to_move, - ) - .unwrap(); + let message = + Message::try_new(program_id, account_ids, nonces, balance_to_move).unwrap(); let signing_key = self.0.storage.user_data.get_pub_account_signing_key(from); @@ -69,16 +61,7 @@ impl NativeTokenTransfer<'_> { let instruction: u128 = 0; let account_ids = vec![from]; let program_id = Program::authenticated_transfer_program().id(); - let message = Message::try_new( - program_id, - account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), - instruction, - ) - .unwrap(); + let message = Message::try_new(program_id, account_ids, nonces, instruction).unwrap(); let signing_key = self.0.storage.user_data.get_pub_account_signing_key(from); diff --git a/wallet/src/program_facades/token.rs b/wallet/src/program_facades/token.rs index bdacae37..fe5165ff 100644 --- a/wallet/src/program_facades/token.rs +++ b/wallet/src/program_facades/token.rs @@ -141,10 +141,7 @@ impl Token<'_> { let message = nssa::public_transaction::Message::try_new( program_id, account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), + nonces, instruction, ) .unwrap(); @@ -345,10 +342,7 @@ impl Token<'_> { let message = nssa::public_transaction::Message::try_new( Program::token().id(), account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), + nonces, instruction, ) .expect("Instruction should serialize"); @@ -478,10 +472,7 @@ impl Token<'_> { let message = nssa::public_transaction::Message::try_new( Program::token().id(), account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), + nonces, instruction, ) .unwrap();