diff --git a/Cargo.lock b/Cargo.lock index 981168d..eeb8f5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2658,6 +2658,7 @@ version = "0.1.0" dependencies = [ "borsh", "bytemuck", + "env_logger", "hex", "hex-literal 1.1.0", "log", diff --git a/artifacts/program_methods/amm.bin b/artifacts/program_methods/amm.bin index 2630aa2..354e655 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 2e78e0a..1b72c46 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 75cb735..91d2b93 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 f992c12..8da8b89 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 c8fb306..404f32b 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 580b944..2269341 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 e09f80f..6bbc507 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 aa504c6..56b017e 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/claimer.bin b/artifacts/test_program_methods/claimer.bin index 22137bb..0f42aae 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 24a21db..99089d3 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 8f13112..ffb622f 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/minter.bin b/artifacts/test_program_methods/minter.bin index 5037f84..08a57ea 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 ec4f40c..891acd5 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 b5ef3e5..1779383 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 2f5d418..9dcb36a 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 a59235e..fba8457 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 260f227..6daa6a1 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 4e8d9a7..4fa42b2 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/integration_tests/src/test_suite_map.rs b/integration_tests/src/test_suite_map.rs index 8a88ec7..e722cc5 100644 --- a/integration_tests/src/test_suite_map.rs +++ b/integration_tests/src/test_suite_map.rs @@ -347,11 +347,14 @@ pub fn prepare_function_map() -> HashMap { assert_eq!(definition_acc.program_owner, Program::token().id()); // The data of a token definition account has the following layout: - // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] + // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) || metadata id (32 + // bytes)] assert_eq!( definition_acc.data.as_ref(), &[ - 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 ] ); @@ -434,6 +437,94 @@ pub fn prepare_function_map() -> HashMap { u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()), 7 ); + + // Burn 3 tokens from `recipient_acc` + let subcommand = TokenProgramAgnosticSubcommand::Burn { + definition: make_public_account_input_from_str(&definition_account_id.to_string()), + holder: make_public_account_input_from_str(&recipient_account_id.to_string()), + amount: 3, + }; + + 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; + + // Check the status of the token definition account is the expected after the execution + let definition_acc = seq_client + .get_account(definition_account_id.to_string()) + .await + .unwrap() + .account; + + assert_eq!( + definition_acc.data.as_ref(), + &[ + 0, 65, 32, 78, 65, 77, 69, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 + ] + ); + + // Check the status of the account at `recipient_account_id` is the expected after the + // execution + let recipient_acc = seq_client + .get_account(recipient_account_id.to_string()) + .await + .unwrap() + .account; + + assert_eq!( + u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()), + 4 + ); + + // Mint 10 tokens at `recipient_acc` + let subcommand = TokenProgramAgnosticSubcommand::Mint { + definition: make_public_account_input_from_str(&definition_account_id.to_string()), + holder: Some(make_public_account_input_from_str( + &recipient_account_id.to_string(), + )), + holder_npk: None, + holder_ipk: None, + amount: 10, + }; + + 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; + + // Check the status of the token definition account is the expected after the execution + let definition_acc = seq_client + .get_account(definition_account_id.to_string()) + .await + .unwrap() + .account; + + assert_eq!( + definition_acc.data.as_ref(), + &[ + 0, 65, 32, 78, 65, 77, 69, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 + ] + ); + + // Check the status of the account at `recipient_account_id` is the expected after the + // execution + let recipient_acc = seq_client + .get_account(recipient_account_id.to_string()) + .await + .unwrap() + .account; + + assert_eq!( + u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()), + 14 + ); } /// This test creates a new private token using the token program. After creating the token, the @@ -506,11 +597,14 @@ pub fn prepare_function_map() -> HashMap { assert_eq!(definition_acc.program_owner, Program::token().id()); // The data of a token definition account has the following layout: - // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] + // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) || metadata id (32 + // bytes)] assert_eq!( definition_acc.data.as_ref(), &[ - 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 ] ); @@ -590,6 +684,194 @@ pub fn prepare_function_map() -> HashMap { .get_private_account_commitment(&recipient_account_id) .unwrap(); assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); + + // Burn 3 tokens from `recipient_acc` + let subcommand = TokenProgramAgnosticSubcommand::Burn { + definition: make_public_account_input_from_str(&definition_account_id.to_string()), + holder: make_private_account_input_from_str(&recipient_account_id.to_string()), + amount: 3, + }; + + 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; + + // Check the status of the token definition account is the expected after the execution + let definition_acc = seq_client + .get_account(definition_account_id.to_string()) + .await + .unwrap() + .account; + + assert_eq!( + definition_acc.data.as_ref(), + &[ + 0, 65, 32, 78, 65, 77, 69, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 + ] + ); + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment2 = wallet_storage + .get_private_account_commitment(&recipient_account_id) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); + + // Check the status of the account at `recipient_account_id` is the expected after the + // execution + let recipient_acc = wallet_storage + .get_account_private(&recipient_account_id) + .unwrap(); + + assert_eq!( + u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()), + 11 + ); + + // Mint 10 tokens at `recipient_acc` + let subcommand = TokenProgramAgnosticSubcommand::Mint { + definition: make_public_account_input_from_str(&definition_account_id.to_string()), + holder: Some(make_private_account_input_from_str( + &recipient_account_id.to_string(), + )), + holder_npk: None, + holder_ipk: None, + amount: 10, + }; + + 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; + + // Check the status of the token definition account is the expected after the execution + let definition_acc = seq_client + .get_account(definition_account_id.to_string()) + .await + .unwrap() + .account; + + assert_eq!( + definition_acc.data.as_ref(), + &[ + 0, 65, 32, 78, 65, 77, 69, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 + ] + ); + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment2 = wallet_storage + .get_private_account_commitment(&recipient_account_id) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); + + // Check the status of the account at `recipient_account_id` is the expected after the + // execution + let recipient_acc = wallet_storage + .get_account_private(&recipient_account_id) + .unwrap(); + + assert_eq!( + u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()), + 21 + ); + + // Now the same mint, but in foreign way + + // Create new account for receiving a mint transaction + let SubcommandReturnValue::RegisterAccount { + account_id: recipient_account_id2, + } = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Private { cci: None }, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let (holder_keys, _) = wallet_storage + .storage + .user_data + .get_private_account(&recipient_account_id2) + .unwrap(); + + // Mint 9 tokens at `recipient_acc2` + let subcommand = TokenProgramAgnosticSubcommand::Mint { + definition: make_public_account_input_from_str(&definition_account_id.to_string()), + holder: None, + holder_npk: Some(hex::encode(holder_keys.nullifer_public_key.0)), + holder_ipk: Some(hex::encode( + holder_keys.incoming_viewing_public_key.0.clone(), + )), + amount: 9, + }; + + 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; + + // Sync to claim holder + let command = Command::Account(AccountSubcommand::SyncPrivate {}); + + wallet::cli::execute_subcommand(command).await.unwrap(); + + // Check the status of the token definition account is the expected after the execution + let definition_acc = seq_client + .get_account(definition_account_id.to_string()) + .await + .unwrap() + .account; + + assert_eq!( + definition_acc.data.as_ref(), + &[ + 0, 65, 32, 78, 65, 77, 69, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 + ] + ); + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + let new_commitment2 = wallet_storage + .get_private_account_commitment(&recipient_account_id2) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); + + // Check the status of the account at `recipient_account_id2` is the expected after the + // execution + let recipient_acc = wallet_storage + .get_account_private(&recipient_account_id2) + .unwrap(); + + assert_eq!( + u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()), + 9 + ); } /// This test creates a new private token using the token program. All accounts are private @@ -663,8 +945,8 @@ pub fn prepare_function_map() -> HashMap { .account; assert_eq!(supply_acc.program_owner, Program::token().id()); - // The data of a token definition account has the following layout: - // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] + // The data of a token holding account has the following layout: + // [ 0x01 || definition id (32 bytes) || balance (little endian 16 bytes) ] assert_eq!( supply_acc.data.as_ref(), &[ @@ -673,6 +955,287 @@ pub fn prepare_function_map() -> HashMap { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ); + + // Create new account for receiving a mint transaction + let SubcommandReturnValue::RegisterAccount { + account_id: recipient_account_id_pr, + } = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Private { cci: None }, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + + // Create new account for receiving a mint transaction + let SubcommandReturnValue::RegisterAccount { + account_id: recipient_account_id_pub, + } = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Public { cci: None }, + ))) + .await + .unwrap() + else { + panic!("invalid subcommand return value"); + }; + + // Mint 10 tokens at `recipient_acc_pub` + let subcommand = TokenProgramAgnosticSubcommand::Mint { + definition: make_private_account_input_from_str(&definition_account_id.to_string()), + holder: Some(make_public_account_input_from_str( + &recipient_account_id_pub.to_string(), + )), + holder_npk: None, + holder_ipk: None, + amount: 10, + }; + + 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 wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + // Check the status of the token definition account is the expected after the execution + let definition_acc = wallet_storage + .get_account_private(&definition_account_id) + .unwrap(); + + assert_eq!( + definition_acc.data.as_ref(), + &[ + 0, 65, 32, 78, 65, 77, 69, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 + ] + ); + + // Check the status of the account at `recipient_account_id_pub` is the expected after the + // execution + let recipient_acc_pub = seq_client + .get_account(recipient_account_id_pub.to_string()) + .await + .unwrap() + .account; + + assert_eq!( + u128::from_le_bytes(recipient_acc_pub.data[33..].try_into().unwrap()), + 10 + ); + + let (holder_keys, _) = wallet_storage + .storage + .user_data + .get_private_account(&recipient_account_id_pr) + .unwrap(); + + // Mint 5 tokens at `recipient_acc_pr` + let subcommand = TokenProgramAgnosticSubcommand::Mint { + definition: make_private_account_input_from_str(&definition_account_id.to_string()), + holder: None, + holder_npk: Some(hex::encode(holder_keys.nullifer_public_key.0)), + holder_ipk: Some(hex::encode( + holder_keys.incoming_viewing_public_key.0.clone(), + )), + amount: 5, + }; + + 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; + + // Sync to claim holder + let command = Command::Account(AccountSubcommand::SyncPrivate {}); + + wallet::cli::execute_subcommand(command).await.unwrap(); + + let wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + // Check the status of the token definition account is the expected after the execution + let definition_acc = wallet_storage + .get_account_private(&definition_account_id) + .unwrap(); + + assert_eq!( + definition_acc.data.as_ref(), + &[ + 0, 65, 32, 78, 65, 77, 69, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 + ] + ); + + let new_commitment2 = wallet_storage + .get_private_account_commitment(&recipient_account_id_pr) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); + + // Check the status of the account at `recipient_account_id_pr` is the expected after the + // execution + let recipient_acc_pr = wallet_storage + .get_account_private(&recipient_account_id_pr) + .unwrap(); + + assert_eq!( + u128::from_le_bytes(recipient_acc_pr.data[33..].try_into().unwrap()), + 5 + ); + + // Mint 5 tokens at `recipient_acc_pr` + let subcommand = TokenProgramAgnosticSubcommand::Mint { + definition: make_private_account_input_from_str(&definition_account_id.to_string()), + holder: Some(make_private_account_input_from_str( + &recipient_account_id_pr.to_string(), + )), + holder_npk: None, + holder_ipk: None, + amount: 5, + }; + + 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 wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + // Check the status of the token definition account is the expected after the execution + let definition_acc = wallet_storage + .get_account_private(&definition_account_id) + .unwrap(); + + assert_eq!( + definition_acc.data.as_ref(), + &[ + 0, 65, 32, 78, 65, 77, 69, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 + ] + ); + + let new_commitment2 = wallet_storage + .get_private_account_commitment(&recipient_account_id_pr) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); + + // Check the status of the account at `recipient_account_id_pr` is the expected after the + // execution + let recipient_acc = wallet_storage + .get_account_private(&recipient_account_id_pr) + .unwrap(); + + assert_eq!( + u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()), + 10 + ); + + // Burn 5 tokens at `recipient_acc_pub` + let subcommand = TokenProgramAgnosticSubcommand::Burn { + definition: make_private_account_input_from_str(&definition_account_id.to_string()), + holder: make_public_account_input_from_str(&recipient_account_id_pub.to_string()), + amount: 5, + }; + + 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 wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + // Check the status of the token definition account is the expected after the execution + let definition_acc = wallet_storage + .get_account_private(&definition_account_id) + .unwrap(); + + assert_eq!( + definition_acc.data.as_ref(), + &[ + 0, 65, 32, 78, 65, 77, 69, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 + ] + ); + + // Check the status of the account at `recipient_account_id_pub` is the expected after the + // execution + let recipient_acc_pub = seq_client + .get_account(recipient_account_id_pub.to_string()) + .await + .unwrap() + .account; + + assert_eq!( + u128::from_le_bytes(recipient_acc_pub.data[33..].try_into().unwrap()), + 5 + ); + + // Burn 5 tokens at `recipient_acc_pr` + let subcommand = TokenProgramAgnosticSubcommand::Burn { + definition: make_private_account_input_from_str(&definition_account_id.to_string()), + holder: make_private_account_input_from_str(&recipient_account_id_pr.to_string()), + amount: 5, + }; + + 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 wallet_config = fetch_config().await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + .await + .unwrap(); + + // Check the status of the token definition account is the expected after the execution + let definition_acc = wallet_storage + .get_account_private(&definition_account_id) + .unwrap(); + + assert_eq!( + definition_acc.data.as_ref(), + &[ + 0, 65, 32, 78, 65, 77, 69, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 + ] + ); + + let new_commitment2 = wallet_storage + .get_private_account_commitment(&recipient_account_id_pr) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); + + // Check the status of the account at `recipient_account_id_pr` is the expected after the + // execution + let recipient_acc = wallet_storage + .get_account_private(&recipient_account_id_pr) + .unwrap(); + + assert_eq!( + u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()), + 5 + ); } /// This test creates a new private token using the token program. All accounts are private @@ -754,17 +1317,20 @@ pub fn prepare_function_map() -> HashMap { assert_eq!(definition_acc.program_owner, Program::token().id()); // The data of a token definition account has the following layout: - // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] + // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) || metadata id (32 + // bytes)] assert_eq!( definition_acc.data.as_ref(), &[ - 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 ] ); assert_eq!(supply_acc.program_owner, Program::token().id()); - // The data of a token definition account has the following layout: - // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] + // The data of a token holding account has the following layout: + // [ 0x01 || definition id (32 bytes) || balance (little endian 16 bytes) ] assert_eq!( supply_acc.data.as_ref(), &[ @@ -844,11 +1410,14 @@ pub fn prepare_function_map() -> HashMap { assert_eq!(definition_acc.program_owner, Program::token().id()); // The data of a token definition account has the following layout: - // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] + // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) || metadata id (32 + // bytes)] assert_eq!( definition_acc.data.as_ref(), &[ - 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 ] ); @@ -980,11 +1549,14 @@ pub fn prepare_function_map() -> HashMap { assert_eq!(definition_acc.program_owner, Program::token().id()); // The data of a token definition account has the following layout: - // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] + // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) || metadata id (32 + // bytes)] assert_eq!( definition_acc.data.as_ref(), &[ - 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 ] ); @@ -1116,11 +1688,14 @@ pub fn prepare_function_map() -> HashMap { assert_eq!(definition_acc.program_owner, Program::token().id()); // The data of a token definition account has the following layout: - // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ] + // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) || metadata id (32 + // bytes)] assert_eq!( definition_acc.data.as_ref(), &[ - 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 ] ); diff --git a/nssa/Cargo.toml b/nssa/Cargo.toml index 07eb0a2..f1c7709 100644 --- a/nssa/Cargo.toml +++ b/nssa/Cargo.toml @@ -25,6 +25,7 @@ risc0-binfmt = "3.0.2" [dev-dependencies] test_program_methods.workspace = true hex-literal = "1.0.0" +env_logger.workspace = true [features] default = [] diff --git a/nssa/core/Cargo.toml b/nssa/core/Cargo.toml index f5500ca..473cde9 100644 --- a/nssa/core/Cargo.toml +++ b/nssa/core/Cargo.toml @@ -6,14 +6,15 @@ edition = "2024" [dependencies] risc0-zkvm.workspace = true borsh.workspace = true -serde = { workspace = true } +serde.workspace = true thiserror.workspace = true -chacha20 = { version = "0.9", default-features = false } -bytemuck = { workspace = true } +bytemuck.workspace = true k256 = { workspace = true, optional = true } base58 = { workspace = true, optional = true } anyhow = { workspace = true, optional = true } +chacha20 = { version = "0.9", default-features = false } + [dev-dependencies] serde_json.workspace = true diff --git a/nssa/core/src/account.rs b/nssa/core/src/account.rs index 90a4f13..51467af 100644 --- a/nssa/core/src/account.rs +++ b/nssa/core/src/account.rs @@ -15,7 +15,7 @@ pub type Nonce = u128; /// Account to be used both in public and private contexts #[derive( - Serialize, Deserialize, Clone, Default, PartialEq, Eq, BorshSerialize, BorshDeserialize, + Clone, Default, Eq, PartialEq, Serialize, Deserialize, BorshSerialize, BorshDeserialize, )] #[cfg_attr(any(feature = "host", test), derive(Debug))] pub struct Account { @@ -25,7 +25,7 @@ pub struct Account { pub nonce: Nonce, } -#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] +#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)] #[cfg_attr(any(feature = "host", test), derive(Debug))] pub struct AccountWithMetadata { pub account: Account, @@ -45,6 +45,7 @@ impl AccountWithMetadata { } #[derive( + Default, Copy, Clone, Serialize, @@ -54,7 +55,6 @@ impl AccountWithMetadata { Hash, BorshSerialize, BorshDeserialize, - Default, )] #[cfg_attr(any(feature = "host", test), derive(Debug, PartialOrd, Ord))] pub struct AccountId { diff --git a/nssa/src/program.rs b/nssa/src/program.rs index 66de831..69cb02c 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -97,8 +97,6 @@ impl Program { } pub fn amm() -> Self { - // This unwrap wont panic since the `AMM_ELF` comes from risc0 build of - // `program_methods` Self::new(AMM_ELF.to_vec()).expect("The AMM program must be a valid Risc0 program") } } diff --git a/nssa/src/state.rs b/nssa/src/state.rs index 30b323f..bc0ff62 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -2285,16 +2285,15 @@ pub mod tests { // TODO: repeated code needs to be cleaned up // from token.rs (also repeated in amm.rs) - const TOKEN_DEFINITION_DATA_SIZE: usize = 23; + const TOKEN_DEFINITION_DATA_SIZE: usize = 55; - #[allow(unused)] - const TOKEN_HOLDING_TYPE: u8 = 1; const TOKEN_HOLDING_DATA_SIZE: usize = 49; struct TokenDefinition { account_type: u8, name: [u8; 6], total_supply: u128, + metadata_id: AccountId, } struct TokenHolding { @@ -2304,14 +2303,17 @@ pub mod tests { } impl TokenDefinition { fn into_data(self) -> Data { - let mut bytes = [0; TOKEN_DEFINITION_DATA_SIZE]; - bytes[0] = self.account_type; - bytes[1..7].copy_from_slice(&self.name); - bytes[7..].copy_from_slice(&self.total_supply.to_le_bytes()); - bytes - .to_vec() - .try_into() - .expect("23 bytes should fit into Data") + let mut bytes = Vec::::new(); + bytes.extend_from_slice(&[self.account_type]); + bytes.extend_from_slice(&self.name); + bytes.extend_from_slice(&self.total_supply.to_le_bytes()); + bytes.extend_from_slice(&self.metadata_id.to_bytes()); + + if bytes.len() != TOKEN_DEFINITION_DATA_SIZE { + panic!("Invalid Token Definition data"); + } + + Data::try_from(bytes).expect("Token definition data size must fit into data") } } @@ -2421,6 +2423,7 @@ pub mod tests { .expect("Hash output must be exactly 32 bytes long"), ) } + const POOL_DEFINITION_DATA_SIZE: usize = 225; #[derive(Default)] @@ -2456,672 +2459,764 @@ pub mod tests { .try_into() .expect("225 bytes should fit into Data") } + } - #[allow(unused)] - fn parse(data: &[u8]) -> Option { - if data.len() != POOL_DEFINITION_DATA_SIZE { - None - } else { - let definition_token_a_id = AccountId::new(data[0..32].try_into().expect("Parse data: The AMM program must be provided a valid AccountId for Token A definition")); - let definition_token_b_id = AccountId::new(data[32..64].try_into().expect("Parse data: The AMM program must be provided a valid AccountId for Vault B definition")); - let vault_a_id = AccountId::new(data[64..96].try_into().expect( - "Parse data: The AMM program must be provided a valid AccountId for Vault A", - )); - let vault_b_id = AccountId::new(data[96..128].try_into().expect( - "Parse data: The AMM program must be provided a valid AccountId for Vault B", - )); - let liquidity_pool_id = AccountId::new(data[128..160].try_into().expect("Parse data: The AMM program must be provided a valid AccountId for Token liquidity pool definition")); - let liquidity_pool_supply = u128::from_le_bytes(data[160..176].try_into().expect( - "Parse data: The AMM program must be provided a valid u128 for liquidity cap", - )); - let reserve_a = u128::from_le_bytes(data[176..192].try_into().expect("Parse data: The AMM program must be provided a valid u128 for reserve A balance")); - let reserve_b = u128::from_le_bytes(data[192..208].try_into().expect("Parse data: The AMM program must be provided a valid u128 for reserve B balance")); - let fees = - u128::from_le_bytes(data[208..224].try_into().expect( - "Parse data: The AMM program must be provided a valid u128 for fees", - )); + struct PrivateKeysForTests; - let active = match data[224] { - 0 => false, - 1 => true, - _ => panic!( - "Parse data: The AMM program must be provided a valid bool for active" - ), - }; + impl PrivateKeysForTests { + fn user_token_a_key() -> PrivateKey { + PrivateKey::try_new([31; 32]).expect("Keys constructor expects valid private key") + } - Some(Self { - definition_token_a_id, - definition_token_b_id, - vault_a_id, - vault_b_id, - liquidity_pool_id, - liquidity_pool_supply, - reserve_a, - reserve_b, - fees, - active, - }) - } + 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") } } - enum AccountsEnum { - UserTokenAHolding, - UserTokenBHolding, - UserTokenLPHolding, - PoolDefinitionInit, - TokenADefinitionAcc, - TokenBDefinitionAcc, - TokenLPDefinitionAcc, - VaultAInit, - VaultBInit, - VaultASwap1, - VaultBSwap1, - UserTokenAHoldingSwap1, - UserTokenBHoldingSwap1, - PoolDefinitionSwap1, - VaultASwap2, - VaultBSwap2, - UserTokenAHoldingSwap2, - UserTokenBHoldingSwap2, - PoolDefinitionSwap2, - VaultAAdd, - VaultBAdd, - UserTokenAHoldingAdd, - UserTokenBHoldingAdd, - UserTokenLPHoldingAdd, - PoolDefinitionAdd, - TokenLPDefinitionAdd, - VaultARemove, - VaultBRemove, - UserTokenAHoldingRemove, - UserTokenBHoldingRemove, - UserTokenLPHoldingRemove, - PoolDefinitionRemove, - TokenLPDefinitionRemove, - VaultAInitInactive, - VaultBInitInactive, - TokenLPDefinitionInitInactive, - PoolDefinitionInactive, - UserTokenAHoldingNewInit, - UserTokenBHoldingNewInit, - UserTokenLPHoldingNewInit, - TokenLPDefinitionNewInit, - PoolDefinitionNewInit, - UserTokenLPHoldingInitZero, - } + struct BalanceForTests; - enum BalancesEnum { - UserTokenAHoldingInit, - UserTokenBHoldingInit, - UserTokenLPHoldingInit, - VaultABalanceInit, - VaultBBalanceInit, - PoolLPSupplyInit, - TokenASupply, - TokenBSupply, - TokenLPSupply, - RemoveLP, - RemoveMinAmountA, - RemoveMinAmountB, - AddMinAmountLP, - AddMaxAmountA, - AddMaxAmountB, - SwapAmountIn, - SwapMinAmountOUt, - VaultABalanceSwap1, - VaultBBalanceSwap1, - UserTokenAHoldingSwap1, - UserTokenBHoldingSwap1, - VaultABalanceSwap2, - VaultBBalanceSwap2, - UserTokenAHoldingSwap2, - UserTokenBHoldingSwap2, - VaultABalanceAdd, - VaultBBalanceAdd, - UserTokenAHoldingAdd, - UserTokenBHoldingAdd, - UserTokenLPHoldingAdd, - TokenLPSupplyAdd, - VaultABalanceRemove, - VaultBBalanceRemove, - UserTokenAHoldingRemove, - UserTokenBHoldingRemove, - UserTokenLPHoldingRemove, - TokenLPSupplyRemove, - UserTokenAHoldingNewDef, - UserTokenBHoldingNewDef, - } + impl BalanceForTests { + fn user_token_a_holding_init() -> u128 { + 10_000 + } - #[allow(clippy::enum_variant_names)] - enum IdEnum { - PoolDefinitionId, - TokenLPDefinitionId, - TokenADefinitionId, - TokenBDefinitionId, - UserTokenAId, - UserTokenBId, - UserTokenLPId, - VaultAId, - VaultBId, - } + fn user_token_b_holding_init() -> u128 { + 10_000 + } - #[allow(clippy::enum_variant_names)] - enum PrivateKeysEnum { - UserTokenAKey, - UserTokenBKey, - UserTokenLPKey, - } + fn user_token_lp_holding_init() -> u128 { + 2_000 + } - fn helper_balances_constructor(selection: BalancesEnum) -> u128 { - match selection { - BalancesEnum::UserTokenAHoldingInit => 10_000, - BalancesEnum::UserTokenBHoldingInit => 10_000, - BalancesEnum::UserTokenLPHoldingInit => 2_000, - BalancesEnum::VaultABalanceInit => 5_000, - BalancesEnum::VaultBBalanceInit => 2_500, - BalancesEnum::PoolLPSupplyInit => 5_000, - BalancesEnum::TokenASupply => 100_000, - BalancesEnum::TokenBSupply => 100_000, - BalancesEnum::TokenLPSupply => 5_000, - BalancesEnum::RemoveLP => 1_000, - BalancesEnum::RemoveMinAmountA => 500, - BalancesEnum::RemoveMinAmountB => 500, - BalancesEnum::AddMinAmountLP => 1_000, - BalancesEnum::AddMaxAmountA => 2_000, - BalancesEnum::AddMaxAmountB => 1_000, - BalancesEnum::SwapAmountIn => 1_000, - BalancesEnum::SwapMinAmountOUt => 200, - BalancesEnum::VaultABalanceSwap1 => 3_572, - BalancesEnum::VaultBBalanceSwap1 => 3_500, - BalancesEnum::UserTokenAHoldingSwap1 => 11_428, - BalancesEnum::UserTokenBHoldingSwap1 => 9_000, - BalancesEnum::VaultABalanceSwap2 => 6_000, - BalancesEnum::VaultBBalanceSwap2 => 2_084, - BalancesEnum::UserTokenAHoldingSwap2 => 9_000, - BalancesEnum::UserTokenBHoldingSwap2 => 10_416, - BalancesEnum::VaultABalanceAdd => 7_000, - BalancesEnum::VaultBBalanceAdd => 3_500, - BalancesEnum::UserTokenAHoldingAdd => 8_000, - BalancesEnum::UserTokenBHoldingAdd => 9_000, - BalancesEnum::UserTokenLPHoldingAdd => 4_000, - BalancesEnum::TokenLPSupplyAdd => 7_000, - BalancesEnum::VaultABalanceRemove => 4_000, - BalancesEnum::VaultBBalanceRemove => 2_000, - BalancesEnum::UserTokenAHoldingRemove => 11_000, - BalancesEnum::UserTokenBHoldingRemove => 10_500, - BalancesEnum::UserTokenLPHoldingRemove => 1_000, - BalancesEnum::TokenLPSupplyRemove => 4_000, - BalancesEnum::UserTokenAHoldingNewDef => 5_000, - BalancesEnum::UserTokenBHoldingNewDef => 7_500, + 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 helper_private_keys_constructor(selection: PrivateKeysEnum) -> PrivateKey { - match selection { - PrivateKeysEnum::UserTokenAKey => { - PrivateKey::try_new([31; 32]).expect("Keys constructor expects valid private key") - } - PrivateKeysEnum::UserTokenBKey => { - PrivateKey::try_new([32; 32]).expect("Keys constructor expects valid private key") - } - PrivateKeysEnum::UserTokenLPKey => { - PrivateKey::try_new([33; 32]).expect("Keys constructor expects valid private key") - } + struct IdForTests; + + impl IdForTests { + fn pool_definition_id() -> AccountId { + compute_pool_pda( + Program::amm().id(), + IdForTests::token_a_definition_id(), + IdForTests::token_b_definition_id(), + ) + } + + fn token_lp_definition_id() -> AccountId { + compute_liquidity_token_pda(Program::amm().id(), IdForTests::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 { + compute_vault_pda( + Program::amm().id(), + IdForTests::pool_definition_id(), + IdForTests::token_a_definition_id(), + ) + } + + fn vault_b_id() -> AccountId { + compute_vault_pda( + Program::amm().id(), + IdForTests::pool_definition_id(), + IdForTests::token_b_definition_id(), + ) } } - fn helper_id_constructor(selection: IdEnum) -> AccountId { - match selection { - IdEnum::PoolDefinitionId => compute_pool_pda( - Program::amm().id(), - helper_id_constructor(IdEnum::TokenADefinitionId), - helper_id_constructor(IdEnum::TokenBDefinitionId), - ), - IdEnum::VaultAId => compute_vault_pda( - Program::amm().id(), - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_id_constructor(IdEnum::TokenADefinitionId), - ), - IdEnum::VaultBId => compute_vault_pda( - Program::amm().id(), - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_id_constructor(IdEnum::TokenBDefinitionId), - ), - IdEnum::TokenLPDefinitionId => compute_liquidity_token_pda( - Program::amm().id(), - helper_id_constructor(IdEnum::PoolDefinitionId), - ), - IdEnum::TokenADefinitionId => AccountId::new([3; 32]), - IdEnum::TokenBDefinitionId => AccountId::new([4; 32]), - IdEnum::UserTokenAId => AccountId::from(&PublicKey::new_from_private_key( - &helper_private_keys_constructor(PrivateKeysEnum::UserTokenAKey), - )), - IdEnum::UserTokenBId => AccountId::from(&PublicKey::new_from_private_key( - &helper_private_keys_constructor(PrivateKeysEnum::UserTokenBKey), - )), - IdEnum::UserTokenLPId => AccountId::from(&PublicKey::new_from_private_key( - &helper_private_keys_constructor(PrivateKeysEnum::UserTokenLPKey), - )), - } - } + struct AccountForTests; - fn helper_account_constructor(selection: AccountsEnum) -> Account { - match selection { - AccountsEnum::UserTokenAHolding => Account { + impl AccountForTests { + fn user_token_a_holding() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenAHoldingInit), + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::user_token_a_holding_init(), }), nonce: 0, - }, - AccountsEnum::UserTokenBHolding => Account { + } + } + + fn user_token_b_holding() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenBHoldingInit), + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::user_token_b_holding_init(), }), nonce: 0, - }, - AccountsEnum::PoolDefinitionInit => Account { + } + } + + fn pool_definition_init() -> Account { + Account { program_owner: Program::amm().id(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balances_constructor( - BalancesEnum::PoolLPSupplyInit, - ), - reserve_a: helper_balances_constructor(BalancesEnum::VaultABalanceInit), - reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceInit), + 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: 0u128, active: true, }), nonce: 0, - }, - AccountsEnum::TokenADefinitionAcc => Account { + } + } + + fn token_a_definition_account() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenDefinition::into_data(TokenDefinition { account_type: 0u8, name: [1u8; 6], - total_supply: helper_balances_constructor(BalancesEnum::TokenASupply), + total_supply: BalanceForTests::token_a_supply(), + metadata_id: AccountId::new([0; 32]), }), nonce: 0, - }, - AccountsEnum::TokenBDefinitionAcc => Account { + } + } + + fn token_b_definition_acc() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenDefinition::into_data(TokenDefinition { account_type: 0u8, name: [1u8; 6], - total_supply: helper_balances_constructor(BalancesEnum::TokenBSupply), + total_supply: BalanceForTests::token_b_supply(), + metadata_id: AccountId::new([0; 32]), }), nonce: 0, - }, - AccountsEnum::TokenLPDefinitionAcc => Account { + } + } + + fn token_lp_definition_acc() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenDefinition::into_data(TokenDefinition { account_type: 0u8, name: [1u8; 6], - total_supply: helper_balances_constructor(BalancesEnum::TokenLPSupply), + total_supply: BalanceForTests::token_lp_supply(), + metadata_id: AccountId::new([0; 32]), }), nonce: 0, - }, - AccountsEnum::VaultAInit => Account { + } + } + + fn vault_a_init() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balances_constructor(BalancesEnum::VaultABalanceInit), + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::vault_a_balance_init(), }), nonce: 0, - }, - AccountsEnum::VaultBInit => Account { + } + } + + fn vault_b_init() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balances_constructor(BalancesEnum::VaultBBalanceInit), + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::vault_b_balance_init(), }), nonce: 0, - }, - AccountsEnum::UserTokenLPHolding => Account { + } + } + + fn user_token_lp_holding() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenLPHoldingInit), + definition_id: IdForTests::token_lp_definition_id(), + balance: BalanceForTests::user_token_lp_holding_init(), }), nonce: 0, - }, - AccountsEnum::VaultASwap1 => Account { + } + } + + fn vault_a_swap_1() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balances_constructor(BalancesEnum::VaultABalanceSwap1), + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::vault_a_balance_swap_1(), }), nonce: 0, - }, - AccountsEnum::VaultBSwap1 => Account { + } + } + + fn vault_b_swap_1() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balances_constructor(BalancesEnum::VaultBBalanceSwap1), + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::vault_b_balance_swap_1(), }), nonce: 0, - }, - AccountsEnum::PoolDefinitionSwap1 => Account { + } + } + + fn pool_definition_swap_1() -> Account { + Account { program_owner: Program::amm().id(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balances_constructor( - BalancesEnum::PoolLPSupplyInit, - ), - reserve_a: helper_balances_constructor(BalancesEnum::VaultABalanceSwap1), - reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceSwap1), + 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: 0u128, active: true, }), nonce: 0, - }, - AccountsEnum::UserTokenAHoldingSwap1 => Account { + } + } + + fn user_token_a_holding_swap_1() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenAHoldingSwap1), + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::user_token_a_holding_swap_1(), }), nonce: 0, - }, - AccountsEnum::UserTokenBHoldingSwap1 => Account { + } + } + + fn user_token_b_holding_swap_1() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenBHoldingSwap1), + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::user_token_b_holding_swap_1(), }), nonce: 1, - }, - AccountsEnum::VaultASwap2 => Account { + } + } + + fn vault_a_swap_2() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balances_constructor(BalancesEnum::VaultABalanceSwap2), + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::vault_a_balance_swap_2(), }), nonce: 0, - }, - AccountsEnum::VaultBSwap2 => Account { + } + } + + fn vault_b_swap_2() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balances_constructor(BalancesEnum::VaultBBalanceSwap2), + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::vault_b_balance_swap_2(), }), nonce: 0, - }, - AccountsEnum::PoolDefinitionSwap2 => Account { + } + } + + fn pool_definition_swap_2() -> Account { + Account { program_owner: Program::amm().id(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balances_constructor( - BalancesEnum::PoolLPSupplyInit, - ), - reserve_a: helper_balances_constructor(BalancesEnum::VaultABalanceSwap2), - reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceSwap2), + 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: 0u128, active: true, }), nonce: 0, - }, - AccountsEnum::UserTokenAHoldingSwap2 => Account { + } + } + + fn user_token_a_holding_swap_2() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenAHoldingSwap2), + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::user_token_a_holding_swap_2(), }), nonce: 1, - }, - AccountsEnum::UserTokenBHoldingSwap2 => Account { + } + } + + fn user_token_b_holding_swap_2() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenBHoldingSwap2), + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::user_token_b_holding_swap_2(), }), nonce: 0, - }, - AccountsEnum::VaultAAdd => Account { + } + } + + fn vault_a_add() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balances_constructor(BalancesEnum::VaultABalanceAdd), + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::vault_a_balance_add(), }), nonce: 0, - }, - AccountsEnum::VaultBAdd => Account { + } + } + + fn vault_b_add() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balances_constructor(BalancesEnum::VaultBBalanceAdd), + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::vault_b_balance_add(), }), nonce: 0, - }, - AccountsEnum::PoolDefinitionAdd => Account { + } + } + + fn pool_definition_add() -> Account { + Account { program_owner: Program::amm().id(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balances_constructor( - BalancesEnum::TokenLPSupplyAdd, - ), - reserve_a: helper_balances_constructor(BalancesEnum::VaultABalanceAdd), - reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceAdd), + 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: 0u128, active: true, }), nonce: 0, - }, - AccountsEnum::UserTokenAHoldingAdd => Account { + } + } + + fn user_token_a_holding_add() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenAHoldingAdd), + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::user_token_a_holding_add(), }), nonce: 1, - }, - AccountsEnum::UserTokenBHoldingAdd => Account { + } + } + + fn user_token_b_holding_add() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenBHoldingAdd), + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::user_token_b_holding_add(), }), nonce: 1, - }, - AccountsEnum::UserTokenLPHoldingAdd => Account { + } + } + + fn user_token_lp_holding_add() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenLPHoldingAdd), + definition_id: IdForTests::token_lp_definition_id(), + balance: BalanceForTests::user_token_lp_holding_add(), }), nonce: 0, - }, - AccountsEnum::TokenLPDefinitionAdd => Account { + } + } + + fn token_lp_definition_add() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenDefinition::into_data(TokenDefinition { account_type: 0u8, name: [1u8; 6], - total_supply: helper_balances_constructor(BalancesEnum::TokenLPSupplyAdd), + total_supply: BalanceForTests::token_lp_supply_add(), + metadata_id: AccountId::new([0; 32]), }), nonce: 0, - }, - AccountsEnum::VaultARemove => Account { + } + } + + fn vault_a_remove() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balances_constructor(BalancesEnum::VaultABalanceRemove), + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::vault_a_balance_remove(), }), nonce: 0, - }, - AccountsEnum::VaultBRemove => Account { + } + } + + fn vault_b_remove() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balances_constructor(BalancesEnum::VaultBBalanceRemove), + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::vault_b_balance_remove(), }), nonce: 0, - }, - AccountsEnum::PoolDefinitionRemove => Account { + } + } + + fn pool_definition_remove() -> Account { + Account { program_owner: Program::amm().id(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balances_constructor( - BalancesEnum::TokenLPSupplyRemove, - ), - reserve_a: helper_balances_constructor(BalancesEnum::VaultABalanceRemove), - reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceRemove), + 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: 0u128, active: true, }), nonce: 0, - }, - AccountsEnum::UserTokenAHoldingRemove => Account { + } + } + + fn user_token_a_holding_remove() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenAHoldingRemove), + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::user_token_a_holding_remove(), }), nonce: 0, - }, - AccountsEnum::UserTokenBHoldingRemove => Account { + } + } + + fn user_token_b_holding_remove() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenBHoldingRemove), + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::user_token_b_holding_remove(), }), nonce: 0, - }, - AccountsEnum::UserTokenLPHoldingRemove => Account { + } + } + + fn user_token_lp_holding_remove() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenLPHoldingRemove), + definition_id: IdForTests::token_lp_definition_id(), + balance: BalanceForTests::user_token_lp_holding_remove(), }), nonce: 1, - }, - AccountsEnum::TokenLPDefinitionRemove => Account { + } + } + + fn token_lp_definition_remove() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenDefinition::into_data(TokenDefinition { account_type: 0u8, name: [1u8; 6], - total_supply: helper_balances_constructor(BalancesEnum::TokenLPSupplyRemove), + total_supply: BalanceForTests::token_lp_supply_remove(), + metadata_id: AccountId::new([0; 32]), }), nonce: 0, - }, - AccountsEnum::TokenLPDefinitionInitInactive => Account { + } + } + + fn token_lp_definition_init_inactive() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenDefinition::into_data(TokenDefinition { account_type: 0u8, name: [1u8; 6], total_supply: 0, + metadata_id: AccountId::new([0; 32]), }), nonce: 0, - }, - AccountsEnum::VaultAInitInactive => Account { + } + } + + fn vault_a_init_inactive() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), + definition_id: IdForTests::token_a_definition_id(), balance: 0, }), nonce: 0, - }, - AccountsEnum::VaultBInitInactive => Account { + } + } + + fn vault_b_init_inactive() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), + definition_id: IdForTests::token_b_definition_id(), balance: 0, }), nonce: 0, - }, - AccountsEnum::PoolDefinitionInactive => Account { + } + } + + fn pool_definition_inactive() -> Account { + Account { program_owner: Program::amm().id(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), + 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, @@ -3129,171 +3224,182 @@ pub mod tests { active: false, }), nonce: 0, - }, - AccountsEnum::UserTokenAHoldingNewInit => Account { + } + } + + fn user_token_a_holding_new_init() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenAHoldingNewDef), + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::user_token_a_holding_new_definition(), }), nonce: 1, - }, - AccountsEnum::UserTokenBHoldingNewInit => Account { + } + } + + fn user_token_b_holding_new_init() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenBHoldingNewDef), + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::user_token_b_holding_new_definition(), }), nonce: 1, - }, - AccountsEnum::UserTokenLPHoldingNewInit => Account { + } + } + + fn user_token_lp_holding_new_init() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - balance: helper_balances_constructor(BalancesEnum::UserTokenAHoldingNewDef), + definition_id: IdForTests::token_lp_definition_id(), + balance: BalanceForTests::user_token_a_holding_new_definition(), }), nonce: 0, - }, - AccountsEnum::TokenLPDefinitionNewInit => Account { + } + } + + fn token_lp_definition_new_init() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenDefinition::into_data(TokenDefinition { account_type: 0u8, name: [1u8; 6], - total_supply: helper_balances_constructor(BalancesEnum::VaultABalanceInit), + total_supply: BalanceForTests::vault_a_balance_init(), + metadata_id: AccountId::new([0; 32]), }), nonce: 0, - }, - AccountsEnum::PoolDefinitionNewInit => Account { + } + } + + fn pool_definition_new_init() -> Account { + Account { program_owner: Program::amm().id(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balances_constructor( - BalancesEnum::UserTokenAHoldingNewDef, - ), - reserve_a: helper_balances_constructor(BalancesEnum::VaultABalanceInit), - reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceInit), + 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::user_token_a_holding_new_definition(), + reserve_a: BalanceForTests::vault_a_balance_init(), + reserve_b: BalanceForTests::vault_b_balance_init(), fees: 0u128, active: true, }), nonce: 0, - }, - AccountsEnum::UserTokenLPHoldingInitZero => Account { + } + } + + fn user_token_lp_holding_init_zero() -> Account { + Account { program_owner: Program::token().id(), balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), + definition_id: IdForTests::token_lp_definition_id(), balance: 0, }), nonce: 0, - }, + } } } - fn amm_state_constructor() -> V02State { + const AMM_NEW_DEFINITION: u8 = 0; + const AMM_SWAP: u8 = 1; + const AMM_ADD_LIQUIDITY: u8 = 2; + const AMM_REMOVE_LIQUIDITY: u8 = 3; + + 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( - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_account_constructor(AccountsEnum::PoolDefinitionInit), + IdForTests::pool_definition_id(), + AccountForTests::pool_definition_init(), ); state.force_insert_account( - helper_id_constructor(IdEnum::TokenADefinitionId), - helper_account_constructor(AccountsEnum::TokenADefinitionAcc), + IdForTests::token_a_definition_id(), + AccountForTests::token_a_definition_account(), ); state.force_insert_account( - helper_id_constructor(IdEnum::TokenBDefinitionId), - helper_account_constructor(AccountsEnum::TokenBDefinitionAcc), + IdForTests::token_b_definition_id(), + AccountForTests::token_b_definition_acc(), ); state.force_insert_account( - helper_id_constructor(IdEnum::TokenLPDefinitionId), - helper_account_constructor(AccountsEnum::TokenLPDefinitionAcc), + IdForTests::token_lp_definition_id(), + AccountForTests::token_lp_definition_acc(), ); state.force_insert_account( - helper_id_constructor(IdEnum::UserTokenAId), - helper_account_constructor(AccountsEnum::UserTokenAHolding), + IdForTests::user_token_a_id(), + AccountForTests::user_token_a_holding(), ); state.force_insert_account( - helper_id_constructor(IdEnum::UserTokenBId), - helper_account_constructor(AccountsEnum::UserTokenBHolding), + IdForTests::user_token_b_id(), + AccountForTests::user_token_b_holding(), ); state.force_insert_account( - helper_id_constructor(IdEnum::UserTokenLPId), - helper_account_constructor(AccountsEnum::UserTokenLPHolding), - ); - state.force_insert_account( - helper_id_constructor(IdEnum::VaultAId), - helper_account_constructor(AccountsEnum::VaultAInit), - ); - state.force_insert_account( - helper_id_constructor(IdEnum::VaultBId), - helper_account_constructor(AccountsEnum::VaultBInit), + 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 amm_state_constructor_for_new_def() -> V02State { + 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( - helper_id_constructor(IdEnum::TokenADefinitionId), - helper_account_constructor(AccountsEnum::TokenADefinitionAcc), + IdForTests::token_a_definition_id(), + AccountForTests::token_a_definition_account(), ); state.force_insert_account( - helper_id_constructor(IdEnum::TokenBDefinitionId), - helper_account_constructor(AccountsEnum::TokenBDefinitionAcc), + IdForTests::token_b_definition_id(), + AccountForTests::token_b_definition_acc(), ); state.force_insert_account( - helper_id_constructor(IdEnum::UserTokenAId), - helper_account_constructor(AccountsEnum::UserTokenAHolding), + IdForTests::user_token_a_id(), + AccountForTests::user_token_a_holding(), ); state.force_insert_account( - helper_id_constructor(IdEnum::UserTokenBId), - helper_account_constructor(AccountsEnum::UserTokenBHolding), + IdForTests::user_token_b_id(), + AccountForTests::user_token_b_holding(), ); state } #[test] fn test_simple_amm_remove() { - let mut state = amm_state_constructor(); + let mut state = state_for_amm_tests(); let mut instruction: Vec = Vec::new(); - instruction.push(3); - instruction - .extend_from_slice(&helper_balances_constructor(BalancesEnum::RemoveLP).to_le_bytes()); - instruction.extend_from_slice( - &helper_balances_constructor(BalancesEnum::RemoveMinAmountA).to_le_bytes(), - ); - instruction.extend_from_slice( - &helper_balances_constructor(BalancesEnum::RemoveMinAmountB).to_le_bytes(), - ); + instruction.push(AMM_REMOVE_LIQUIDITY); + instruction.extend_from_slice(&BalanceForTests::remove_lp().to_le_bytes()); + instruction.extend_from_slice(&BalanceForTests::remove_min_amount_a().to_le_bytes()); + instruction.extend_from_slice(&BalanceForTests::remove_min_amount_b().to_le_bytes()); let message = public_transaction::Message::try_new( Program::amm().id(), vec![ - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_id_constructor(IdEnum::VaultAId), - helper_id_constructor(IdEnum::VaultBId), - helper_id_constructor(IdEnum::TokenLPDefinitionId), - helper_id_constructor(IdEnum::UserTokenAId), - helper_id_constructor(IdEnum::UserTokenBId), - helper_id_constructor(IdEnum::UserTokenLPId), + 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![0], instruction, @@ -3302,89 +3408,76 @@ pub mod tests { let witness_set = public_transaction::WitnessSet::for_message( &message, - &[&helper_private_keys_constructor( - PrivateKeysEnum::UserTokenLPKey, - )], + &[&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(&helper_id_constructor(IdEnum::PoolDefinitionId)); - let vault_a_post = state.get_account_by_id(&helper_id_constructor(IdEnum::VaultAId)); - let vault_b_post = state.get_account_by_id(&helper_id_constructor(IdEnum::VaultBId)); - let token_lp_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::TokenLPDefinitionId)); - let user_token_a_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenAId)); - let user_token_b_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenBId)); - let user_token_lp_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenLPId)); + 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 = helper_account_constructor(AccountsEnum::PoolDefinitionRemove); - let expected_vault_a = helper_account_constructor(AccountsEnum::VaultARemove); - let expected_vault_b = helper_account_constructor(AccountsEnum::VaultBRemove); - let expected_token_lp = helper_account_constructor(AccountsEnum::TokenLPDefinitionRemove); - let expected_user_token_a = - helper_account_constructor(AccountsEnum::UserTokenAHoldingRemove); - let expected_user_token_b = - helper_account_constructor(AccountsEnum::UserTokenBHoldingRemove); - let expected_user_token_lp = - helper_account_constructor(AccountsEnum::UserTokenLPHoldingRemove); + 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!(pool_post == expected_pool); - assert!(vault_a_post == expected_vault_a); - assert!(vault_b_post == expected_vault_b); - assert!(token_lp_post == expected_token_lp); - assert!(user_token_a_post == expected_user_token_a); - assert!(user_token_b_post == expected_user_token_b); - assert!(user_token_lp_post == expected_user_token_lp); + 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 test_simple_amm_new_definition_inactive_initialized_pool_and_uninit_user_lp() { - let mut state = amm_state_constructor_for_new_def(); + let mut state = state_for_amm_tests_with_new_def(); // Uninitialized in constructor state.force_insert_account( - helper_id_constructor(IdEnum::VaultAId), - helper_account_constructor(AccountsEnum::VaultAInitInactive), + IdForTests::vault_a_id(), + AccountForTests::vault_a_init_inactive(), ); state.force_insert_account( - helper_id_constructor(IdEnum::VaultBId), - helper_account_constructor(AccountsEnum::VaultBInitInactive), + IdForTests::vault_b_id(), + AccountForTests::vault_b_init_inactive(), ); state.force_insert_account( - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_account_constructor(AccountsEnum::PoolDefinitionInactive), + IdForTests::pool_definition_id(), + AccountForTests::pool_definition_inactive(), ); state.force_insert_account( - helper_id_constructor(IdEnum::TokenLPDefinitionId), - helper_account_constructor(AccountsEnum::TokenLPDefinitionInitInactive), + IdForTests::token_lp_definition_id(), + AccountForTests::token_lp_definition_init_inactive(), ); let mut instruction: Vec = Vec::new(); - instruction.push(0); - instruction.extend_from_slice( - &helper_balances_constructor(BalancesEnum::VaultABalanceInit).to_le_bytes(), - ); - instruction.extend_from_slice( - &helper_balances_constructor(BalancesEnum::VaultBBalanceInit).to_le_bytes(), - ); + instruction.push(AMM_NEW_DEFINITION); + instruction.extend_from_slice(&BalanceForTests::vault_a_balance_init().to_le_bytes()); + instruction.extend_from_slice(&BalanceForTests::vault_b_balance_init().to_le_bytes()); let amm_program_u8: [u8; 32] = bytemuck::cast(Program::amm().id()); instruction.extend_from_slice(&amm_program_u8); let message = public_transaction::Message::try_new( Program::amm().id(), vec![ - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_id_constructor(IdEnum::VaultAId), - helper_id_constructor(IdEnum::VaultBId), - helper_id_constructor(IdEnum::TokenLPDefinitionId), - helper_id_constructor(IdEnum::UserTokenAId), - helper_id_constructor(IdEnum::UserTokenBId), - helper_id_constructor(IdEnum::UserTokenLPId), + 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![0, 0], instruction, @@ -3394,93 +3487,82 @@ pub mod tests { let witness_set = public_transaction::WitnessSet::for_message( &message, &[ - &helper_private_keys_constructor(PrivateKeysEnum::UserTokenAKey), - &helper_private_keys_constructor(PrivateKeysEnum::UserTokenBKey), + &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(&helper_id_constructor(IdEnum::PoolDefinitionId)); - let vault_a_post = state.get_account_by_id(&helper_id_constructor(IdEnum::VaultAId)); - let vault_b_post = state.get_account_by_id(&helper_id_constructor(IdEnum::VaultBId)); - let token_lp_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::TokenLPDefinitionId)); - let user_token_a_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenAId)); - let user_token_b_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenBId)); - let user_token_lp_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenLPId)); + 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 = helper_account_constructor(AccountsEnum::PoolDefinitionNewInit); - let expected_vault_a = helper_account_constructor(AccountsEnum::VaultAInit); - let expected_vault_b = helper_account_constructor(AccountsEnum::VaultBInit); - let expected_token_lp = helper_account_constructor(AccountsEnum::TokenLPDefinitionNewInit); - let expected_user_token_a = - helper_account_constructor(AccountsEnum::UserTokenAHoldingNewInit); - let expected_user_token_b = - helper_account_constructor(AccountsEnum::UserTokenBHoldingNewInit); - let expected_user_token_lp = - helper_account_constructor(AccountsEnum::UserTokenLPHoldingNewInit); + 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!(pool_post == expected_pool); - assert!(vault_a_post == expected_vault_a); - assert!(vault_b_post == expected_vault_b); - assert!(token_lp_post == expected_token_lp); - assert!(user_token_a_post == expected_user_token_a); - assert!(user_token_b_post == expected_user_token_b); - assert!(user_token_lp_post == expected_user_token_lp); + 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 test_simple_amm_new_definition_inactive_initialized_pool_init_user_lp() { - let mut state = amm_state_constructor_for_new_def(); + let mut state = state_for_amm_tests_with_new_def(); // Uninitialized in constructor state.force_insert_account( - helper_id_constructor(IdEnum::VaultAId), - helper_account_constructor(AccountsEnum::VaultAInitInactive), + IdForTests::vault_a_id(), + AccountForTests::vault_a_init_inactive(), ); state.force_insert_account( - helper_id_constructor(IdEnum::VaultBId), - helper_account_constructor(AccountsEnum::VaultBInitInactive), + IdForTests::vault_b_id(), + AccountForTests::vault_b_init_inactive(), ); state.force_insert_account( - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_account_constructor(AccountsEnum::PoolDefinitionInactive), + IdForTests::pool_definition_id(), + AccountForTests::pool_definition_inactive(), ); state.force_insert_account( - helper_id_constructor(IdEnum::TokenLPDefinitionId), - helper_account_constructor(AccountsEnum::TokenLPDefinitionInitInactive), + IdForTests::token_lp_definition_id(), + AccountForTests::token_lp_definition_init_inactive(), ); state.force_insert_account( - helper_id_constructor(IdEnum::UserTokenLPId), - helper_account_constructor(AccountsEnum::UserTokenLPHoldingInitZero), + IdForTests::user_token_lp_id(), + AccountForTests::user_token_lp_holding_init_zero(), ); let mut instruction: Vec = Vec::new(); - instruction.push(0); - instruction.extend_from_slice( - &helper_balances_constructor(BalancesEnum::VaultABalanceInit).to_le_bytes(), - ); - instruction.extend_from_slice( - &helper_balances_constructor(BalancesEnum::VaultBBalanceInit).to_le_bytes(), - ); + instruction.push(AMM_NEW_DEFINITION); + instruction.extend_from_slice(&BalanceForTests::vault_a_balance_init().to_le_bytes()); + instruction.extend_from_slice(&BalanceForTests::vault_b_balance_init().to_le_bytes()); let amm_program_u8: [u8; 32] = bytemuck::cast(Program::amm().id()); instruction.extend_from_slice(&amm_program_u8); let message = public_transaction::Message::try_new( Program::amm().id(), vec![ - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_id_constructor(IdEnum::VaultAId), - helper_id_constructor(IdEnum::VaultBId), - helper_id_constructor(IdEnum::TokenLPDefinitionId), - helper_id_constructor(IdEnum::UserTokenAId), - helper_id_constructor(IdEnum::UserTokenBId), - helper_id_constructor(IdEnum::UserTokenLPId), + 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![0, 0], instruction, @@ -3490,81 +3572,70 @@ pub mod tests { let witness_set = public_transaction::WitnessSet::for_message( &message, &[ - &helper_private_keys_constructor(PrivateKeysEnum::UserTokenAKey), - &helper_private_keys_constructor(PrivateKeysEnum::UserTokenBKey), + &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(&helper_id_constructor(IdEnum::PoolDefinitionId)); - let vault_a_post = state.get_account_by_id(&helper_id_constructor(IdEnum::VaultAId)); - let vault_b_post = state.get_account_by_id(&helper_id_constructor(IdEnum::VaultBId)); - let token_lp_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::TokenLPDefinitionId)); - let user_token_a_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenAId)); - let user_token_b_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenBId)); - let user_token_lp_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenLPId)); + 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 = helper_account_constructor(AccountsEnum::PoolDefinitionNewInit); - let expected_vault_a = helper_account_constructor(AccountsEnum::VaultAInit); - let expected_vault_b = helper_account_constructor(AccountsEnum::VaultBInit); - let expected_token_lp = helper_account_constructor(AccountsEnum::TokenLPDefinitionNewInit); - let expected_user_token_a = - helper_account_constructor(AccountsEnum::UserTokenAHoldingNewInit); - let expected_user_token_b = - helper_account_constructor(AccountsEnum::UserTokenBHoldingNewInit); - let expected_user_token_lp = - helper_account_constructor(AccountsEnum::UserTokenLPHoldingNewInit); + let expected_pool = AccountForTests::pool_definition_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!(pool_post == expected_pool); - assert!(vault_a_post == expected_vault_a); - assert!(vault_b_post == expected_vault_b); - assert!(token_lp_post == expected_token_lp); - assert!(user_token_a_post == expected_user_token_a); - assert!(user_token_b_post == expected_user_token_b); - assert!(user_token_lp_post == expected_user_token_lp); + 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 test_simple_amm_new_definition_uninitialized_pool() { - let mut state = amm_state_constructor_for_new_def(); + let mut state = state_for_amm_tests_with_new_def(); // Uninitialized in constructor state.force_insert_account( - helper_id_constructor(IdEnum::VaultAId), - helper_account_constructor(AccountsEnum::VaultAInitInactive), + IdForTests::vault_a_id(), + AccountForTests::vault_a_init_inactive(), ); state.force_insert_account( - helper_id_constructor(IdEnum::VaultBId), - helper_account_constructor(AccountsEnum::VaultBInitInactive), + IdForTests::vault_b_id(), + AccountForTests::vault_b_init_inactive(), ); let mut instruction: Vec = Vec::new(); - instruction.push(0); - instruction.extend_from_slice( - &helper_balances_constructor(BalancesEnum::VaultABalanceInit).to_le_bytes(), - ); - instruction.extend_from_slice( - &helper_balances_constructor(BalancesEnum::VaultBBalanceInit).to_le_bytes(), - ); + instruction.push(AMM_NEW_DEFINITION); + instruction.extend_from_slice(&BalanceForTests::vault_a_balance_init().to_le_bytes()); + instruction.extend_from_slice(&BalanceForTests::vault_b_balance_init().to_le_bytes()); let amm_program_u8: [u8; 32] = bytemuck::cast(Program::amm().id()); instruction.extend_from_slice(&amm_program_u8); let message = public_transaction::Message::try_new( Program::amm().id(), vec![ - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_id_constructor(IdEnum::VaultAId), - helper_id_constructor(IdEnum::VaultBId), - helper_id_constructor(IdEnum::TokenLPDefinitionId), - helper_id_constructor(IdEnum::UserTokenAId), - helper_id_constructor(IdEnum::UserTokenBId), - helper_id_constructor(IdEnum::UserTokenLPId), + 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![0, 0], instruction, @@ -3574,72 +3645,60 @@ pub mod tests { let witness_set = public_transaction::WitnessSet::for_message( &message, &[ - &helper_private_keys_constructor(PrivateKeysEnum::UserTokenAKey), - &helper_private_keys_constructor(PrivateKeysEnum::UserTokenBKey), + &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(&helper_id_constructor(IdEnum::PoolDefinitionId)); - let vault_a_post = state.get_account_by_id(&helper_id_constructor(IdEnum::VaultAId)); - let vault_b_post = state.get_account_by_id(&helper_id_constructor(IdEnum::VaultBId)); - let token_lp_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::TokenLPDefinitionId)); - let user_token_a_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenAId)); - let user_token_b_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenBId)); - let user_token_lp_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenLPId)); + 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 = helper_account_constructor(AccountsEnum::PoolDefinitionNewInit); - let expected_vault_a = helper_account_constructor(AccountsEnum::VaultAInit); - let expected_vault_b = helper_account_constructor(AccountsEnum::VaultBInit); - let expected_token_lp = helper_account_constructor(AccountsEnum::TokenLPDefinitionNewInit); - let expected_user_token_a = - helper_account_constructor(AccountsEnum::UserTokenAHoldingNewInit); - let expected_user_token_b = - helper_account_constructor(AccountsEnum::UserTokenBHoldingNewInit); - let expected_user_token_lp = - helper_account_constructor(AccountsEnum::UserTokenLPHoldingNewInit); + 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!(pool_post == expected_pool); - assert!(vault_a_post == expected_vault_a); - assert!(vault_b_post == expected_vault_b); - assert!(token_lp_post == expected_token_lp); - assert!(user_token_a_post == expected_user_token_a); - assert!(user_token_b_post == expected_user_token_b); - assert!(user_token_lp_post == expected_user_token_lp); + 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 test_simple_amm_add() { - let mut state = amm_state_constructor(); + env_logger::init(); + let mut state = state_for_amm_tests(); let mut instruction: Vec = Vec::new(); - instruction.push(2); - instruction.extend_from_slice( - &helper_balances_constructor(BalancesEnum::AddMinAmountLP).to_le_bytes(), - ); - instruction.extend_from_slice( - &helper_balances_constructor(BalancesEnum::AddMaxAmountA).to_le_bytes(), - ); - instruction.extend_from_slice( - &helper_balances_constructor(BalancesEnum::AddMaxAmountB).to_le_bytes(), - ); + instruction.push(AMM_ADD_LIQUIDITY); + instruction.extend_from_slice(&BalanceForTests::add_min_amount_lp().to_le_bytes()); + instruction.extend_from_slice(&BalanceForTests::add_max_amount_a().to_le_bytes()); + instruction.extend_from_slice(&BalanceForTests::add_max_amount_b().to_le_bytes()); let message = public_transaction::Message::try_new( Program::amm().id(), vec![ - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_id_constructor(IdEnum::VaultAId), - helper_id_constructor(IdEnum::VaultBId), - helper_id_constructor(IdEnum::TokenLPDefinitionId), - helper_id_constructor(IdEnum::UserTokenAId), - helper_id_constructor(IdEnum::UserTokenBId), - helper_id_constructor(IdEnum::UserTokenLPId), + 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![0, 0], instruction, @@ -3649,67 +3708,57 @@ pub mod tests { let witness_set = public_transaction::WitnessSet::for_message( &message, &[ - &helper_private_keys_constructor(PrivateKeysEnum::UserTokenAKey), - &helper_private_keys_constructor(PrivateKeysEnum::UserTokenBKey), + &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(&helper_id_constructor(IdEnum::PoolDefinitionId)); - let vault_a_post = state.get_account_by_id(&helper_id_constructor(IdEnum::VaultAId)); - let vault_b_post = state.get_account_by_id(&helper_id_constructor(IdEnum::VaultBId)); - let token_lp_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::TokenLPDefinitionId)); - let user_token_a_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenAId)); - let user_token_b_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenBId)); - let user_token_lp_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenLPId)); + 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 = helper_account_constructor(AccountsEnum::PoolDefinitionAdd); - let expected_vault_a = helper_account_constructor(AccountsEnum::VaultAAdd); - let expected_vault_b = helper_account_constructor(AccountsEnum::VaultBAdd); - let expected_token_lp = helper_account_constructor(AccountsEnum::TokenLPDefinitionAdd); - let expected_user_token_a = helper_account_constructor(AccountsEnum::UserTokenAHoldingAdd); - let expected_user_token_b = helper_account_constructor(AccountsEnum::UserTokenBHoldingAdd); - let expected_user_token_lp = - helper_account_constructor(AccountsEnum::UserTokenLPHoldingAdd); + 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!(pool_post == expected_pool); - assert!(vault_a_post == expected_vault_a); - assert!(vault_b_post == expected_vault_b); - assert!(token_lp_post == expected_token_lp); - assert!(user_token_a_post == expected_user_token_a); - assert!(user_token_b_post == expected_user_token_b); - assert!(user_token_lp_post == expected_user_token_lp); + 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 test_simple_amm_swap_1() { - let mut state = amm_state_constructor(); + let mut state = state_for_amm_tests(); let mut instruction: Vec = Vec::new(); - instruction.push(1); - instruction.extend_from_slice( - &helper_balances_constructor(BalancesEnum::SwapAmountIn).to_le_bytes(), - ); - instruction.extend_from_slice( - &helper_balances_constructor(BalancesEnum::SwapMinAmountOUt).to_le_bytes(), - ); - instruction - .extend_from_slice(&helper_id_constructor(IdEnum::TokenBDefinitionId).to_bytes()); + instruction.push(AMM_SWAP); + instruction.extend_from_slice(&BalanceForTests::swap_amount_in().to_le_bytes()); + instruction.extend_from_slice(&BalanceForTests::swap_min_amount_out().to_le_bytes()); + instruction.extend_from_slice(&IdForTests::token_b_definition_id().to_bytes()); let message = public_transaction::Message::try_new( Program::amm().id(), vec![ - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_id_constructor(IdEnum::VaultAId), - helper_id_constructor(IdEnum::VaultBId), - helper_id_constructor(IdEnum::UserTokenAId), - helper_id_constructor(IdEnum::UserTokenBId), + IdForTests::pool_definition_id(), + IdForTests::vault_a_id(), + IdForTests::vault_b_id(), + IdForTests::user_token_a_id(), + IdForTests::user_token_b_id(), ], vec![0], instruction, @@ -3718,60 +3767,49 @@ pub mod tests { let witness_set = public_transaction::WitnessSet::for_message( &message, - &[&helper_private_keys_constructor( - PrivateKeysEnum::UserTokenBKey, - )], + &[&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(&helper_id_constructor(IdEnum::PoolDefinitionId)); - let vault_a_post = state.get_account_by_id(&helper_id_constructor(IdEnum::VaultAId)); - let vault_b_post = state.get_account_by_id(&helper_id_constructor(IdEnum::VaultBId)); - let user_token_a_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenAId)); - let user_token_b_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenBId)); + 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 = helper_account_constructor(AccountsEnum::PoolDefinitionSwap1); - let expected_vault_a = helper_account_constructor(AccountsEnum::VaultASwap1); - let expected_vault_b = helper_account_constructor(AccountsEnum::VaultBSwap1); - let expected_user_token_a = - helper_account_constructor(AccountsEnum::UserTokenAHoldingSwap1); - let expected_user_token_b = - helper_account_constructor(AccountsEnum::UserTokenBHoldingSwap1); + 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!(pool_post == expected_pool); - assert!(vault_a_post == expected_vault_a); - assert!(vault_b_post == expected_vault_b); - assert!(user_token_a_post == expected_user_token_a); - assert!(user_token_b_post == expected_user_token_b); + 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 test_simple_amm_swap_2() { - let mut state = amm_state_constructor(); + let mut state = state_for_amm_tests(); let mut instruction: Vec = Vec::new(); - instruction.push(1); - instruction.extend_from_slice( - &helper_balances_constructor(BalancesEnum::SwapAmountIn).to_le_bytes(), - ); - instruction.extend_from_slice( - &helper_balances_constructor(BalancesEnum::SwapMinAmountOUt).to_le_bytes(), - ); - instruction - .extend_from_slice(&helper_id_constructor(IdEnum::TokenADefinitionId).to_bytes()); + instruction.push(AMM_SWAP); + instruction.extend_from_slice(&BalanceForTests::swap_amount_in().to_le_bytes()); + instruction.extend_from_slice(&BalanceForTests::swap_min_amount_out().to_le_bytes()); + instruction.extend_from_slice(&IdForTests::token_a_definition_id().to_bytes()); let message = public_transaction::Message::try_new( Program::amm().id(), vec![ - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_id_constructor(IdEnum::VaultAId), - helper_id_constructor(IdEnum::VaultBId), - helper_id_constructor(IdEnum::UserTokenAId), - helper_id_constructor(IdEnum::UserTokenBId), + IdForTests::pool_definition_id(), + IdForTests::vault_a_id(), + IdForTests::vault_b_id(), + IdForTests::user_token_a_id(), + IdForTests::user_token_b_id(), ], vec![0], instruction, @@ -3780,35 +3818,29 @@ pub mod tests { let witness_set = public_transaction::WitnessSet::for_message( &message, - &[&helper_private_keys_constructor( - PrivateKeysEnum::UserTokenAKey, - )], + &[&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(&helper_id_constructor(IdEnum::PoolDefinitionId)); - let vault_a_post = state.get_account_by_id(&helper_id_constructor(IdEnum::VaultAId)); - let vault_b_post = state.get_account_by_id(&helper_id_constructor(IdEnum::VaultBId)); - let user_token_a_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenAId)); - let user_token_b_post = - state.get_account_by_id(&helper_id_constructor(IdEnum::UserTokenBId)); + 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 = helper_account_constructor(AccountsEnum::PoolDefinitionSwap2); - let expected_vault_a = helper_account_constructor(AccountsEnum::VaultASwap2); - let expected_vault_b = helper_account_constructor(AccountsEnum::VaultBSwap2); - let expected_user_token_a = - helper_account_constructor(AccountsEnum::UserTokenAHoldingSwap2); - let expected_user_token_b = - helper_account_constructor(AccountsEnum::UserTokenBHoldingSwap2); + 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!(pool_post == expected_pool); - assert!(vault_a_post == expected_vault_a); - assert!(vault_b_post == expected_vault_b); - assert!(user_token_a_post == expected_user_token_a); - assert!(user_token_b_post == expected_user_token_b); + 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] @@ -4054,7 +4086,7 @@ pub mod tests { // definition and supply accounts let total_supply: u128 = 10_000_000; // instruction: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)] - let mut instruction: [u8; 23] = [0; 23]; + let mut instruction = vec![0; 23]; instruction[1..17].copy_from_slice(&total_supply.to_le_bytes()); instruction[17..].copy_from_slice(b"PINATA"); let message = public_transaction::Message::try_new( @@ -4069,7 +4101,7 @@ pub mod tests { state.transition_from_public_transaction(&tx).unwrap(); // Execution of the token program transfer just to initialize the winner token account - let mut instruction: [u8; 23] = [0; 23]; + let mut instruction = vec![0; 23]; instruction[0] = 2; let message = public_transaction::Message::try_new( token.id(), @@ -4194,8 +4226,8 @@ pub mod tests { this }; - assert!(expected_sender_post == sender_post); - assert!(expected_recipient_post == recipient_post); + assert_eq!(expected_sender_post, sender_post); + assert_eq!(expected_recipient_post, recipient_post); } #[test] diff --git a/program_methods/guest/src/bin/amm.rs b/program_methods/guest/src/bin/amm.rs index 68b593f..9488db1 100644 --- a/program_methods/guest/src/bin/amm.rs +++ b/program_methods/guest/src/bin/amm.rs @@ -8,61 +8,63 @@ use nssa_core::{ // The AMM program has five functions (four directly accessible via instructions): // 1. New AMM definition. Arguments to this function are: -// * Seven **default** accounts: [amm_pool, vault_holding_a, vault_holding_b, pool_lp, -// user_holding_a, user_holding_b, user_holding_lp]. amm_pool is a default account that will -// initiate the amm definition account values vault_holding_a is a token holding account for -// token a vault_holding_b is a token holding account for token b pool_lp is a token holding -// account for the pool's lp token user_holding_a is a token holding account for token a -// user_holding_b is a token holding account for token b user_holding_lp is a token holding -// account for lp token +// * Seven accounts: [amm_pool, vault_holding_a, vault_holding_b, pool_lp, user_holding_a, +// user_holding_b, user_holding_lp]. For new AMM Pool: amm_pool, vault_holding_a, +// vault_holding_b, pool_lp and user_holding_lp are default accounts. amm_pool is a default +// account that will initiate the amm definition account values vault_holding_a is a token +// holding account for token a vault_holding_b is a token holding account for token b pool_lp +// is a token holding account for the pool's lp token user_holding_a is a token holding +// account for token a user_holding_b is a token holding account for token b user_holding_lp +// is a token holding account for lp token +// * PDA remark: Accounts amm_pool, vault_holding_a, vault_holding_b and pool_lp are PDA. The +// AccountId for these accounts must be computed using: amm_pool AccountId <- +// compute_pool_pda vault_holding_a, vault_holding_b <- compute_vault_pda pool_lp +// <-compute_liquidity_token_pda // * Requires authorization: user_holding_a, user_holding_b // * 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) || AMM_PROGRAM_ID)] +// * Internally, calls compute_liquidity_token_pda_seed, compute_vault_pda_seed to authorize +// transfers. +// * Internally, calls compute_pool_da, compute_vault_pda and compute_vault_pda to check +// various AccountIds are correct. // 2. Swap assets Arguments to this function are: -// * Five accounts: [amm_pool, vault_holding_1, vault_holding_2, user_holding_a, +// * Five accounts: [amm_pool, vault_holding_a, vault_holding_b, user_holding_a, // user_holding_b]. // * Requires authorization: user holding account associated to TOKEN_DEFINITION_ID (either // user_holding_a or user_holding_b) -// * An instruction data byte string of length 49, indicating which token type to swap, +// * 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]. +// * Internally, calls swap logic. +// * Four accounts: [user_deposit, vault_deposit, vault_withdraw, user_withdraw]. +// user_deposit and vault_deposit define deposit transaction. vault_withdraw and +// user_withdraw define withdraw transaction. +// * deposit_amount is the amount for user_deposit -> vault_deposit transfer. +// * reserve_amounts is the pool's reserves; used to compute the withdraw amount. +// * Outputs the token transfers as a Vec and the withdraw amount. // 3. Add liquidity Arguments to this function are: // * Seven accounts: [amm_pool, vault_holding_a, vault_holding_b, pool_lp, user_holding_a, -// UserHouser_holding_a, user_holding_lp]. +// user_holding_a, user_holding_lp]. // * Requires authorization: user_holding_a, user_holding_b // * 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)]. +// * Internally, calls compute_liquidity_token_pda_seed to compute liquidity pool PDA seed. // 4. Remove liquidity // * Seven accounts: [amm_pool, vault_holding_a, vault_holding_b, pool_lp, user_holding_a, -// UserHouser_holding_a, user_holding_lp]. +// user_holding_a, user_holding_lp]. // * Requires authorization: user_holding_lp // * 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)]. -// - Internal functions: -// - Swap logic Arguments of this function are: -// * Four accounts: [user_deposit_tx, vault_deposit_tx, vault_withdraw_tx, user_withdraw_tx]. -// user_deposit_tx and vault_deposit_tx define deposit transaction. vault_withdraw_tx and -// user_withdraw_tx define withdraw transaction. -// * deposit_amount is the amount for user_deposit_tx -> vault_deposit_tx transfer. -// * reserve_amounts is the pool's reserves; used to compute the withdraw amount. -// * Outputs the token transfers as a Vec and the withdraw amount. -// - PDA computations: -// * compute_pool_pda: AMM_PROGRAM_ID, token definitions for the pool pair -// * compute_vault_pda: AMM_PROGRAM_ID, pool definition id, definition token id -// * compute_liquidity_token_pda: AMM_PROGRAM, pool definition id, pool definition id -// - PDA seed computations: -// * compute_pool_pda_seed: token definitions for the pool pair -// * compute_vault_pda_seed: pool definition id, definition token id, -// * compute_liquidity_token_pda_seed: pool definition id +// * Internally, calls compute_vault_pda_seed to compute vault_a and vault_b's PDA seed. const POOL_DEFINITION_DATA_SIZE: usize = 225; -#[derive(Default)] +#[derive(Clone, Default)] struct PoolDefinition { definition_token_a_id: AccountId, definition_token_b_id: AccountId, @@ -72,7 +74,11 @@ struct PoolDefinition { liquidity_pool_supply: u128, reserve_a: u128, reserve_b: u128, + /// Fees are currently not used fees: u128, + /// A pool becomes inactive (active = false) + /// once all of its liquidity has been removed (e.g., reserves are emptied and + /// liquidity_pool_supply = 0) active: bool, } @@ -147,65 +153,18 @@ impl PoolDefinition { } // TODO: remove repeated code for Token_Definition and TokenHoldling -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 { - account_type: u8, - name: [u8; 6], - total_supply: u128, -} - struct TokenHolding { + #[cfg_attr(not(test), expect(dead_code, reason = "TODO: fix later"))] account_type: u8, definition_id: AccountId, balance: u128, } -impl TokenDefinition { - fn into_data(self) -> Data { - let mut bytes = [0; TOKEN_DEFINITION_DATA_SIZE]; - bytes[0] = self.account_type; - bytes[1..7].copy_from_slice(&self.name); - bytes[7..].copy_from_slice(&self.total_supply.to_le_bytes()); - bytes - .to_vec() - .try_into() - .expect("23 bytes should fit into Data") - } - - 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() - .expect("Total supply must be 16 bytes little-endian"), - ); - Some(Self { - account_type, - name, - total_supply, - }) - } - } -} - impl TokenHolding { - fn new(definition_id: &AccountId) -> Self { - Self { - account_type: TOKEN_HOLDING_TYPE, - definition_id: definition_id.clone(), - balance: 0, - } - } - fn parse(data: &[u8]) -> Option { if data.len() != TOKEN_HOLDING_DATA_SIZE || data[0] != TOKEN_HOLDING_TYPE { None @@ -229,6 +188,7 @@ impl TokenHolding { } } + #[cfg(test)] fn into_data(self) -> Data { let mut bytes = [0; TOKEN_HOLDING_DATA_SIZE]; bytes[0] = self.account_type; @@ -386,23 +346,13 @@ fn compute_pool_pda_seed( ) -> 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.clone(); - let token_2 = definition_token_b_id.clone(); - 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.clone(); - let token_2 = definition_token_a_id.clone(); - break (token_1, token_2); - } - - if i == 32 { - panic!("Definitions match"); - } else { - i += 1; - } + let (token_1, token_2) = match definition_token_a_id + .value() + .cmp(definition_token_b_id.value()) + { + std::cmp::Ordering::Less => (definition_token_b_id, definition_token_a_id), + std::cmp::Ordering::Greater => (definition_token_a_id, definition_token_b_id), + std::cmp::Ordering::Equal => panic!("Definitions match"), }; let mut bytes = [0; 64]; @@ -462,6 +412,32 @@ fn compute_liquidity_token_pda_seed(pool_id: AccountId) -> PdaSeed { ) } +const TOKEN_PROGRAM_NEW: u8 = 0; +const TOKEN_PROGRAM_TRANSFER: u8 = 1; +const TOKEN_PROGRAM_MINT: u8 = 4; +const TOKEN_PROGRAM_BURN: u8 = 3; + +fn initialize_token_transfer_chained_call( + token_program_command: u8, + sender: AccountWithMetadata, + recipient: AccountWithMetadata, + amount_to_move: u128, + pda_seed: Vec, +) -> ChainedCall { + let mut instruction_data = vec![0u8; 23]; + instruction_data[0] = token_program_command; + instruction_data[1..17].copy_from_slice(&amount_to_move.to_le_bytes()); + let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) + .expect("AMM Program expects valid token transfer instruction data"); + + ChainedCall { + program_id: sender.account.program_owner, + instruction_data, + pre_states: vec![sender, recipient], + pda_seeds: pda_seed, + } +} + fn new_definition( pre_states: &[AccountWithMetadata], balance_in: &[u128], @@ -505,39 +481,29 @@ fn new_definition( // both instances of the same token program let token_program = user_holding_a.account.program_owner; + if user_holding_b.account.program_owner != token_program { + panic!("User Token holdings must use the same Token Program"); + } + if definition_token_a_id == definition_token_b_id { panic!("Cannot set up a swap for a token with itself") } if pool.account_id - != compute_pool_pda( - amm_program_id.clone(), - definition_token_a_id.clone(), - definition_token_b_id.clone(), - ) + != compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id) { panic!("Pool Definition Account ID does not match PDA"); } if vault_a.account_id - != compute_vault_pda( - amm_program_id.clone(), - pool.account_id.clone(), - definition_token_a_id.clone(), - ) + != compute_vault_pda(amm_program_id, pool.account_id, definition_token_a_id) || vault_b.account_id - != compute_vault_pda( - amm_program_id.clone(), - pool.account_id.clone(), - definition_token_b_id.clone(), - ) + != compute_vault_pda(amm_program_id, pool.account_id, definition_token_b_id) { panic!("Vault ID does not match PDA"); } - if pool_lp.account_id - != compute_liquidity_token_pda(amm_program_id.clone(), pool.account_id.clone()) - { + if pool_lp.account_id != compute_liquidity_token_pda(amm_program_id, pool.account_id) { panic!("Liquidity pool Token Definition Account ID does not match PDA"); } @@ -552,28 +518,25 @@ fn new_definition( panic!("Cannot initialize an active Pool Definition") } - // 3. LP Token minting calculation + // LP Token minting calculation // We assume LP is based on the initial deposit amount for Token_A. - // 5. Update pool account + // Update pool account let mut pool_post = pool.account.clone(); let pool_post_definition = PoolDefinition { definition_token_a_id, definition_token_b_id, - vault_a_id: vault_a.account_id.clone(), - vault_b_id: vault_b.account_id.clone(), - liquidity_pool_id: pool_lp.account_id.clone(), - liquidity_pool_supply: amount_a.clone(), - reserve_a: amount_a.clone(), - reserve_b: amount_b.clone(), + vault_a_id: vault_a.account_id, + vault_b_id: vault_b.account_id, + liquidity_pool_id: pool_lp.account_id, + liquidity_pool_supply: amount_a, + reserve_a: amount_a, + reserve_b: amount_b, fees: 0u128, // TODO: we assume all fees are 0 for now. active: true, }; - pool_post.data = pool_post_definition - .into_data() - .try_into() - .expect("Data too big"); + pool_post.data = pool_post_definition.into_data(); let pool_post: AccountPostState = if pool.account == Account::default() { AccountPostState::new_claimed(pool_post.clone()) } else { @@ -583,38 +546,28 @@ fn new_definition( let mut chained_calls = Vec::::new(); // Chain call for Token A (user_holding_a -> Vault_A) - let mut instruction_data = [0; 23]; - instruction_data[0] = 1; - instruction_data[1..17].copy_from_slice(&amount_a.to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) - .expect("New definition: AMM Program expects valid token transfer instruction data"); - let call_token_a = ChainedCall { - program_id: user_holding_a.account.program_owner, - instruction_data, - pre_states: vec![user_holding_a.clone(), vault_a.clone()], - pda_seeds: Vec::::new(), - }; - + let call_token_a = initialize_token_transfer_chained_call( + TOKEN_PROGRAM_TRANSFER, + user_holding_a.clone(), + vault_a.clone(), + amount_a, + Vec::::new(), + ); // Chain call for Token B (user_holding_b -> Vault_B) - let mut instruction_data = [0; 23]; - instruction_data[0] = 1; - instruction_data[1..17].copy_from_slice(&amount_b.to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) - .expect("New definition: AMM Program expects valid instruction_data"); - - let call_token_b = ChainedCall { - program_id: user_holding_b.account.program_owner, - instruction_data, - pre_states: vec![user_holding_b.clone(), vault_b.clone()], - pda_seeds: Vec::::new(), - }; + let call_token_b = initialize_token_transfer_chained_call( + TOKEN_PROGRAM_TRANSFER, + user_holding_b.clone(), + vault_b.clone(), + amount_b, + Vec::::new(), + ); // Chain call for liquidity token (TokenLP definition -> User LP Holding) - let mut instruction_data = [0; 23]; + let mut instruction_data = vec![0u8; 23]; instruction_data[0] = if pool.account == Account::default() { - 0 + TOKEN_PROGRAM_NEW } else { - 4 + TOKEN_PROGRAM_MINT }; //new or mint let nme = if pool.account == Account::default() { [1u8; 6] @@ -635,7 +588,7 @@ fn new_definition( program_id: token_program_id, instruction_data, pre_states: vec![pool_lp_auth.clone(), user_holding_lp.clone()], - pda_seeds: vec![compute_liquidity_token_pda_seed(pool.account_id.clone())], + pda_seeds: vec![compute_liquidity_token_pda_seed(pool.account_id)], }; chained_calls.push(call_token_lp); @@ -668,9 +621,6 @@ fn swap( panic!("Invalid number of amounts provided"); } - let amount_in = amounts[0]; - let min_amount_out = amounts[1]; - let pool = &pre_states[0]; let vault_a = &pre_states[1]; let vault_b = &pre_states[2]; @@ -712,33 +662,31 @@ fn swap( let (chained_calls, [deposit_a, withdraw_a], [deposit_b, withdraw_b]) = if token_in_id == pool_def_data.definition_token_a_id { - let (chained_calls, withdraw_b) = swap_logic( - &[ - user_holding_a.clone(), - vault_a.clone(), - vault_b.clone(), - user_holding_b.clone(), - ], - &[amount_in, min_amount_out], + let (chained_calls, deposit_a, withdraw_b) = swap_logic( + user_holding_a.clone(), + vault_a.clone(), + vault_b.clone(), + user_holding_b.clone(), + amounts[0], + amounts[1], &[pool_def_data.reserve_a, pool_def_data.reserve_b], - pool.account_id.clone(), + pool.account_id, ); - (chained_calls, [amount_in, 0], [0, withdraw_b]) + (chained_calls, [deposit_a, 0], [0, withdraw_b]) } else if token_in_id == pool_def_data.definition_token_b_id { - let (chained_calls, withdraw_a) = swap_logic( - &[ - user_holding_b.clone(), - vault_b.clone(), - vault_a.clone(), - user_holding_a.clone(), - ], - &[amount_in, min_amount_out], + let (chained_calls, deposit_b, withdraw_a) = swap_logic( + user_holding_b.clone(), + vault_b.clone(), + vault_a.clone(), + user_holding_a.clone(), + amounts[0], + amounts[1], &[pool_def_data.reserve_b, pool_def_data.reserve_a], - pool.account_id.clone(), + pool.account_id, ); - (chained_calls, [0, withdraw_a], [amount_in, 0]) + (chained_calls, [0, withdraw_a], [deposit_b, 0]) } else { panic!("AccountId is not a token type for the pool"); }; @@ -746,22 +694,12 @@ fn swap( // Update pool account let mut pool_post = pool.account.clone(); let pool_post_definition = PoolDefinition { - definition_token_a_id: pool_def_data.definition_token_a_id.clone(), - definition_token_b_id: pool_def_data.definition_token_b_id.clone(), - vault_a_id: pool_def_data.vault_a_id.clone(), - vault_b_id: pool_def_data.vault_b_id.clone(), - liquidity_pool_id: pool_def_data.liquidity_pool_id.clone(), - liquidity_pool_supply: pool_def_data.liquidity_pool_supply.clone(), reserve_a: pool_def_data.reserve_a + deposit_a - withdraw_a, reserve_b: pool_def_data.reserve_b + deposit_b - withdraw_b, - fees: 0u128, - active: true, + ..pool_def_data }; - pool_post.data = pool_post_definition - .into_data() - .try_into() - .expect("Data too big"); + pool_post.data = pool_post_definition.into_data(); let post_states = vec![ AccountPostState::new(pool_post.clone()), @@ -774,26 +712,23 @@ fn swap( (post_states, chained_calls) } +#[expect(clippy::too_many_arguments, reason = "TODO: Fix later")] fn swap_logic( - pre_states: &[AccountWithMetadata], - balances: &[u128], + user_deposit: AccountWithMetadata, + vault_deposit: AccountWithMetadata, + vault_withdraw: AccountWithMetadata, + user_withdraw: AccountWithMetadata, + deposit_amount: u128, + min_amount_out: u128, reserve_amounts: &[u128], pool_id: AccountId, -) -> (Vec, u128) { - let user_deposit_tx = pre_states[0].clone(); - let vault_deposit_tx = pre_states[1].clone(); - let vault_withdraw_tx = pre_states[2].clone(); - let user_withdraw_tx = pre_states[3].clone(); - +) -> (Vec, u128, u128) { let reserve_deposit_vault_amount = reserve_amounts[0]; let reserve_withdraw_vault_amount = reserve_amounts[1]; - let deposit_amount = balances[0]; - let min_amount_out = balances[1]; - // Compute withdraw amount - // Compute pool's exchange constant - // let k = pool_def_data.reserve_a * pool_def_data.reserve_b; + // Maintains pool constant product + // k = pool_def_data.reserve_a * pool_def_data.reserve_b; let withdraw_amount = (reserve_withdraw_vault_amount * deposit_amount) / (reserve_deposit_vault_amount + deposit_amount); @@ -807,39 +742,31 @@ fn swap_logic( } let mut chained_calls = Vec::new(); - let mut instruction_data = [0; 23]; - instruction_data[0] = 1; - instruction_data[1..17].copy_from_slice(&deposit_amount.to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) - .expect("Swap Logic: AMM Program expects valid transaction instruction data"); - chained_calls.push(ChainedCall { - program_id: vault_deposit_tx.account.program_owner, - instruction_data, - pre_states: vec![user_deposit_tx.clone(), vault_deposit_tx.clone()], - pda_seeds: Vec::::new(), - }); + chained_calls.push(initialize_token_transfer_chained_call( + TOKEN_PROGRAM_TRANSFER, + user_deposit.clone(), + vault_deposit.clone(), + deposit_amount, + Vec::::new(), + )); - let mut vault_withdraw_tx = vault_withdraw_tx.clone(); - vault_withdraw_tx.is_authorized = true; + let mut vault_withdraw = vault_withdraw.clone(); + vault_withdraw.is_authorized = true; - let mut instruction_data = [0; 23]; - instruction_data[0] = 1; - instruction_data[1..17].copy_from_slice(&withdraw_amount.to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) - .expect("Swap Logic: AMM Program expects valid transaction instruction data"); - chained_calls.push(ChainedCall { - program_id: vault_deposit_tx.account.program_owner, - instruction_data, - pre_states: vec![vault_withdraw_tx.clone(), user_withdraw_tx.clone()], - pda_seeds: vec![compute_vault_pda_seed( + chained_calls.push(initialize_token_transfer_chained_call( + TOKEN_PROGRAM_TRANSFER, + vault_withdraw.clone(), + user_withdraw.clone(), + withdraw_amount, + vec![compute_vault_pda_seed( pool_id, - TokenHolding::parse(&vault_withdraw_tx.account.data) + TokenHolding::parse(&vault_withdraw.account.data) .expect("Swap Logic: AMM Program expects valid token data") .definition_id, )], - }); + )); - (chained_calls, withdraw_amount) + (chained_calls, deposit_amount, withdraw_amount) } fn add_liquidity( @@ -858,7 +785,7 @@ fn add_liquidity( let user_holding_b = &pre_states[5]; let user_holding_lp = &pre_states[6]; - // Verify vaults are in fact vaults + // 1. Fetch Pool state let pool_def_data = PoolDefinition::parse(&pool.account.data) .expect("Add liquidity: AMM Program expects valid Pool Definition Account"); if vault_a.account_id != pool_def_data.vault_a_id { @@ -945,65 +872,41 @@ fn add_liquidity( // 5. Update pool account let mut pool_post = pool.account.clone(); let pool_post_definition = PoolDefinition { - definition_token_a_id: pool_def_data.definition_token_a_id.clone(), - definition_token_b_id: pool_def_data.definition_token_b_id.clone(), - vault_a_id: pool_def_data.vault_a_id.clone(), - vault_b_id: pool_def_data.vault_b_id.clone(), - liquidity_pool_id: pool_def_data.liquidity_pool_id.clone(), liquidity_pool_supply: pool_def_data.liquidity_pool_supply + delta_lp, reserve_a: pool_def_data.reserve_a + actual_amount_a, reserve_b: pool_def_data.reserve_b + actual_amount_b, - fees: 0u128, - active: true, + ..pool_def_data }; - pool_post.data = pool_post_definition - .into_data() - .try_into() - .expect("Data too big"); + pool_post.data = pool_post_definition.into_data(); let mut chained_call = Vec::new(); // Chain call for Token A (UserHoldingA -> Vault_A) - let mut instruction_data = [0; 23]; - instruction_data[0] = 1; - instruction_data[1..17].copy_from_slice(&actual_amount_a.to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) - .expect("Add liquidity: AMM Program expects valid token transfer instruction data"); - let call_token_a = ChainedCall { - program_id: vault_a.account.program_owner, - instruction_data, - pre_states: vec![user_holding_a.clone(), vault_a.clone()], - pda_seeds: Vec::::new(), - }; - + let call_token_a = initialize_token_transfer_chained_call( + TOKEN_PROGRAM_TRANSFER, + user_holding_a.clone(), + vault_a.clone(), + actual_amount_a, + Vec::::new(), + ); // Chain call for Token B (UserHoldingB -> Vault_B) - let mut instruction_data = [0; 23]; - instruction_data[0] = 1; - instruction_data[1..17].copy_from_slice(&actual_amount_b.to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) - .expect("Add liquidity: AMM Program expects valid token transfer instruction data"); - let call_token_b = ChainedCall { - program_id: vault_b.account.program_owner, - instruction_data, - pre_states: vec![user_holding_b.clone(), vault_b.clone()], - pda_seeds: Vec::::new(), - }; - + let call_token_b = initialize_token_transfer_chained_call( + TOKEN_PROGRAM_TRANSFER, + user_holding_b.clone(), + vault_b.clone(), + actual_amount_b, + Vec::::new(), + ); // Chain call for LP (mint new tokens for user_holding_lp) let mut pool_definition_lp_auth = pool_definition_lp.clone(); pool_definition_lp_auth.is_authorized = true; - - let mut instruction_data = [0; 23]; - instruction_data[0] = 4; - instruction_data[1..17].copy_from_slice(&delta_lp.to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) - .expect("Add liquidity: AMM Program expects valid token transfer instruction data"); - let call_token_lp = ChainedCall { - program_id: pool_definition_lp.account.program_owner, - instruction_data, - pre_states: vec![pool_definition_lp_auth.clone(), user_holding_lp.clone()], - pda_seeds: vec![compute_liquidity_token_pda_seed(pool.account_id.clone())], - }; + let call_token_lp = initialize_token_transfer_chained_call( + TOKEN_PROGRAM_MINT, + pool_definition_lp_auth.clone(), + user_holding_lp.clone(), + delta_lp, + vec![compute_liquidity_token_pda_seed(pool.account_id)], + ); chained_call.push(call_token_lp); chained_call.push(call_token_b); @@ -1046,7 +949,7 @@ fn remove_liquidity( let amount_min_a = amounts[1]; let amount_min_b = amounts[2]; - // Verify vaults are in fact vaults + // 1. Fetch Pool state let pool_def_data = PoolDefinition::parse(&pool.account.data) .expect("Remove liquidity: AMM Program expects a valid Pool Definition Account"); @@ -1109,81 +1012,54 @@ fn remove_liquidity( let delta_lp: u128 = (pool_def_data.liquidity_pool_supply * amount_lp) / pool_def_data.liquidity_pool_supply; - let active: bool = if pool_def_data.liquidity_pool_supply - delta_lp == 0 { - false - } else { - true - }; + let active: bool = pool_def_data.liquidity_pool_supply - delta_lp != 0; // 5. Update pool account let mut pool_post = pool.account.clone(); let pool_post_definition = PoolDefinition { - definition_token_a_id: pool_def_data.definition_token_a_id.clone(), - definition_token_b_id: pool_def_data.definition_token_b_id.clone(), - vault_a_id: pool_def_data.vault_a_id.clone(), - vault_b_id: pool_def_data.vault_b_id.clone(), - liquidity_pool_id: pool_def_data.liquidity_pool_id.clone(), liquidity_pool_supply: pool_def_data.liquidity_pool_supply - delta_lp, reserve_a: pool_def_data.reserve_a - withdraw_amount_a, reserve_b: pool_def_data.reserve_b - withdraw_amount_b, - fees: 0u128, active, + ..pool_def_data.clone() }; - pool_post.data = pool_post_definition - .into_data() - .try_into() - .expect("Data too big"); + pool_post.data = pool_post_definition.into_data(); let mut chained_calls = Vec::new(); // Chaincall for Token A withdraw - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 1; // token transfer - instruction[1..17].copy_from_slice(&withdraw_amount_a.to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("Remove liquidity: AMM Program expects valid token transfer instruction data"); - let call_token_a = ChainedCall { - program_id: vault_a.account.program_owner, - instruction_data, - pre_states: vec![running_vault_a, user_holding_a.clone()], - pda_seeds: vec![compute_vault_pda_seed( - pool.account_id.clone(), - pool_def_data.definition_token_a_id.clone(), + let call_token_a = initialize_token_transfer_chained_call( + TOKEN_PROGRAM_TRANSFER, + running_vault_a, + user_holding_a.clone(), + withdraw_amount_a, + vec![compute_vault_pda_seed( + pool.account_id, + pool_def_data.definition_token_a_id, )], - }; - + ); // Chaincall for Token B withdraw - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 1; // token transfer - instruction[1..17].copy_from_slice(&withdraw_amount_b.to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("Remove liquidity: AMM Program expects valid token transfer instruction data"); - let call_token_b = ChainedCall { - program_id: vault_b.account.program_owner, - instruction_data, - pre_states: vec![running_vault_b, user_holding_b.clone()], - pda_seeds: vec![compute_vault_pda_seed( - pool.account_id.clone(), - pool_def_data.definition_token_b_id.clone(), + let call_token_b = initialize_token_transfer_chained_call( + TOKEN_PROGRAM_TRANSFER, + running_vault_b, + user_holding_b.clone(), + withdraw_amount_b, + vec![compute_vault_pda_seed( + pool.account_id, + pool_def_data.definition_token_b_id, )], - }; - + ); // Chaincall for LP adjustment let mut pool_definition_lp_auth = pool_definition_lp.clone(); pool_definition_lp_auth.is_authorized = true; - - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 3; // token burn - instruction[1..17].copy_from_slice(&delta_lp.to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("Remove liquidity: AMM Program expects valid token transfer instruction data"); - let call_token_lp = ChainedCall { - program_id: pool_definition_lp.account.program_owner, - instruction_data, - pre_states: vec![pool_definition_lp_auth.clone(), user_holding_lp.clone()], - pda_seeds: vec![compute_liquidity_token_pda_seed(pool.account_id.clone())], - }; + let call_token_lp = initialize_token_transfer_chained_call( + TOKEN_PROGRAM_BURN, + pool_definition_lp_auth.clone(), + user_holding_lp.clone(), + delta_lp, + vec![compute_liquidity_token_pda_seed(pool.account_id)], + ); chained_calls.push(call_token_lp); chained_calls.push(call_token_b); @@ -1205,861 +1081,795 @@ fn remove_liquidity( #[cfg(test)] mod tests { use nssa_core::{ - account::{Account, AccountId, AccountWithMetadata}, + account::{Account, AccountId, AccountWithMetadata, Data}, program::{ChainedCall, PdaSeed, ProgramId}, }; use crate::{ - PoolDefinition, TokenDefinition, TokenHolding, add_liquidity, compute_liquidity_token_pda, - compute_liquidity_token_pda_seed, compute_pool_pda, compute_pool_pda_seed, - compute_vault_pda, compute_vault_pda_seed, new_definition, remove_liquidity, swap, + PoolDefinition, TokenHolding, add_liquidity, compute_liquidity_token_pda, + compute_liquidity_token_pda_seed, compute_pool_pda, compute_vault_pda, + compute_vault_pda_seed, new_definition, remove_liquidity, swap, }; const TOKEN_PROGRAM_ID: ProgramId = [15; 8]; const AMM_PROGRAM_ID: ProgramId = [42; 8]; + const TOKEN_DEFINITION_DATA_SIZE: usize = 55; - enum AccountEnum { - UserHoldingB, - UserHoldingA, - VaultAUninit, - VaultBUninit, - VaultAInit, - VaultBInit, - VaultAInitHigh, - VaultBInitHigh, - VaultAInitLow, - VaultBInitLow, - VaultAInitZero, - VaultBInitZero, - VaultAWrongAccId, - VaultBWrongAccId, - PoolLPUninit, - PoolLPInit, - PoolLPWrongAccId, - UserHoldingLPUninit, - UserHoldingLPInit, - PoolDefinitionUninit, - PoolDefinitionInit, - PoolDefinitionInitReserveAZero, - PoolDefinitionInitReserveBZero, - PoolDefinitionInitReserveALow, - PoolDefinitionInitReserveBLow, - PoolDefinitionUnauth, - PoolDefinitionSwapTest1, - PoolDefinitionSwapTest2, - PoolDefinitionAddZeroLP, - PoolDefinitionAddSuccessful, - PoolDefinitionRemoveSuccessful, - PoolDefinitionInactive, - PoolDefinitionWrongId, - VaultAWrongId, - VaultBWrongId, - PoolLPWrongId, - PoolDefinitionActive, + struct TokenDefinition { + account_type: u8, + name: [u8; 6], + total_supply: u128, + metadata_id: AccountId, } - enum BalanceEnum { - VaultAReserveInit, - VaultBReserveInit, - VaultAReserveLow, - VaultBReserveLow, - VaultAReserveHigh, - VaultBReserveHigh, - UserTokenABal, - UserTokenBBal, - UserTokenLPBal, - RemoveMinAmountA, - RemoveMinAmountB, - RemoveActualASuccessful, - RemoveMinAmountBLow, - RemoveMinAmountBAow, - RemoveAmountLP, - RemoveAmountLP1, - AddMaxAmountALow, - AddMaxAmountBLow, - AddMaxAmountBHigh, - AddMaxAmountA, - AddMaxAmountb, - AddMinAmountLP, - VaultASwapTest1, - VaultASwapTest2, - VaultBSwapTest1, - VaultBSwapTest2, - MinAmountOut, - VaultAAddSuccessful, - VaultBAddSuccessful, - AddSuccessfulAmountA, - AddSuccessfulAmountB, - VaultARemoveSuccessful, - VaultBRemoveSuccessful, - } + impl TokenDefinition { + fn into_data(self) -> Data { + let mut bytes = Vec::::new(); + bytes.extend_from_slice(&[self.account_type]); + bytes.extend_from_slice(&self.name); + bytes.extend_from_slice(&self.total_supply.to_le_bytes()); + bytes.extend_from_slice(&self.metadata_id.to_bytes()); - fn helper_balance_constructor(selection: BalanceEnum) -> u128 { - match selection { - BalanceEnum::VaultAReserveInit => 1_000, - BalanceEnum::VaultBReserveInit => 500, - BalanceEnum::VaultAReserveLow => 10, - BalanceEnum::VaultBReserveLow => 10, - BalanceEnum::VaultAReserveHigh => 500_000, - BalanceEnum::VaultBReserveHigh => 500_000, - BalanceEnum::UserTokenABal => 1_000, - BalanceEnum::UserTokenBBal => 500, - BalanceEnum::UserTokenLPBal => 100, - BalanceEnum::RemoveMinAmountA => 50, - BalanceEnum::RemoveMinAmountB => 100, - BalanceEnum::RemoveActualASuccessful => 100, - BalanceEnum::RemoveMinAmountBLow => 50, - BalanceEnum::RemoveMinAmountBAow => 10, - BalanceEnum::RemoveAmountLP => 100, - BalanceEnum::RemoveAmountLP1 => 30, - BalanceEnum::AddMaxAmountA => 500, - BalanceEnum::AddMaxAmountb => 200, - BalanceEnum::AddMaxAmountBHigh => 20_000, - BalanceEnum::AddMaxAmountALow => 10, - BalanceEnum::AddMaxAmountBLow => 10, - BalanceEnum::AddMinAmountLP => 20, - BalanceEnum::VaultASwapTest1 => 1_500, - BalanceEnum::VaultASwapTest2 => 715, - BalanceEnum::VaultBSwapTest1 => 334, - BalanceEnum::VaultBSwapTest2 => 700, - BalanceEnum::MinAmountOut => 200, - BalanceEnum::VaultAAddSuccessful => 1_400, - BalanceEnum::VaultBAddSuccessful => 700, - BalanceEnum::AddSuccessfulAmountA => 400, - BalanceEnum::AddSuccessfulAmountB => 200, - BalanceEnum::VaultARemoveSuccessful => 900, - BalanceEnum::VaultBRemoveSuccessful => 450, - _ => panic!("Invalid selection"), + if bytes.len() != TOKEN_DEFINITION_DATA_SIZE { + panic!("Invalid Token Definition data"); + } + + Data::try_from(bytes).expect("Token definition data size must fit into data") } } - enum IdEnum { - TokenADefinitionId, - TokenBDefinitionId, - TokenLPDefinitionId, - UserTokenAId, - UserTokenBId, - UserTokenLPId, - PoolDefinitionId, - VaultAId, - VaultBId, - } + struct BalanceForTests; - enum ChainedCallsEnum { - CcTokenAInitialization, - CcTokenBInitialization, - CcPoolLPInitiailization, - CcSwapTokenATest1, - CcSwapTokenBTest1, - CcSwapTokenATest2, - CcSwapTokenBTest2, - CcAddTokenA, - CcAddTokenB, - CcAddPoolLP, - CcRemoveTokenA, - CcRemoveTokenB, - CcRemovePoolLP, - CcNewDefinitionTokenA, - CcNewDefinitionTokenB, - CcNewDefinitionLP, - } + impl BalanceForTests { + fn vault_a_reserve_init() -> u128 { + 1_000 + } - fn helper_chained_call_constructor(selection: ChainedCallsEnum) -> ChainedCall { - match selection { - ChainedCallsEnum::CcTokenAInitialization => { - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 1; - instruction[1..17].copy_from_slice( - &helper_balance_constructor(BalanceEnum::UserTokenABal).to_le_bytes(), - ); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::VaultAUninit), - ], - pda_seeds: Vec::::new(), - } - } - ChainedCallsEnum::CcTokenBInitialization => { - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 1; - instruction[1..17].copy_from_slice( - &helper_balance_constructor(BalanceEnum::UserTokenBBal).to_le_bytes(), - ); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::VaultBUninit), - ], - pda_seeds: Vec::::new(), - } - } - ChainedCallsEnum::CcPoolLPInitiailization => { - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 1; - instruction[1..17].copy_from_slice( - &helper_balance_constructor(BalanceEnum::UserTokenABal).to_le_bytes(), - ); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - helper_account_constructor(AccountEnum::PoolLPUninit), - helper_account_constructor(AccountEnum::UserHoldingLPUninit), - ], - pda_seeds: Vec::::new(), - } - } - ChainedCallsEnum::CcSwapTokenATest1 => { - let mut instruction_data: [u8; 23] = [0; 23]; - instruction_data[0] = 1; - instruction_data[1..17].copy_from_slice( - &helper_balance_constructor(BalanceEnum::AddMaxAmountA).to_le_bytes(), - ); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::VaultAInit), - ], - pda_seeds: Vec::::new(), - } - } - ChainedCallsEnum::CcSwapTokenBTest1 => { - let swap_amount: u128 = 166; + fn vault_b_reserve_init() -> u128 { + 500 + } - let mut vault_b_auth = helper_account_constructor(AccountEnum::VaultBInit); - vault_b_auth.is_authorized = true; + fn vault_a_reserve_low() -> u128 { + 10 + } - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 1; - instruction[1..17].copy_from_slice(&swap_amount.to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - vault_b_auth, - helper_account_constructor(AccountEnum::UserHoldingB), - ], - pda_seeds: vec![compute_vault_pda_seed( - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_id_constructor(IdEnum::TokenBDefinitionId), - )], - } - } - ChainedCallsEnum::CcSwapTokenATest2 => { - let swap_amount: u128 = 285; + fn vault_b_reserve_low() -> u128 { + 10 + } - let mut vault_a_auth = helper_account_constructor(AccountEnum::VaultAInit); - vault_a_auth.is_authorized = true; + fn vault_a_reserve_high() -> u128 { + 500_000 + } - let mut instruction_data: [u8; 23] = [0; 23]; - instruction_data[0] = 1; - instruction_data[1..17].copy_from_slice(&swap_amount.to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - vault_a_auth, - helper_account_constructor(AccountEnum::UserHoldingA), - ], - pda_seeds: vec![compute_vault_pda_seed( - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_id_constructor(IdEnum::TokenADefinitionId), - )], - } - } - ChainedCallsEnum::CcSwapTokenBTest2 => { - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 1; - instruction[1..17].copy_from_slice( - &helper_balance_constructor(BalanceEnum::AddMaxAmountb).to_le_bytes(), - ); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::VaultBInit), - ], - pda_seeds: Vec::::new(), - } - } - ChainedCallsEnum::CcAddTokenA => { - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 1; - instruction[1..17].copy_from_slice( - &helper_balance_constructor(BalanceEnum::AddSuccessfulAmountA).to_le_bytes(), - ); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::VaultAInit), - ], - pda_seeds: Vec::::new(), - } - } - ChainedCallsEnum::CcAddTokenB => { - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 1; - instruction[1..17].copy_from_slice( - &helper_balance_constructor(BalanceEnum::AddSuccessfulAmountB).to_le_bytes(), - ); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("Swap Logic: AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::VaultBInit), - ], - pda_seeds: Vec::::new(), - } - } - ChainedCallsEnum::CcAddPoolLP => { - let mut pool_lp_auth = helper_account_constructor(AccountEnum::PoolLPInit); - pool_lp_auth.is_authorized = true; + fn vault_b_reserve_high() -> u128 { + 500_000 + } - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 4; - instruction[1..17].copy_from_slice( - &helper_balance_constructor(BalanceEnum::AddSuccessfulAmountA).to_le_bytes(), - ); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("Swap Logic: AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - pool_lp_auth, - helper_account_constructor(AccountEnum::UserHoldingLPInit), - ], - pda_seeds: vec![compute_liquidity_token_pda_seed(helper_id_constructor( - IdEnum::PoolDefinitionId, - ))], - } - } - ChainedCallsEnum::CcRemoveTokenA => { - let mut vault_a_auth = helper_account_constructor(AccountEnum::VaultAInit); - vault_a_auth.is_authorized = true; + fn user_token_a_balance() -> u128 { + 1_000 + } - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 1; - instruction[1..17].copy_from_slice( - &helper_balance_constructor(BalanceEnum::RemoveActualASuccessful).to_le_bytes(), - ); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - vault_a_auth, - helper_account_constructor(AccountEnum::UserHoldingA), - ], - pda_seeds: vec![compute_vault_pda_seed( - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_id_constructor(IdEnum::TokenADefinitionId), - )], - } - } - ChainedCallsEnum::CcRemoveTokenB => { - let mut vault_b_auth = helper_account_constructor(AccountEnum::VaultBInit); - vault_b_auth.is_authorized = true; + fn user_token_b_balance() -> u128 { + 500 + } - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 1; - instruction[1..17].copy_from_slice( - &helper_balance_constructor(BalanceEnum::RemoveMinAmountBLow).to_le_bytes(), - ); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - vault_b_auth, - helper_account_constructor(AccountEnum::UserHoldingB), - ], - pda_seeds: vec![compute_vault_pda_seed( - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_id_constructor(IdEnum::TokenBDefinitionId), - )], - } - } - ChainedCallsEnum::CcRemovePoolLP => { - let mut pool_lp_auth = helper_account_constructor(AccountEnum::PoolLPInit); - pool_lp_auth.is_authorized = true; + fn user_token_lp_balance() -> u128 { + 100 + } - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 3; - instruction[1..17].copy_from_slice( - &helper_balance_constructor(BalanceEnum::RemoveActualASuccessful).to_le_bytes(), - ); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - helper_account_constructor(AccountEnum::UserHoldingLPInit), - helper_account_constructor(AccountEnum::PoolLPInit), - ], - pda_seeds: vec![compute_liquidity_token_pda_seed(helper_id_constructor( - IdEnum::PoolDefinitionId, - ))], - } - } - ChainedCallsEnum::CcNewDefinitionTokenA => { - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 1; - instruction[1..17].copy_from_slice( - &helper_balance_constructor(BalanceEnum::AddSuccessfulAmountA).to_le_bytes(), - ); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::VaultAInit), - ], - pda_seeds: Vec::::new(), - } - } - ChainedCallsEnum::CcNewDefinitionTokenB => { - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 1; - instruction[1..17].copy_from_slice( - &helper_balance_constructor(BalanceEnum::AddSuccessfulAmountB).to_le_bytes(), - ); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("Swap Logic: AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::VaultBInit), - ], - pda_seeds: Vec::::new(), - } - } - ChainedCallsEnum::CcAddPoolLP => { - let mut pool_lp_auth = helper_account_constructor(AccountEnum::PoolLPInit); - pool_lp_auth.is_authorized = true; + fn remove_min_amount_a() -> u128 { + 50 + } - let mut instruction: [u8; 23] = [0; 23]; - instruction[0] = 0; - instruction[1..17].copy_from_slice( - &helper_balance_constructor(BalanceEnum::AddSuccessfulAmountA).to_le_bytes(), - ); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("Swap Logic: AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - pool_lp_auth, - helper_account_constructor(AccountEnum::UserHoldingLPInit), - ], - pda_seeds: vec![compute_liquidity_token_pda_seed(helper_id_constructor( - IdEnum::PoolDefinitionId, - ))], - } - } - _ => panic!("Invalid selection"), + fn remove_min_amount_b() -> u128 { + 100 + } + + fn remove_actual_a_successful() -> u128 { + 100 + } + + fn remove_min_amount_b_low() -> u128 { + 50 + } + + fn remove_amount_lp() -> u128 { + 100 + } + + fn remove_amount_lp_1() -> u128 { + 30 + } + + fn add_max_amount_a() -> u128 { + 500 + } + + fn add_max_amount_b() -> u128 { + 200 + } + + fn add_max_amount_a_low() -> u128 { + 10 + } + + fn add_max_amount_b_low() -> u128 { + 10 + } + + fn add_min_amount_lp() -> u128 { + 20 + } + + fn vault_a_swap_test_1() -> u128 { + 1_500 + } + + fn vault_a_swap_test_2() -> u128 { + 715 + } + + fn vault_b_swap_test_1() -> u128 { + 334 + } + + fn vault_b_swap_test_2() -> u128 { + 700 + } + + fn min_amount_out() -> u128 { + 200 + } + + fn vault_a_add_successful() -> u128 { + 1_400 + } + + fn vault_b_add_successful() -> u128 { + 700 + } + + fn add_successful_amount_a() -> u128 { + 400 + } + + fn add_successful_amount_b() -> u128 { + 200 + } + + fn vault_a_remove_successful() -> u128 { + 900 + } + + fn vault_b_remove_successful() -> u128 { + 450 } } - fn helper_id_constructor(selection: IdEnum) -> AccountId { - match selection { - IdEnum::TokenADefinitionId => AccountId::new([42; 32]), - IdEnum::TokenBDefinitionId => AccountId::new([43; 32]), - IdEnum::TokenLPDefinitionId => compute_liquidity_token_pda( - AMM_PROGRAM_ID, - helper_id_constructor(IdEnum::PoolDefinitionId), - ), - IdEnum::UserTokenAId => AccountId::new([45; 32]), - IdEnum::UserTokenBId => AccountId::new([46; 32]), - IdEnum::UserTokenLPId => AccountId::new([47; 32]), - IdEnum::PoolDefinitionId => compute_pool_pda( - AMM_PROGRAM_ID, - helper_id_constructor(IdEnum::TokenADefinitionId), - helper_id_constructor(IdEnum::TokenBDefinitionId), - ), - IdEnum::VaultAId => compute_vault_pda( - AMM_PROGRAM_ID, - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_id_constructor(IdEnum::TokenADefinitionId), - ), - IdEnum::VaultBId => compute_vault_pda( - AMM_PROGRAM_ID, - helper_id_constructor(IdEnum::PoolDefinitionId), - helper_id_constructor(IdEnum::TokenBDefinitionId), - ), - _ => panic!("Invalid selection"), + struct ChainedCallForTests; + + impl ChainedCallForTests { + fn cc_swap_token_a_test_1() -> ChainedCall { + let mut instruction_data = vec![0; 23]; + instruction_data[0] = 1; + instruction_data[1..17] + .copy_from_slice(&BalanceForTests::add_max_amount_a().to_le_bytes()); + let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) + .expect("AMM Program expects valid transaction instruction data"); + ChainedCall { + program_id: TOKEN_PROGRAM_ID, + instruction_data, + pre_states: vec![ + AccountForTests::user_holding_a(), + AccountForTests::vault_a_init(), + ], + pda_seeds: Vec::::new(), + } + } + + fn cc_swap_token_b_test_1() -> ChainedCall { + let swap_amount: u128 = 166; + + let mut vault_b_auth = AccountForTests::vault_b_init(); + vault_b_auth.is_authorized = true; + + let mut instruction = vec![0; 23]; + instruction[0] = 1; + instruction[1..17].copy_from_slice(&swap_amount.to_le_bytes()); + let instruction_data = risc0_zkvm::serde::to_vec(&instruction) + .expect("AMM Program expects valid transaction instruction data"); + ChainedCall { + program_id: TOKEN_PROGRAM_ID, + instruction_data, + pre_states: vec![vault_b_auth, AccountForTests::user_holding_b()], + pda_seeds: vec![compute_vault_pda_seed( + IdForTests::pool_definition_id(), + IdForTests::token_b_definition_id(), + )], + } + } + + fn cc_swap_token_a_test_2() -> ChainedCall { + let swap_amount: u128 = 285; + + let mut vault_a_auth = AccountForTests::vault_a_init(); + vault_a_auth.is_authorized = true; + + let mut instruction_data = vec![0; 23]; + instruction_data[0] = 1; + instruction_data[1..17].copy_from_slice(&swap_amount.to_le_bytes()); + let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) + .expect("AMM Program expects valid transaction instruction data"); + ChainedCall { + program_id: TOKEN_PROGRAM_ID, + instruction_data, + pre_states: vec![vault_a_auth, AccountForTests::user_holding_a()], + pda_seeds: vec![compute_vault_pda_seed( + IdForTests::pool_definition_id(), + IdForTests::token_a_definition_id(), + )], + } + } + + fn cc_swap_token_b_test_2() -> ChainedCall { + let mut instruction = vec![0; 23]; + instruction[0] = 1; + instruction[1..17].copy_from_slice(&BalanceForTests::add_max_amount_b().to_le_bytes()); + let instruction_data = risc0_zkvm::serde::to_vec(&instruction) + .expect("AMM Program expects valid transaction instruction data"); + ChainedCall { + program_id: TOKEN_PROGRAM_ID, + instruction_data, + pre_states: vec![ + AccountForTests::user_holding_b(), + AccountForTests::vault_b_init(), + ], + pda_seeds: Vec::::new(), + } + } + + fn cc_add_token_a() -> ChainedCall { + let mut instruction = vec![0u8; 23]; + instruction[0] = 1; + instruction[1..17] + .copy_from_slice(&BalanceForTests::add_successful_amount_a().to_le_bytes()); + let instruction_data = risc0_zkvm::serde::to_vec(&instruction) + .expect("AMM Program expects valid transaction instruction data"); + ChainedCall { + program_id: TOKEN_PROGRAM_ID, + instruction_data, + pre_states: vec![ + AccountForTests::user_holding_a(), + AccountForTests::vault_a_init(), + ], + pda_seeds: Vec::::new(), + } + } + + fn cc_add_token_b() -> ChainedCall { + let mut instruction = vec![0u8; 23]; + instruction[0] = 1; + instruction[1..17] + .copy_from_slice(&BalanceForTests::add_successful_amount_b().to_le_bytes()); + let instruction_data = risc0_zkvm::serde::to_vec(&instruction) + .expect("Swap Logic: AMM Program expects valid transaction instruction data"); + ChainedCall { + program_id: TOKEN_PROGRAM_ID, + instruction_data, + pre_states: vec![ + AccountForTests::user_holding_b(), + AccountForTests::vault_b_init(), + ], + pda_seeds: Vec::::new(), + } + } + + fn cc_add_pool_lp() -> ChainedCall { + let mut pool_lp_auth = AccountForTests::pool_lp_init(); + pool_lp_auth.is_authorized = true; + + let mut instruction = vec![0u8; 23]; + instruction[0] = 4; + instruction[1..17] + .copy_from_slice(&BalanceForTests::add_successful_amount_a().to_le_bytes()); + let instruction_data = risc0_zkvm::serde::to_vec(&instruction) + .expect("Swap Logic: AMM Program expects valid transaction instruction data"); + ChainedCall { + program_id: TOKEN_PROGRAM_ID, + instruction_data, + pre_states: vec![pool_lp_auth, AccountForTests::user_holding_lp_init()], + pda_seeds: vec![compute_liquidity_token_pda_seed( + IdForTests::pool_definition_id(), + )], + } + } + + fn cc_remove_token_a() -> ChainedCall { + let mut vault_a_auth = AccountForTests::vault_a_init(); + vault_a_auth.is_authorized = true; + + let mut instruction = vec![0; 23]; + instruction[0] = 1; + instruction[1..17] + .copy_from_slice(&BalanceForTests::remove_actual_a_successful().to_le_bytes()); + let instruction_data = risc0_zkvm::serde::to_vec(&instruction) + .expect("AMM Program expects valid transaction instruction data"); + ChainedCall { + program_id: TOKEN_PROGRAM_ID, + instruction_data, + pre_states: vec![vault_a_auth, AccountForTests::user_holding_a()], + pda_seeds: vec![compute_vault_pda_seed( + IdForTests::pool_definition_id(), + IdForTests::token_a_definition_id(), + )], + } + } + + fn cc_remove_token_b() -> ChainedCall { + let mut vault_b_auth = AccountForTests::vault_b_init(); + vault_b_auth.is_authorized = true; + + let mut instruction = vec![0; 23]; + instruction[0] = 1; + instruction[1..17] + .copy_from_slice(&BalanceForTests::remove_min_amount_b_low().to_le_bytes()); + let instruction_data = risc0_zkvm::serde::to_vec(&instruction) + .expect("AMM Program expects valid transaction instruction data"); + ChainedCall { + program_id: TOKEN_PROGRAM_ID, + instruction_data, + pre_states: vec![vault_b_auth, AccountForTests::user_holding_b()], + pda_seeds: vec![compute_vault_pda_seed( + IdForTests::pool_definition_id(), + IdForTests::token_b_definition_id(), + )], + } + } + + fn cc_remove_pool_lp() -> ChainedCall { + let mut pool_lp_auth = AccountForTests::pool_lp_init(); + pool_lp_auth.is_authorized = true; + + let mut instruction = vec![0; 23]; + instruction[0] = 3; + instruction[1..17] + .copy_from_slice(&BalanceForTests::remove_actual_a_successful().to_le_bytes()); + let instruction_data = risc0_zkvm::serde::to_vec(&instruction) + .expect("AMM Program expects valid transaction instruction data"); + ChainedCall { + program_id: TOKEN_PROGRAM_ID, + instruction_data, + pre_states: vec![ + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_lp_init(), + ], + pda_seeds: vec![compute_liquidity_token_pda_seed( + IdForTests::pool_definition_id(), + )], + } + } + + fn cc_new_definition_token_a() -> ChainedCall { + let mut instruction = vec![0; 23]; + instruction[0] = 1; + instruction[1..17] + .copy_from_slice(&BalanceForTests::add_successful_amount_a().to_le_bytes()); + let instruction_data = risc0_zkvm::serde::to_vec(&instruction) + .expect("AMM Program expects valid transaction instruction data"); + ChainedCall { + program_id: TOKEN_PROGRAM_ID, + instruction_data, + pre_states: vec![ + AccountForTests::user_holding_a(), + AccountForTests::vault_a_init(), + ], + pda_seeds: Vec::::new(), + } + } + + fn cc_new_definition_token_b() -> ChainedCall { + let mut instruction = vec![0; 23]; + instruction[0] = 1; + instruction[1..17] + .copy_from_slice(&BalanceForTests::add_successful_amount_b().to_le_bytes()); + let instruction_data = risc0_zkvm::serde::to_vec(&instruction) + .expect("Swap Logic: AMM Program expects valid transaction instruction data"); + ChainedCall { + program_id: TOKEN_PROGRAM_ID, + instruction_data, + pre_states: vec![ + AccountForTests::user_holding_b(), + AccountForTests::vault_b_init(), + ], + pda_seeds: Vec::::new(), + } + } + + fn cc_new_definition_token_lp() -> ChainedCall { + let mut instruction = vec![0; 23]; + instruction[0] = 1; + instruction[1..17] + .copy_from_slice(&BalanceForTests::add_successful_amount_a().to_le_bytes()); + let instruction_data = risc0_zkvm::serde::to_vec(&instruction) + .expect("AMM Program expects valid transaction instruction data"); + ChainedCall { + program_id: TOKEN_PROGRAM_ID, + instruction_data, + pre_states: vec![ + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_lp_uninit(), + ], + pda_seeds: vec![compute_liquidity_token_pda_seed( + IdForTests::pool_definition_id(), + )], + } } } - fn helper_account_constructor(selection: AccountEnum) -> AccountWithMetadata { - match selection { - AccountEnum::UserHoldingA => AccountWithMetadata { + struct IdForTests; + + impl IdForTests { + fn token_a_definition_id() -> AccountId { + AccountId::new([42; 32]) + } + + fn token_b_definition_id() -> AccountId { + AccountId::new([43; 32]) + } + + fn token_lp_definition_id() -> AccountId { + compute_liquidity_token_pda(AMM_PROGRAM_ID, IdForTests::pool_definition_id()) + } + + fn user_token_a_id() -> AccountId { + AccountId::new([45; 32]) + } + + fn user_token_b_id() -> AccountId { + AccountId::new([46; 32]) + } + + fn user_token_lp_id() -> AccountId { + AccountId::new([47; 32]) + } + + fn pool_definition_id() -> AccountId { + compute_pool_pda( + AMM_PROGRAM_ID, + IdForTests::token_a_definition_id(), + IdForTests::token_b_definition_id(), + ) + } + + fn vault_a_id() -> AccountId { + compute_vault_pda( + AMM_PROGRAM_ID, + IdForTests::pool_definition_id(), + IdForTests::token_a_definition_id(), + ) + } + + fn vault_b_id() -> AccountId { + compute_vault_pda( + AMM_PROGRAM_ID, + IdForTests::pool_definition_id(), + IdForTests::token_b_definition_id(), + ) + } + } + + struct AccountForTests; + + impl AccountForTests { + fn user_holding_a() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balance_constructor(BalanceEnum::UserTokenABal), + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::user_token_a_balance(), }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::UserTokenAId), - }, - AccountEnum::UserHoldingB => AccountWithMetadata { + account_id: IdForTests::user_token_a_id(), + } + } + + fn user_holding_b() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balance_constructor(BalanceEnum::UserTokenBBal), + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::user_token_b_balance(), }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::UserTokenBId), - }, - AccountEnum::VaultAUninit => AccountWithMetadata { + account_id: IdForTests::user_token_b_id(), + } + } + + fn vault_a_init() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::vault_a_reserve_init(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::vault_a_id(), + } + } + + fn vault_b_init() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: TOKEN_PROGRAM_ID, + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: 1u8, + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::vault_b_reserve_init(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::vault_b_id(), + } + } + + fn vault_a_init_high() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: TOKEN_PROGRAM_ID, + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: 1u8, + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::vault_a_reserve_high(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::vault_a_id(), + } + } + + fn vault_b_init_high() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: TOKEN_PROGRAM_ID, + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: 1u8, + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::vault_b_reserve_high(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::vault_b_id(), + } + } + + fn vault_a_init_low() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: TOKEN_PROGRAM_ID, + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: 1u8, + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::vault_a_reserve_low(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::vault_a_id(), + } + } + + fn vault_b_init_low() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: TOKEN_PROGRAM_ID, + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: 1u8, + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::vault_b_reserve_low(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::vault_b_id(), + } + } + + fn vault_a_init_zero() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: TOKEN_PROGRAM_ID, + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: 1u8, + definition_id: IdForTests::token_a_definition_id(), balance: 0, }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::VaultAId), - }, - AccountEnum::VaultBUninit => AccountWithMetadata { + account_id: IdForTests::vault_a_id(), + } + } + + fn vault_b_init_zero() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), + definition_id: IdForTests::token_b_definition_id(), balance: 0, }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::VaultBId), - }, - AccountEnum::VaultAInit => AccountWithMetadata { - account: Account { - program_owner: TOKEN_PROGRAM_ID, - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balance_constructor(BalanceEnum::VaultAReserveInit), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::VaultAId), - }, - AccountEnum::VaultBInit => AccountWithMetadata { - account: Account { - program_owner: TOKEN_PROGRAM_ID, - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balance_constructor(BalanceEnum::VaultBReserveInit), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::VaultBId), - }, - AccountEnum::VaultAInitHigh => AccountWithMetadata { - account: Account { - program_owner: TOKEN_PROGRAM_ID, - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balance_constructor(BalanceEnum::VaultAReserveHigh), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::VaultAId), - }, - AccountEnum::VaultBInitHigh => AccountWithMetadata { - account: Account { - program_owner: TOKEN_PROGRAM_ID, - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balance_constructor(BalanceEnum::VaultBReserveHigh), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::VaultBId), - }, - AccountEnum::VaultAInitLow => AccountWithMetadata { - account: Account { - program_owner: TOKEN_PROGRAM_ID, - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balance_constructor(BalanceEnum::VaultAReserveLow), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::VaultAId), - }, - AccountEnum::VaultBInitLow => AccountWithMetadata { - account: Account { - program_owner: TOKEN_PROGRAM_ID, - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balance_constructor(BalanceEnum::VaultBReserveLow), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::VaultBId), - }, - AccountEnum::VaultAInitZero => AccountWithMetadata { - account: Account { - program_owner: TOKEN_PROGRAM_ID, - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: 0, - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::VaultAId), - }, - AccountEnum::VaultBInitZero => AccountWithMetadata { - account: Account { - program_owner: TOKEN_PROGRAM_ID, - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: 0, - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::VaultBId), - }, - AccountEnum::VaultAWrongAccId => AccountWithMetadata { - account: Account { - program_owner: TOKEN_PROGRAM_ID, - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balance_constructor(BalanceEnum::VaultAReserveInit), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::VaultBId), - }, - AccountEnum::VaultBWrongAccId => AccountWithMetadata { - account: Account { - program_owner: TOKEN_PROGRAM_ID, - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balance_constructor(BalanceEnum::VaultBReserveInit), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::VaultAId), - }, - AccountEnum::PoolLPUninit => AccountWithMetadata { + account_id: IdForTests::vault_b_id(), + } + } + + fn pool_lp_init() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, data: TokenDefinition::into_data(TokenDefinition { account_type: 0u8, name: [1; 6], - total_supply: 0u128, + total_supply: BalanceForTests::vault_a_reserve_init(), + metadata_id: AccountId::new([0; 32]), }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - }, - AccountEnum::PoolLPInit => AccountWithMetadata { + account_id: IdForTests::token_lp_definition_id(), + } + } + + fn pool_lp_with_wrong_id() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, data: TokenDefinition::into_data(TokenDefinition { account_type: 0u8, name: [1; 6], - total_supply: helper_balance_constructor(BalanceEnum::VaultAReserveInit), + total_supply: BalanceForTests::vault_a_reserve_init(), + metadata_id: AccountId::new([0; 32]), }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - }, - AccountEnum::PoolLPWrongAccId => AccountWithMetadata { - account: Account { - program_owner: TOKEN_PROGRAM_ID, - balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: 0u8, - name: [1; 6], - total_supply: helper_balance_constructor(BalanceEnum::VaultAReserveInit), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::VaultAId), - }, - AccountEnum::UserHoldingLPUninit => AccountWithMetadata { + account_id: IdForTests::vault_a_id(), + } + } + + fn user_holding_lp_uninit() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), + definition_id: IdForTests::token_lp_definition_id(), balance: 0, }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::UserTokenLPId), - }, - AccountEnum::UserHoldingLPInit => AccountWithMetadata { + account_id: IdForTests::user_token_lp_id(), + } + } + + fn user_holding_lp_init() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - balance: helper_balance_constructor(BalanceEnum::UserTokenLPBal), + definition_id: IdForTests::token_lp_definition_id(), + balance: BalanceForTests::user_token_lp_balance(), }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::UserTokenLPId), - }, - AccountEnum::PoolDefinitionUninit => AccountWithMetadata { + account_id: IdForTests::user_token_lp_id(), + } + } + + fn pool_definition_uninit() -> AccountWithMetadata { + AccountWithMetadata { account: Account::default(), is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountEnum::PoolDefinitionInit => AccountWithMetadata { + account_id: IdForTests::pool_definition_id(), + } + } + + fn pool_definition_init() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: ProgramId::default(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balance_constructor( - BalanceEnum::VaultAReserveInit, - ), - reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveInit), - reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveInit), + 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::vault_a_reserve_init(), + reserve_a: BalanceForTests::vault_a_reserve_init(), + reserve_b: BalanceForTests::vault_b_reserve_init(), fees: 0u128, active: true, }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountEnum::PoolDefinitionInitReserveAZero => AccountWithMetadata { + account_id: IdForTests::pool_definition_id(), + } + } + + fn pool_definition_init_reserve_a_zero() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: ProgramId::default(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balance_constructor( - BalanceEnum::VaultAReserveInit, - ), + 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::vault_a_reserve_init(), reserve_a: 0, - reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveInit), + reserve_b: BalanceForTests::vault_b_reserve_init(), fees: 0u128, active: true, }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountEnum::PoolDefinitionInitReserveBZero => AccountWithMetadata { + account_id: IdForTests::pool_definition_id(), + } + } + + fn pool_definition_init_reserve_b_zero() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: ProgramId::default(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balance_constructor( - BalanceEnum::VaultAReserveInit, - ), - reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveInit), + 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::vault_a_reserve_init(), + reserve_a: BalanceForTests::vault_a_reserve_init(), reserve_b: 0, fees: 0u128, active: true, @@ -2067,230 +1877,216 @@ mod tests { nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountEnum::PoolDefinitionInitReserveALow => AccountWithMetadata { + account_id: IdForTests::pool_definition_id(), + } + } + + fn pool_definition_init_reserve_a_low() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: ProgramId::default(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balance_constructor( - BalanceEnum::VaultAReserveLow, - ), - reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveLow), - reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveHigh), + 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::vault_a_reserve_low(), + reserve_a: BalanceForTests::vault_a_reserve_low(), + reserve_b: BalanceForTests::vault_b_reserve_high(), fees: 0u128, active: true, }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountEnum::PoolDefinitionInitReserveBLow => AccountWithMetadata { + account_id: IdForTests::pool_definition_id(), + } + } + + fn pool_definition_init_reserve_b_low() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: ProgramId::default(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balance_constructor( - BalanceEnum::VaultAReserveHigh, - ), - reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveHigh), - reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveLow), + 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::vault_a_reserve_high(), + reserve_a: BalanceForTests::vault_a_reserve_high(), + reserve_b: BalanceForTests::vault_b_reserve_low(), fees: 0u128, active: true, }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountEnum::PoolDefinitionUnauth => AccountWithMetadata { + account_id: IdForTests::pool_definition_id(), + } + } + + fn pool_definition_swap_test_1() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: ProgramId::default(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balance_constructor( - BalanceEnum::VaultAReserveInit, - ), - reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveInit), - reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveInit), - fees: 0u128, - active: true, - }), - nonce: 0, - }, - is_authorized: false, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountEnum::PoolDefinitionSwapTest1 => AccountWithMetadata { - account: Account { - program_owner: ProgramId::default(), - balance: 0u128, - data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balance_constructor( - BalanceEnum::VaultAReserveInit, - ), - reserve_a: helper_balance_constructor(BalanceEnum::VaultASwapTest1), - reserve_b: helper_balance_constructor(BalanceEnum::VaultBSwapTest1), + 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::vault_a_reserve_init(), + reserve_a: BalanceForTests::vault_a_swap_test_1(), + reserve_b: BalanceForTests::vault_b_swap_test_1(), fees: 0u128, active: true, }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountEnum::PoolDefinitionSwapTest2 => AccountWithMetadata { + account_id: IdForTests::pool_definition_id(), + } + } + + fn pool_definition_swap_test_2() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: ProgramId::default(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balance_constructor( - BalanceEnum::VaultAReserveInit, - ), - reserve_a: helper_balance_constructor(BalanceEnum::VaultASwapTest2), - reserve_b: helper_balance_constructor(BalanceEnum::VaultBSwapTest2), + 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::vault_a_reserve_init(), + reserve_a: BalanceForTests::vault_a_swap_test_2(), + reserve_b: BalanceForTests::vault_b_swap_test_2(), fees: 0u128, active: true, }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountEnum::PoolDefinitionAddZeroLP => AccountWithMetadata { + account_id: IdForTests::pool_definition_id(), + } + } + + fn pool_definition_add_zero_lp() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: ProgramId::default(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balance_constructor( - BalanceEnum::VaultAReserveLow, - ), - reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveInit), - reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveInit), + 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::vault_a_reserve_low(), + reserve_a: BalanceForTests::vault_a_reserve_init(), + reserve_b: BalanceForTests::vault_b_reserve_init(), fees: 0u128, active: true, }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountEnum::PoolDefinitionAddSuccessful => AccountWithMetadata { + account_id: IdForTests::pool_definition_id(), + } + } + + fn pool_definition_add_successful() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: ProgramId::default(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balance_constructor( - BalanceEnum::VaultAAddSuccessful, - ), - reserve_a: helper_balance_constructor(BalanceEnum::VaultAAddSuccessful), - reserve_b: helper_balance_constructor(BalanceEnum::VaultBAddSuccessful), + 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::vault_a_add_successful(), + reserve_a: BalanceForTests::vault_a_add_successful(), + reserve_b: BalanceForTests::vault_b_add_successful(), fees: 0u128, active: true, }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountEnum::PoolDefinitionRemoveSuccessful => AccountWithMetadata { + account_id: IdForTests::pool_definition_id(), + } + } + + fn pool_definition_remove_successful() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: ProgramId::default(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balance_constructor( - BalanceEnum::VaultARemoveSuccessful, - ), - reserve_a: helper_balance_constructor(BalanceEnum::VaultARemoveSuccessful), - reserve_b: helper_balance_constructor(BalanceEnum::VaultBRemoveSuccessful), + 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::vault_a_remove_successful(), + reserve_a: BalanceForTests::vault_a_remove_successful(), + reserve_b: BalanceForTests::vault_b_remove_successful(), fees: 0u128, active: true, }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountEnum::PoolDefinitionInactive => AccountWithMetadata { + account_id: IdForTests::pool_definition_id(), + } + } + + fn pool_definition_inactive() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: ProgramId::default(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balance_constructor( - BalanceEnum::VaultAReserveInit, - ), - reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveInit), - reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveInit), + 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::vault_a_reserve_init(), + reserve_a: BalanceForTests::vault_a_reserve_init(), + reserve_b: BalanceForTests::vault_b_reserve_init(), fees: 0u128, active: false, }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountEnum::PoolDefinitionWrongId => AccountWithMetadata { + account_id: IdForTests::pool_definition_id(), + } + } + + fn pool_definition_with_wrong_id() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: ProgramId::default(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balance_constructor( - BalanceEnum::VaultAReserveInit, - ), - reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveInit), - reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveInit), + 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::vault_a_reserve_init(), + reserve_a: BalanceForTests::vault_a_reserve_init(), + reserve_b: BalanceForTests::vault_b_reserve_init(), fees: 0u128, active: false, }), @@ -2298,73 +2094,65 @@ mod tests { }, is_authorized: true, account_id: AccountId::new([4; 32]), - }, - AccountEnum::VaultAWrongId => AccountWithMetadata { + } + } + + fn vault_a_with_wrong_id() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenADefinitionId), - balance: helper_balance_constructor(BalanceEnum::VaultAReserveInit), + definition_id: IdForTests::token_a_definition_id(), + balance: BalanceForTests::vault_a_reserve_init(), }), nonce: 0, }, is_authorized: true, account_id: AccountId::new([4; 32]), - }, - AccountEnum::VaultBWrongId => AccountWithMetadata { + } + } + + fn vault_b_with_wrong_id() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, data: TokenHolding::into_data(TokenHolding { account_type: 1u8, - definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - balance: helper_balance_constructor(BalanceEnum::VaultBReserveInit), + definition_id: IdForTests::token_b_definition_id(), + balance: BalanceForTests::vault_b_reserve_init(), }), nonce: 0, }, is_authorized: true, account_id: AccountId::new([4; 32]), - }, - AccountEnum::PoolLPWrongId => AccountWithMetadata { - account: Account { - program_owner: TOKEN_PROGRAM_ID, - balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: 0u8, - name: [1; 6], - total_supply: helper_balance_constructor(BalanceEnum::VaultAReserveInit), - }), - nonce: 0, - }, - is_authorized: true, - account_id: AccountId::new([4; 32]), - }, - AccountEnum::PoolDefinitionActive => AccountWithMetadata { + } + } + + fn pool_definition_active() -> AccountWithMetadata { + AccountWithMetadata { account: Account { program_owner: ProgramId::default(), balance: 0u128, data: PoolDefinition::into_data(PoolDefinition { - definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId), - definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId), - vault_a_id: helper_id_constructor(IdEnum::VaultAId), - vault_b_id: helper_id_constructor(IdEnum::VaultBId), - liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId), - liquidity_pool_supply: helper_balance_constructor( - BalanceEnum::VaultAReserveInit, - ), - reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveInit), - reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveInit), + 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::vault_a_reserve_init(), + reserve_a: BalanceForTests::vault_a_reserve_init(), + reserve_b: BalanceForTests::vault_b_reserve_init(), fees: 0u128, active: true, }), nonce: 0, }, is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - _ => panic!("Invalid selection"), + account_id: IdForTests::pool_definition_id(), + } } } @@ -2375,12 +2163,12 @@ mod tests { assert!( compute_pool_pda( AMM_PROGRAM_ID, - helper_id_constructor(IdEnum::TokenADefinitionId), - helper_id_constructor(IdEnum::TokenBDefinitionId) + IdForTests::token_a_definition_id(), + IdForTests::token_b_definition_id() ) == compute_pool_pda( AMM_PROGRAM_ID, - helper_id_constructor(IdEnum::TokenBDefinitionId), - helper_id_constructor(IdEnum::TokenADefinitionId) + IdForTests::token_b_definition_id(), + IdForTests::token_a_definition_id() ) ); } @@ -2388,14 +2176,12 @@ mod tests { #[should_panic(expected = "Invalid number of input accounts")] #[test] fn test_call_new_definition_with_invalid_number_of_accounts_1() { - let pre_states = vec![helper_account_constructor( - AccountEnum::PoolDefinitionUninit, - )]; + let pre_states = vec![AccountForTests::pool_definition_uninit()]; let _post_states = new_definition( &pre_states, &[ - helper_balance_constructor(BalanceEnum::VaultAReserveInit), - helper_balance_constructor(BalanceEnum::VaultBReserveInit), + BalanceForTests::vault_a_reserve_init(), + BalanceForTests::vault_b_reserve_init(), ], AMM_PROGRAM_ID, ); @@ -2405,14 +2191,14 @@ mod tests { #[test] fn test_call_new_definition_with_invalid_number_of_accounts_2() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), ]; let _post_states = new_definition( &pre_states, &[ - helper_balance_constructor(BalanceEnum::VaultAReserveInit), - helper_balance_constructor(BalanceEnum::VaultBReserveInit), + BalanceForTests::vault_a_reserve_init(), + BalanceForTests::vault_b_reserve_init(), ], AMM_PROGRAM_ID, ); @@ -2420,17 +2206,17 @@ mod tests { #[should_panic(expected = "Invalid number of input accounts")] #[test] - fn test_call_new_definition__with_invalid_number_of_accounts_3() { + fn test_call_new_definition_with_invalid_number_of_accounts_3() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), ]; let _post_states = new_definition( &pre_states, &[ - helper_balance_constructor(BalanceEnum::VaultAReserveInit), - helper_balance_constructor(BalanceEnum::VaultBReserveInit), + BalanceForTests::vault_a_reserve_init(), + BalanceForTests::vault_b_reserve_init(), ], AMM_PROGRAM_ID, ); @@ -2438,18 +2224,18 @@ mod tests { #[should_panic(expected = "Invalid number of input accounts")] #[test] - fn test_call_new_definition__with_invalid_number_of_accounts_4() { + fn test_call_new_definition_with_invalid_number_of_accounts_4() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), ]; let _post_states = new_definition( &pre_states, &[ - helper_balance_constructor(BalanceEnum::VaultAReserveInit), - helper_balance_constructor(BalanceEnum::VaultBReserveInit), + BalanceForTests::vault_a_reserve_init(), + BalanceForTests::vault_b_reserve_init(), ], AMM_PROGRAM_ID, ); @@ -2457,19 +2243,19 @@ mod tests { #[should_panic(expected = "Invalid number of input accounts")] #[test] - fn test_call_new_definition__with_invalid_number_of_accounts_5() { + fn test_call_new_definition_with_invalid_number_of_accounts_5() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), ]; let _post_states = new_definition( &pre_states, &[ - helper_balance_constructor(BalanceEnum::VaultAReserveInit), - helper_balance_constructor(BalanceEnum::VaultBReserveInit), + BalanceForTests::vault_a_reserve_init(), + BalanceForTests::vault_b_reserve_init(), ], AMM_PROGRAM_ID, ); @@ -2479,18 +2265,18 @@ mod tests { #[test] fn test_call_new_definition_with_invalid_number_of_accounts_6() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), ]; let _post_states = new_definition( &pre_states, &[ - helper_balance_constructor(BalanceEnum::VaultAReserveInit), - helper_balance_constructor(BalanceEnum::VaultBReserveInit), + BalanceForTests::vault_a_reserve_init(), + BalanceForTests::vault_b_reserve_init(), ], AMM_PROGRAM_ID, ); @@ -2500,17 +2286,17 @@ mod tests { #[test] fn test_call_new_definition_with_invalid_number_of_balances() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPUninit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_uninit(), ]; let _post_states = new_definition( &pre_states, - &[helper_balance_constructor(BalanceEnum::VaultAReserveInit)], + &[BalanceForTests::vault_a_reserve_init()], AMM_PROGRAM_ID, ); } @@ -2519,20 +2305,17 @@ mod tests { #[test] fn test_call_new_definition_with_zero_balance_1() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPUninit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_uninit(), ]; let _post_states = new_definition( &pre_states, - &[ - 0, - helper_balance_constructor(BalanceEnum::VaultBReserveInit), - ], + &[0, BalanceForTests::vault_b_reserve_init()], AMM_PROGRAM_ID, ); } @@ -2541,20 +2324,17 @@ mod tests { #[test] fn test_call_new_definition_with_zero_balance_2() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPUninit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_uninit(), ]; let _post_states = new_definition( &pre_states, - &[ - helper_balance_constructor(BalanceEnum::VaultAReserveInit), - 0, - ], + &[BalanceForTests::vault_a_reserve_init(), 0], AMM_PROGRAM_ID, ); } @@ -2563,19 +2343,19 @@ mod tests { #[test] fn test_call_new_definition_same_token_definition() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingLPUninit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_lp_uninit(), ]; let _post_states = new_definition( &pre_states, &[ - helper_balance_constructor(BalanceEnum::VaultAReserveInit), - helper_balance_constructor(BalanceEnum::VaultBReserveInit), + BalanceForTests::vault_a_reserve_init(), + BalanceForTests::vault_b_reserve_init(), ], AMM_PROGRAM_ID, ); @@ -2585,19 +2365,19 @@ mod tests { #[test] fn test_call_new_definition_wrong_liquidity_id() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPWrongId), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPUninit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_with_wrong_id(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_uninit(), ]; let _post_states = new_definition( &pre_states, &[ - helper_balance_constructor(BalanceEnum::VaultAReserveInit), - helper_balance_constructor(BalanceEnum::VaultBReserveInit), + BalanceForTests::vault_a_reserve_init(), + BalanceForTests::vault_b_reserve_init(), ], AMM_PROGRAM_ID, ); @@ -2607,19 +2387,19 @@ mod tests { #[test] fn test_call_new_definition_wrong_pool_id() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionWrongId), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPUninit), + AccountForTests::pool_definition_with_wrong_id(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_uninit(), ]; let _post_states = new_definition( &pre_states, &[ - helper_balance_constructor(BalanceEnum::VaultAReserveInit), - helper_balance_constructor(BalanceEnum::VaultBReserveInit), + BalanceForTests::vault_a_reserve_init(), + BalanceForTests::vault_b_reserve_init(), ], AMM_PROGRAM_ID, ); @@ -2629,19 +2409,19 @@ mod tests { #[test] fn test_call_new_definition_wrong_vault_id_1() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAWrongId), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPUninit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_with_wrong_id(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_uninit(), ]; let _post_states = new_definition( &pre_states, &[ - helper_balance_constructor(BalanceEnum::VaultAReserveInit), - helper_balance_constructor(BalanceEnum::VaultBReserveInit), + BalanceForTests::vault_a_reserve_init(), + BalanceForTests::vault_b_reserve_init(), ], AMM_PROGRAM_ID, ); @@ -2651,19 +2431,19 @@ mod tests { #[test] fn test_call_new_definition_wrong_vault_id_2() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBWrongId), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPUninit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_with_wrong_id(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_uninit(), ]; let _post_states = new_definition( &pre_states, &[ - helper_balance_constructor(BalanceEnum::VaultAReserveInit), - helper_balance_constructor(BalanceEnum::VaultBReserveInit), + BalanceForTests::vault_a_reserve_init(), + BalanceForTests::vault_b_reserve_init(), ], AMM_PROGRAM_ID, ); @@ -2673,19 +2453,19 @@ mod tests { #[test] fn test_call_new_definition_cannot_initialize_active_pool() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionActive), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPUninit), + AccountForTests::pool_definition_active(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_uninit(), ]; let _post_states = new_definition( &pre_states, &[ - helper_balance_constructor(BalanceEnum::VaultAReserveInit), - helper_balance_constructor(BalanceEnum::VaultBReserveInit), + BalanceForTests::vault_a_reserve_init(), + BalanceForTests::vault_b_reserve_init(), ], AMM_PROGRAM_ID, ); @@ -2693,62 +2473,51 @@ mod tests { #[should_panic(expected = "Cannot initialize an active Pool Definition")] #[test] - fn test_call_new_definition_chain_call_successful() { + fn test_call_new_definition_chained_call_successful() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionActive), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPUninit), + AccountForTests::pool_definition_active(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_uninit(), ]; let (post_states, chained_calls) = new_definition( &pre_states, &[ - helper_balance_constructor(BalanceEnum::VaultAReserveInit), - helper_balance_constructor(BalanceEnum::VaultBReserveInit), + BalanceForTests::vault_a_reserve_init(), + BalanceForTests::vault_b_reserve_init(), ], AMM_PROGRAM_ID, ); let pool_post = post_states[0].clone(); - assert!( - helper_account_constructor(AccountEnum::PoolDefinitionAddSuccessful).account - == *pool_post.account() - ); + assert!(AccountForTests::pool_definition_add_successful().account == *pool_post.account()); let chained_call_lp = chained_calls[0].clone(); let chained_call_b = chained_calls[1].clone(); let chained_call_a = chained_calls[2].clone(); - assert!( - chained_call_a - == helper_chained_call_constructor(ChainedCallsEnum::CcNewDefinitionTokenA) - ); - assert!( - chained_call_b - == helper_chained_call_constructor(ChainedCallsEnum::CcNewDefinitionTokenB) - ); - assert!( - chained_call_lp == helper_chained_call_constructor(ChainedCallsEnum::CcNewDefinitionLP) - ); + assert!(chained_call_a == ChainedCallForTests::cc_new_definition_token_a()); + assert!(chained_call_b == ChainedCallForTests::cc_new_definition_token_b()); + assert!(chained_call_lp == ChainedCallForTests::cc_new_definition_token_lp()); } #[should_panic(expected = "Invalid number of input accounts")] #[test] fn test_call_remove_liquidity_with_invalid_number_of_accounts_2() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), ]; let _post_states = remove_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::RemoveAmountLP), - helper_balance_constructor(BalanceEnum::RemoveMinAmountA), - helper_balance_constructor(BalanceEnum::RemoveMinAmountB), + BalanceForTests::remove_amount_lp(), + BalanceForTests::remove_min_amount_a(), + BalanceForTests::remove_min_amount_b(), ], ); } @@ -2757,16 +2526,16 @@ mod tests { #[test] fn test_call_remove_liquidity_with_invalid_number_of_accounts_3() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), ]; let _post_states = remove_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::RemoveAmountLP), - helper_balance_constructor(BalanceEnum::RemoveMinAmountA), - helper_balance_constructor(BalanceEnum::RemoveMinAmountB), + BalanceForTests::remove_amount_lp(), + BalanceForTests::remove_min_amount_a(), + BalanceForTests::remove_min_amount_b(), ], ); } @@ -2775,17 +2544,17 @@ mod tests { #[test] fn test_call_remove_liquidity_with_invalid_number_of_accounts_4() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), ]; let _post_states = remove_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::RemoveAmountLP), - helper_balance_constructor(BalanceEnum::RemoveMinAmountA), - helper_balance_constructor(BalanceEnum::RemoveMinAmountB), + BalanceForTests::remove_amount_lp(), + BalanceForTests::remove_min_amount_a(), + BalanceForTests::remove_min_amount_b(), ], ); } @@ -2794,18 +2563,18 @@ mod tests { #[test] fn test_call_remove_liquidity_with_invalid_number_of_accounts_5() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), ]; let _post_states = remove_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::RemoveAmountLP), - helper_balance_constructor(BalanceEnum::RemoveMinAmountA), - helper_balance_constructor(BalanceEnum::RemoveMinAmountB), + BalanceForTests::remove_amount_lp(), + BalanceForTests::remove_min_amount_a(), + BalanceForTests::remove_min_amount_b(), ], ); } @@ -2814,19 +2583,19 @@ mod tests { #[test] fn test_call_remove_liquidity_with_invalid_number_of_accounts_6() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), ]; let _post_states = remove_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::RemoveAmountLP), - helper_balance_constructor(BalanceEnum::RemoveMinAmountA), - helper_balance_constructor(BalanceEnum::RemoveMinAmountB), + BalanceForTests::remove_amount_lp(), + BalanceForTests::remove_min_amount_a(), + BalanceForTests::remove_min_amount_b(), ], ); } @@ -2835,20 +2604,20 @@ mod tests { #[test] fn test_call_remove_liquidity_vault_a_omitted() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAWrongAccId), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_with_wrong_id(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = remove_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::RemoveAmountLP), - helper_balance_constructor(BalanceEnum::RemoveMinAmountA), - helper_balance_constructor(BalanceEnum::RemoveMinAmountB), + BalanceForTests::remove_amount_lp(), + BalanceForTests::remove_min_amount_a(), + BalanceForTests::remove_min_amount_b(), ], ); } @@ -2857,20 +2626,20 @@ mod tests { #[test] fn test_call_remove_liquidity_vault_b_omitted() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBWrongAccId), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_with_wrong_id(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = remove_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::RemoveAmountLP), - helper_balance_constructor(BalanceEnum::RemoveMinAmountA), - helper_balance_constructor(BalanceEnum::RemoveMinAmountB), + BalanceForTests::remove_amount_lp(), + BalanceForTests::remove_min_amount_a(), + BalanceForTests::remove_min_amount_b(), ], ); } @@ -2879,20 +2648,20 @@ mod tests { #[test] fn test_call_remove_liquidity_lp_def_mismatch() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPWrongAccId), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_with_wrong_id(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = remove_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::RemoveAmountLP), - helper_balance_constructor(BalanceEnum::RemoveMinAmountA), - helper_balance_constructor(BalanceEnum::RemoveMinAmountB), + BalanceForTests::remove_amount_lp(), + BalanceForTests::remove_min_amount_a(), + BalanceForTests::remove_min_amount_b(), ], ); } @@ -2901,22 +2670,21 @@ mod tests { #[test] fn test_call_remove_liquidity_insufficient_liquidity_amount() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingA), /* different token account - * than lp to create desired - * error */ + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_a(), /* different token account than lp to create + * desired error */ ]; let _post_states = remove_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::RemoveAmountLP), - helper_balance_constructor(BalanceEnum::RemoveMinAmountA), - helper_balance_constructor(BalanceEnum::RemoveMinAmountB), + BalanceForTests::remove_amount_lp(), + BalanceForTests::remove_min_amount_a(), + BalanceForTests::remove_min_amount_b(), ], ); } @@ -2927,20 +2695,20 @@ mod tests { #[test] fn test_call_remove_liquidity_insufficient_balance_1() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = remove_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::RemoveAmountLP1), - helper_balance_constructor(BalanceEnum::RemoveMinAmountA), - helper_balance_constructor(BalanceEnum::RemoveMinAmountB), + BalanceForTests::remove_amount_lp_1(), + BalanceForTests::remove_min_amount_a(), + BalanceForTests::remove_min_amount_b(), ], ); } @@ -2951,20 +2719,20 @@ mod tests { #[test] fn test_call_remove_liquidity_insufficient_balance_2() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = remove_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::RemoveAmountLP), - helper_balance_constructor(BalanceEnum::RemoveMinAmountA), - helper_balance_constructor(BalanceEnum::RemoveMinAmountB), + BalanceForTests::remove_amount_lp(), + BalanceForTests::remove_min_amount_a(), + BalanceForTests::remove_min_amount_b(), ], ); } @@ -2973,20 +2741,20 @@ mod tests { #[test] fn test_call_remove_liquidity_min_bal_zero_1() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = remove_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::RemoveAmountLP), + BalanceForTests::remove_amount_lp(), 0, - helper_balance_constructor(BalanceEnum::RemoveMinAmountB), + BalanceForTests::remove_min_amount_b(), ], ); } @@ -2995,19 +2763,19 @@ mod tests { #[test] fn test_call_remove_liquidity_min_bal_zero_2() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = remove_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::RemoveAmountLP), - helper_balance_constructor(BalanceEnum::RemoveMinAmountA), + BalanceForTests::remove_amount_lp(), + BalanceForTests::remove_min_amount_a(), 0, ], ); @@ -3017,20 +2785,20 @@ mod tests { #[test] fn test_call_remove_liquidity_lp_bal_zero() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = remove_liquidity( &pre_states, &[ 0, - helper_balance_constructor(BalanceEnum::RemoveMinAmountA), - helper_balance_constructor(BalanceEnum::RemoveMinAmountB), + BalanceForTests::remove_min_amount_a(), + BalanceForTests::remove_min_amount_b(), ], ); } @@ -3038,57 +2806,48 @@ mod tests { #[test] fn test_call_remove_liquidity_chained_call_successful() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let (post_states, chained_calls) = remove_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::RemoveAmountLP), - helper_balance_constructor(BalanceEnum::RemoveMinAmountA), - helper_balance_constructor(BalanceEnum::RemoveMinAmountBLow), + BalanceForTests::remove_amount_lp(), + BalanceForTests::remove_min_amount_a(), + BalanceForTests::remove_min_amount_b_low(), ], ); let pool_post = post_states[0].clone(); assert!( - helper_account_constructor(AccountEnum::PoolDefinitionRemoveSuccessful).account - == *pool_post.account() + AccountForTests::pool_definition_remove_successful().account == *pool_post.account() ); let chained_call_lp = chained_calls[0].clone(); let chained_call_b = chained_calls[1].clone(); let chained_call_a = chained_calls[2].clone(); - assert!( - chained_call_a == helper_chained_call_constructor(ChainedCallsEnum::CcRemoveTokenA) - ); - assert!( - chained_call_b == helper_chained_call_constructor(ChainedCallsEnum::CcRemoveTokenB) - ); - assert!( - chained_call_lp.instruction_data - == helper_chained_call_constructor(ChainedCallsEnum::CcRemovePoolLP) - .instruction_data - ); + assert!(chained_call_a == ChainedCallForTests::cc_remove_token_a()); + assert!(chained_call_b == ChainedCallForTests::cc_remove_token_b()); + assert!(chained_call_lp == ChainedCallForTests::cc_remove_pool_lp()); } #[should_panic(expected = "Invalid number of input accounts")] #[test] fn test_call_add_liquidity_with_invalid_number_of_accounts_1() { - let pre_states = vec![helper_account_constructor(AccountEnum::PoolDefinitionInit)]; + let pre_states = vec![AccountForTests::pool_definition_init()]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), ], ); } @@ -3097,15 +2856,15 @@ mod tests { #[test] fn test_call_add_liquidity_with_invalid_number_of_accounts_2() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), ], ); } @@ -3114,16 +2873,16 @@ mod tests { #[test] fn test_call_add_liquidity_with_invalid_number_of_accounts_3() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), ], ); } @@ -3132,17 +2891,17 @@ mod tests { #[test] fn test_call_add_liquidity_with_invalid_number_of_accounts_4() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), ], ); } @@ -3151,18 +2910,18 @@ mod tests { #[test] fn test_call_add_liquidity_with_invalid_number_of_accounts_5() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), ], ); } @@ -3171,19 +2930,19 @@ mod tests { #[test] fn test_call_add_liquidity_with_invalid_number_of_accounts_6() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), ], ); } @@ -3192,17 +2951,35 @@ mod tests { #[test] fn test_call_add_liquidity_invalid_number_of_balances_1() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), + ]; + let _post_states = add_liquidity(&pre_states, &[BalanceForTests::add_min_amount_lp()]); + } + + #[should_panic(expected = "Invalid number of input balances")] + #[test] + fn test_call_add_liquidity_invalid_number_of_balances_2() { + let pre_states = vec![ + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = add_liquidity( &pre_states, - &[helper_balance_constructor(BalanceEnum::AddMaxAmountA)], + &[ + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a(), + ], ); } @@ -3210,20 +2987,20 @@ mod tests { #[test] fn test_call_add_liquidity_vault_a_omitted() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAWrongAccId), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_with_wrong_id(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), ], ); } @@ -3232,42 +3009,42 @@ mod tests { #[test] fn test_call_add_liquidity_vault_b_omitted() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBWrongAccId), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_with_wrong_id(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), ], ); } #[should_panic(expected = "LP definition mismatch")] #[test] - fn test_call_add_liquidity_lp_def_mismatch() { + fn test_call_add_liquidity_lp_definition_mismatch() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPWrongAccId), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_with_wrong_id(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), ], ); } @@ -3276,20 +3053,20 @@ mod tests { #[test] fn test_call_add_liquidity_zero_balance_1() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_min_amount_lp(), 0, - helper_balance_constructor(BalanceEnum::AddMaxAmountb), + BalanceForTests::add_max_amount_b(), ], ); } @@ -3298,20 +3075,20 @@ mod tests { #[test] fn test_call_add_liquidity_zero_balance_2() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), + BalanceForTests::add_min_amount_lp(), 0, - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_max_amount_a(), ], ); } @@ -3320,20 +3097,20 @@ mod tests { #[test] fn test_call_add_liquidity_zero_min_lp() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = add_liquidity( &pre_states, &[ 0, - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), ], ); } @@ -3342,20 +3119,20 @@ mod tests { #[test] fn test_call_add_liquidity_vault_insufficient_balance_1() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInitZero), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init_zero(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), + BalanceForTests::add_min_amount_lp(), ], ); } @@ -3364,20 +3141,20 @@ mod tests { #[test] fn test_call_add_liquidity_vault_insufficient_balance_2() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInitZero), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init_zero(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), + BalanceForTests::add_min_amount_lp(), ], ); } @@ -3386,20 +3163,20 @@ mod tests { #[test] fn test_call_add_liquidity_actual_amount_zero_1() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInitReserveALow), - helper_account_constructor(AccountEnum::VaultAInitLow), - helper_account_constructor(AccountEnum::VaultBInitHigh), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init_reserve_a_low(), + AccountForTests::vault_a_init_low(), + AccountForTests::vault_b_init_high(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), ], ); } @@ -3408,20 +3185,20 @@ mod tests { #[test] fn test_call_add_liquidity_actual_amount_zero_2() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInitReserveBLow), - helper_account_constructor(AccountEnum::VaultAInitHigh), - helper_account_constructor(AccountEnum::VaultBInitLow), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init_reserve_b_low(), + AccountForTests::vault_a_init_high(), + AccountForTests::vault_b_init_low(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountALow), - helper_balance_constructor(BalanceEnum::AddMaxAmountBLow), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a_low(), + BalanceForTests::add_max_amount_b_low(), ], ); } @@ -3430,20 +3207,20 @@ mod tests { #[test] fn test_call_add_liquidity_reserves_zero_1() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInitReserveAZero), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init_reserve_a_zero(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), ], ); } @@ -3452,20 +3229,20 @@ mod tests { #[test] fn test_call_add_liquidity_reserves_zero_2() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInitReserveBZero), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init_reserve_b_zero(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), ], ); } @@ -3474,71 +3251,68 @@ mod tests { #[test] fn test_call_add_liquidity_payable_lp_zero() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionAddZeroLP), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_add_zero_lp(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let _post_states = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountALow), - helper_balance_constructor(BalanceEnum::AddMaxAmountBLow), - helper_balance_constructor(BalanceEnum::AddMinAmountLP), + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a_low(), + BalanceForTests::add_max_amount_b_low(), ], ); } #[test] - fn test_call_add_liquidity_successful_chain_call() { + fn test_call_add_liquidity_chained_call_successsful() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::PoolLPInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), - helper_account_constructor(AccountEnum::UserHoldingLPInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_init(), ]; let (post_states, chained_calls) = add_liquidity( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMinAmountLP), - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountb), + BalanceForTests::add_min_amount_lp(), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_b(), ], ); let pool_post = post_states[0].clone(); - assert!( - helper_account_constructor(AccountEnum::PoolDefinitionAddSuccessful).account - == *pool_post.account() - ); + assert!(AccountForTests::pool_definition_add_successful().account == *pool_post.account()); let chained_call_lp = chained_calls[0].clone(); let chained_call_b = chained_calls[1].clone(); let chained_call_a = chained_calls[2].clone(); - assert!(chained_call_a == helper_chained_call_constructor(ChainedCallsEnum::CcAddTokenA)); - assert!(chained_call_b == helper_chained_call_constructor(ChainedCallsEnum::CcAddTokenB)); - assert!(chained_call_lp == helper_chained_call_constructor(ChainedCallsEnum::CcAddPoolLP)); + assert!(chained_call_a == ChainedCallForTests::cc_add_token_a()); + assert!(chained_call_b == ChainedCallForTests::cc_add_token_b()); + assert!(chained_call_lp == ChainedCallForTests::cc_add_pool_lp()); } #[should_panic(expected = "Invalid number of input accounts")] #[test] fn test_call_swap_with_invalid_number_of_accounts_1() { - let pre_states = vec![helper_account_constructor(AccountEnum::PoolDefinitionInit)]; + let pre_states = vec![AccountForTests::pool_definition_init()]; let _post_states = swap( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::MinAmountOut), + BalanceForTests::add_max_amount_a(), + BalanceForTests::min_amount_out(), ], - helper_id_constructor(IdEnum::TokenADefinitionId), + IdForTests::token_a_definition_id(), ); } @@ -3546,16 +3320,16 @@ mod tests { #[test] fn test_call_swap_with_invalid_number_of_accounts_2() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), ]; let _post_states = swap( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::MinAmountOut), + BalanceForTests::add_max_amount_a(), + BalanceForTests::min_amount_out(), ], - helper_id_constructor(IdEnum::TokenADefinitionId), + IdForTests::token_a_definition_id(), ); } @@ -3563,17 +3337,17 @@ mod tests { #[test] fn test_call_swap_with_invalid_number_of_accounts_3() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), ]; let _post_states = swap( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::MinAmountOut), + BalanceForTests::add_max_amount_a(), + BalanceForTests::min_amount_out(), ], - helper_id_constructor(IdEnum::TokenADefinitionId), + IdForTests::token_a_definition_id(), ); } @@ -3581,18 +3355,18 @@ mod tests { #[test] fn test_call_swap_with_invalid_number_of_accounts_4() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::UserHoldingA), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::user_holding_a(), ]; let _post_states = swap( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::MinAmountOut), + BalanceForTests::add_max_amount_a(), + BalanceForTests::min_amount_out(), ], - helper_id_constructor(IdEnum::TokenADefinitionId), + IdForTests::token_a_definition_id(), ); } @@ -3600,16 +3374,16 @@ mod tests { #[test] fn test_call_swap_with_invalid_number_of_amounts() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), ]; let _post_states = swap( &pre_states, - &[helper_balance_constructor(BalanceEnum::AddMaxAmountA)], - helper_id_constructor(IdEnum::TokenLPDefinitionId), + &[BalanceForTests::add_max_amount_a()], + IdForTests::token_a_definition_id(), ); } @@ -3617,19 +3391,19 @@ mod tests { #[test] fn test_call_swap_incorrect_token_type() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), ]; let _post_states = swap( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::MinAmountOut), + BalanceForTests::add_max_amount_a(), + BalanceForTests::min_amount_out(), ], - helper_id_constructor(IdEnum::TokenLPDefinitionId), + IdForTests::token_lp_definition_id(), ); } @@ -3637,19 +3411,19 @@ mod tests { #[test] fn test_call_swap_vault_a_omitted() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAWrongAccId), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_with_wrong_id(), + AccountForTests::vault_b_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), ]; let _post_states = swap( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::MinAmountOut), + BalanceForTests::add_max_amount_a(), + BalanceForTests::min_amount_out(), ], - helper_id_constructor(IdEnum::TokenADefinitionId), + IdForTests::token_a_definition_id(), ); } @@ -3657,19 +3431,19 @@ mod tests { #[test] fn test_call_swap_vault_b_omitted() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBWrongAccId), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_with_wrong_id(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), ]; let _post_states = swap( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::MinAmountOut), + BalanceForTests::add_max_amount_a(), + BalanceForTests::min_amount_out(), ], - helper_id_constructor(IdEnum::TokenADefinitionId), + IdForTests::token_a_definition_id(), ); } @@ -3677,19 +3451,19 @@ mod tests { #[test] fn test_call_swap_reserves_vault_mismatch_1() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInitLow), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init_low(), + AccountForTests::vault_b_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), ]; let _post_states = swap( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::MinAmountOut), + BalanceForTests::add_max_amount_a(), + BalanceForTests::min_amount_out(), ], - helper_id_constructor(IdEnum::TokenADefinitionId), + IdForTests::token_a_definition_id(), ); } @@ -3697,19 +3471,19 @@ mod tests { #[test] fn test_call_swap_reserves_vault_mismatch_2() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInitLow), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init_low(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), ]; let _post_states = swap( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::MinAmountOut), + BalanceForTests::add_max_amount_a(), + BalanceForTests::min_amount_out(), ], - helper_id_constructor(IdEnum::TokenADefinitionId), + IdForTests::token_a_definition_id(), ); } @@ -3717,19 +3491,19 @@ mod tests { #[test] fn test_call_swap_ianctive() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInactive), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), + AccountForTests::pool_definition_inactive(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), ]; let _post_states = swap( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::MinAmountOut), + BalanceForTests::add_max_amount_a(), + BalanceForTests::min_amount_out(), ], - helper_id_constructor(IdEnum::TokenADefinitionId), + IdForTests::token_a_definition_id(), ); } @@ -3737,91 +3511,77 @@ mod tests { #[test] fn test_call_swap_below_min_out() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), ]; let _post_states = swap( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::MinAmountOut), + BalanceForTests::add_max_amount_a(), + BalanceForTests::min_amount_out(), ], - helper_id_constructor(IdEnum::TokenADefinitionId), + IdForTests::token_a_definition_id(), ); } #[test] - fn test_call_swap_successful_chain_call_1() { + fn test_call_swap_chained_call_successful_1() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), ]; let (post_states, chained_calls) = swap( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountA), - helper_balance_constructor(BalanceEnum::AddMaxAmountALow), + BalanceForTests::add_max_amount_a(), + BalanceForTests::add_max_amount_a_low(), ], - helper_id_constructor(IdEnum::TokenADefinitionId), + IdForTests::token_a_definition_id(), ); let pool_post = post_states[0].clone(); - assert!( - helper_account_constructor(AccountEnum::PoolDefinitionSwapTest1).account - == *pool_post.account() - ); + assert!(AccountForTests::pool_definition_swap_test_1().account == *pool_post.account()); let chained_call_a = chained_calls[0].clone(); let chained_call_b = chained_calls[1].clone(); - assert!( - chained_call_a == helper_chained_call_constructor(ChainedCallsEnum::CcSwapTokenATest1) - ); - assert!( - chained_call_b == helper_chained_call_constructor(ChainedCallsEnum::CcSwapTokenBTest1) - ); + assert!(chained_call_a == ChainedCallForTests::cc_swap_token_a_test_1()); + assert!(chained_call_b == ChainedCallForTests::cc_swap_token_b_test_1()); } #[test] - fn test_call_swap_successful_chain_call_2() { + fn test_call_swap_chained_call_successful_2() { let pre_states = vec![ - helper_account_constructor(AccountEnum::PoolDefinitionInit), - helper_account_constructor(AccountEnum::VaultAInit), - helper_account_constructor(AccountEnum::VaultBInit), - helper_account_constructor(AccountEnum::UserHoldingA), - helper_account_constructor(AccountEnum::UserHoldingB), + AccountForTests::pool_definition_init(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), ]; let (post_states, chained_calls) = swap( &pre_states, &[ - helper_balance_constructor(BalanceEnum::AddMaxAmountb), - helper_balance_constructor(BalanceEnum::MinAmountOut), + BalanceForTests::add_max_amount_b(), + BalanceForTests::min_amount_out(), ], - helper_id_constructor(IdEnum::TokenBDefinitionId), + IdForTests::token_b_definition_id(), ); let pool_post = post_states[0].clone(); - assert!( - helper_account_constructor(AccountEnum::PoolDefinitionSwapTest2).account - == *pool_post.account() - ); + assert!(AccountForTests::pool_definition_swap_test_2().account == *pool_post.account()); let chained_call_a = chained_calls[1].clone(); let chained_call_b = chained_calls[0].clone(); - assert!( - chained_call_a == helper_chained_call_constructor(ChainedCallsEnum::CcSwapTokenATest2) - ); - assert!( - chained_call_b == helper_chained_call_constructor(ChainedCallsEnum::CcSwapTokenBTest2) - ); + assert!(chained_call_a == ChainedCallForTests::cc_swap_token_a_test_2()); + assert!(chained_call_b == ChainedCallForTests::cc_swap_token_b_test_2()); } } diff --git a/program_methods/guest/src/bin/pinata_token.rs b/program_methods/guest/src/bin/pinata_token.rs index f988be9..0461379 100644 --- a/program_methods/guest/src/bin/pinata_token.rs +++ b/program_methods/guest/src/bin/pinata_token.rs @@ -82,7 +82,7 @@ fn main() { let winner_token_holding_post = winner_token_holding.account.clone(); pinata_definition_post.data = data.next_data(); - let mut instruction_data: [u8; 23] = [0; 23]; + let mut instruction_data = vec![0; 23]; instruction_data[0] = 1; instruction_data[1..17].copy_from_slice(&PRIZE.to_le_bytes()); diff --git a/program_methods/guest/src/bin/token.rs b/program_methods/guest/src/bin/token.rs index 3fdfc7a..0f7b628 100644 --- a/program_methods/guest/src/bin/token.rs +++ b/program_methods/guest/src/bin/token.rs @@ -36,17 +36,115 @@ use nssa_core::{ // * An instruction data byte string of length 23, indicating the balance to mint with the // folloiwng layout // [0x04 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. +// 6. New token definition with metadata. Arguments to this function are: +// * Three **default** accounts: [definition_account, metadata_account. holding_account]. The +// first default account will be initialized with the token definition account values. The +// second account will be initialized to a token metadata account for the new token +// definition. The third account will be initialized to a token holding account for the new +// token, holding the entire total supply. +// * An instruction data of 474-bytes, indicating the token name, total supply, token standard, +// metadata standard and metadata_values (uri and creators). the following layout: [0x05 || +// total_supply (little-endian 16 bytes) || name (6 bytes) || token_standard || +// metadata_standard || metadata_values] The name cannot be equal to [0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00] +// 7. Print NFT copy from Master NFT Arguments to this function are: +// * Two accounts: [master_nft, printed_account (default)]. +// * Authorization required: master_nft +// * An dummy byte string of length 23, with the following layout [0x06 || 0x00 || 0x00 || 0x00 +// || ... || 0x00 || 0x00]. +const TOKEN_STANDARD_FUNGIBLE_TOKEN: u8 = 0; +const TOKEN_STANDARD_FUNGIBLE_ASSET: u8 = 1; +const TOKEN_STANDARD_NONFUNGIBLE: u8 = 2; +const TOKEN_STANDARD_NONFUNGIBLE_PRINTABLE: u8 = 3; -const TOKEN_DEFINITION_TYPE: u8 = 0; -const TOKEN_DEFINITION_DATA_SIZE: usize = 23; +const METADATA_TYPE_SIMPLE: u8 = 0; +const METADATA_TYPE_EXPANDED: u8 = 1; + +const TOKEN_DEFINITION_DATA_SIZE: usize = 55; + +const TOKEN_HOLDING_STANDARD: u8 = 1; +const TOKEN_HOLDING_NFT_MASTER: u8 = 2; +const TOKEN_HOLDING_NFT_PRINTED_COPY: u8 = 3; -const TOKEN_HOLDING_TYPE: u8 = 1; const TOKEN_HOLDING_DATA_SIZE: usize = 49; +const CURRENT_VERSION: u8 = 1; + +const TOKEN_METADATA_DATA_SIZE: usize = 463; + +fn is_token_standard_valid(standard: u8) -> bool { + matches!( + standard, + TOKEN_STANDARD_FUNGIBLE_TOKEN + | TOKEN_STANDARD_FUNGIBLE_ASSET + | TOKEN_STANDARD_NONFUNGIBLE + | TOKEN_STANDARD_NONFUNGIBLE_PRINTABLE + ) +} + +fn is_metadata_type_valid(standard: u8) -> bool { + matches!(standard, METADATA_TYPE_SIMPLE | METADATA_TYPE_EXPANDED) +} + +fn is_token_holding_type_valid(standard: u8) -> bool { + matches!(standard, |TOKEN_HOLDING_STANDARD| TOKEN_HOLDING_NFT_MASTER + | TOKEN_HOLDING_NFT_PRINTED_COPY) +} struct TokenDefinition { account_type: u8, name: [u8; 6], total_supply: u128, + metadata_id: AccountId, +} + +impl TokenDefinition { + fn into_data(self) -> Data { + let mut bytes = Vec::::new(); + bytes.extend_from_slice(&[self.account_type]); + bytes.extend_from_slice(&self.name); + bytes.extend_from_slice(&self.total_supply.to_le_bytes()); + bytes.extend_from_slice(&self.metadata_id.to_bytes()); + + if bytes.len() != TOKEN_DEFINITION_DATA_SIZE { + panic!("Invalid Token Definition data"); + } + + Data::try_from(bytes).expect("Token definition data size must fit into data") + } + + fn parse(data: &Data) -> Option { + let data = Vec::::from(data.clone()); + + if data.len() != TOKEN_DEFINITION_DATA_SIZE { + None + } else { + let account_type = data[0]; + let name = data[1..7].try_into().expect("Name must be a 6 bytes"); + let total_supply = u128::from_le_bytes( + data[7..23] + .try_into() + .expect("Total supply must be 16 bytes little-endian"), + ); + let metadata_id = AccountId::new( + data[23..TOKEN_DEFINITION_DATA_SIZE] + .try_into() + .expect("Token Program expects valid Account Id for Metadata"), + ); + + let this = Some(Self { + account_type, + name, + total_supply, + metadata_id, + }); + + match account_type { + TOKEN_STANDARD_NONFUNGIBLE if total_supply != 1 => None, + TOKEN_STANDARD_FUNGIBLE_TOKEN if metadata_id != AccountId::new([0; 32]) => None, + _ => this, + } + } + } } struct TokenHolding { @@ -55,49 +153,24 @@ struct TokenHolding { balance: u128, } -impl TokenDefinition { - fn into_data(self) -> Data { - let mut bytes = [0; TOKEN_DEFINITION_DATA_SIZE]; - bytes[0] = self.account_type; - bytes[1..7].copy_from_slice(&self.name); - bytes[7..].copy_from_slice(&self.total_supply.to_le_bytes()); - bytes - .to_vec() - .try_into() - .expect("23 bytes should fit into Data") - } - - 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() - .expect("Total supply must be 16 bytes little-endian"), - ); - Some(Self { - account_type, - name, - total_supply, - }) - } - } -} - impl TokenHolding { - fn new(definition_id: AccountId) -> Self { + fn new(definition_id: &AccountId) -> Self { Self { - account_type: TOKEN_HOLDING_TYPE, - definition_id, + account_type: TOKEN_HOLDING_STANDARD, + definition_id: *definition_id, balance: 0, } } - fn parse(data: &[u8]) -> Option { - if data.len() != TOKEN_HOLDING_DATA_SIZE || data[0] != TOKEN_HOLDING_TYPE { + fn parse(data: &Data) -> Option { + let data = Vec::::from(data.clone()); + + if data.len() != TOKEN_HOLDING_DATA_SIZE { + return None; + } + + // Check account_type + if !is_token_holding_type_valid(data[0]) { return None; } @@ -112,6 +185,7 @@ impl TokenHolding { .try_into() .expect("balance must be 16 bytes little-endian"), ); + Some(Self { definition_id, balance, @@ -120,14 +194,52 @@ impl TokenHolding { } fn into_data(self) -> Data { - let mut bytes = [0; TOKEN_HOLDING_DATA_SIZE]; - bytes[0] = self.account_type; - bytes[1..33].copy_from_slice(&self.definition_id.to_bytes()); - bytes[33..].copy_from_slice(&self.balance.to_le_bytes()); - bytes - .to_vec() - .try_into() - .expect("33 bytes should fit into Data") + if !is_token_holding_type_valid(self.account_type) { + panic!("Invalid Token Holding type"); + } + + let mut bytes = Vec::::new(); + bytes.extend_from_slice(&[self.account_type]); + bytes.extend_from_slice(&self.definition_id.to_bytes()); + bytes.extend_from_slice(&self.balance.to_le_bytes()); + + if bytes.len() != TOKEN_HOLDING_DATA_SIZE { + panic!("Invalid Token Holding data"); + } + + Data::try_from(bytes).expect("Invalid data") + } +} + +struct TokenMetadata { + account_type: u8, + version: u8, + definition_id: AccountId, + uri: [u8; 200], + creators: [u8; 250], + /// Block id + primary_sale_date: u64, +} + +impl TokenMetadata { + fn into_data(self) -> Data { + if !is_metadata_type_valid(self.account_type) { + panic!("Invalid Metadata type"); + } + + let mut bytes = Vec::::new(); + bytes.extend_from_slice(&[self.account_type]); + bytes.extend_from_slice(&[self.version]); + bytes.extend_from_slice(&self.definition_id.to_bytes()); + bytes.extend_from_slice(&self.uri); + bytes.extend_from_slice(&self.creators); + bytes.extend_from_slice(&self.primary_sale_date.to_le_bytes()); + + if bytes.len() != TOKEN_METADATA_DATA_SIZE { + panic!("Invalid Token Definition data length"); + } + + Data::try_from(bytes).expect("Invalid data") } } @@ -138,10 +250,14 @@ fn transfer(pre_states: &[AccountWithMetadata], balance_to_move: u128) -> Vec Vec Vec (TokenHolding, TokenHolding) { + let mut sender_holding = sender_holding; + let mut recipient_holding = recipient_holding; + + if sender_holding.balance < balance_to_move { + panic!("Insufficient balance"); + } + + sender_holding.balance = sender_holding + .balance + .checked_sub(balance_to_move) + .expect("Checked above"); + recipient_holding.balance = recipient_holding + .balance + .checked_add(balance_to_move) + .expect("Recipient balance overflow"); + + recipient_holding.account_type = sender_holding.account_type; + + (sender_holding, recipient_holding) +} + +fn nft_master_transfer( + sender_holding: TokenHolding, + recipient_holding: TokenHolding, + balance_to_move: u128, +) -> (TokenHolding, TokenHolding) { + let mut sender_holding = sender_holding; + let mut recipient_holding = recipient_holding; + + if recipient_holding.balance != 0 { + panic!("Invalid balance in recipient account for NFT transfer"); + } + + if sender_holding.balance != balance_to_move { + panic!("Invalid balance for NFT Master transfer"); + } + + sender_holding.balance = 0; + recipient_holding.balance = balance_to_move; + recipient_holding.account_type = sender_holding.account_type; + + (sender_holding, recipient_holding) +} + fn new_definition( pre_states: &[AccountWithMetadata], name: [u8; 6], @@ -193,6 +351,7 @@ fn new_definition( if pre_states.len() != 2 { panic!("Invalid number of input accounts"); } + let definition_target_account = &pre_states[0]; let holding_target_account = &pre_states[1]; @@ -205,13 +364,14 @@ fn new_definition( } let token_definition = TokenDefinition { - account_type: TOKEN_DEFINITION_TYPE, + account_type: TOKEN_STANDARD_FUNGIBLE_TOKEN, name, total_supply, + metadata_id: AccountId::new([0; 32]), }; let token_holding = TokenHolding { - account_type: TOKEN_HOLDING_TYPE, + account_type: TOKEN_HOLDING_STANDARD, definition_id: definition_target_account.account_id, balance: total_supply, }; @@ -228,6 +388,99 @@ fn new_definition( ] } +fn new_definition_with_metadata( + pre_states: &[AccountWithMetadata], + name: [u8; 6], + total_supply: u128, + token_standard: u8, + metadata_standard: u8, + metadata_values: &Data, +) -> Vec { + if pre_states.len() != 3 { + panic!("Invalid number of input accounts"); + } + + let definition_target_account = &pre_states[0]; + let metadata_target_account = &pre_states[1]; + let holding_target_account = &pre_states[2]; + + if definition_target_account.account != Account::default() { + panic!("Definition target account must have default values"); + } + + if metadata_target_account.account != Account::default() { + panic!("Metadata target account must have default values"); + } + + if holding_target_account.account != Account::default() { + panic!("Holding target account must have default values"); + } + + if !is_token_standard_valid(token_standard) { + panic!("Invalid Token Standard provided"); + } + + if !is_metadata_type_valid(metadata_standard) { + panic!("Invalid Metadata Standadard provided"); + } + + if !valid_total_supply_for_token_standard(total_supply, token_standard) { + panic!("Invalid total supply for the specified token supply"); + } + + let token_definition = TokenDefinition { + account_type: token_standard, + name, + total_supply, + metadata_id: metadata_target_account.account_id, + }; + + let token_holding = TokenHolding { + account_type: TOKEN_HOLDING_STANDARD, + definition_id: definition_target_account.account_id, + balance: total_supply, + }; + + if metadata_values.len() != 450 { + panic!("Metadata values data should be 450 bytes"); + } + + let uri: [u8; 200] = metadata_values[0..200] + .try_into() + .expect("Token program expects valid uri for Metadata"); + let creators: [u8; 250] = metadata_values[200..450] + .try_into() + .expect("Token program expects valid creators for Metadata"); + + let token_metadata = TokenMetadata { + account_type: metadata_standard, + version: CURRENT_VERSION, + definition_id: definition_target_account.account_id, + uri, + creators, + primary_sale_date: 0u64, // TODO #261: future works to implement this + }; + + let mut definition_target_account_post = definition_target_account.account.clone(); + definition_target_account_post.data = token_definition.into_data(); + + let mut holding_target_account_post = holding_target_account.account.clone(); + holding_target_account_post.data = token_holding.into_data(); + + let mut metadata_target_account_post = metadata_target_account.account.clone(); + metadata_target_account_post.data = token_metadata.into_data(); + + vec![ + AccountPostState::new_claimed(definition_target_account_post), + AccountPostState::new_claimed(holding_target_account_post), + AccountPostState::new_claimed(metadata_target_account_post), + ] +} + +fn valid_total_supply_for_token_standard(total_supply: u128, token_standard: u8) -> bool { + token_standard != TOKEN_STANDARD_NONFUNGIBLE || total_supply == 1 +} + fn initialize_account(pre_states: &[AccountWithMetadata]) -> Vec { if pre_states.len() != 2 { panic!("Invalid number of accounts"); @@ -246,7 +499,7 @@ fn initialize_account(pre_states: &[AccountWithMetadata]) -> Vec Vec Vec Vec bool { + account_type != TOKEN_STANDARD_NONFUNGIBLE +} + fn mint_additional_supply( pre_states: &[AccountWithMetadata], amount_to_mint: u128, @@ -329,13 +587,17 @@ fn mint_additional_supply( TokenDefinition::parse(&definition.account.data).expect("Definition account must be valid"); let token_holding_values: TokenHolding = if token_holding.account == Account::default() { - TokenHolding::new(definition.account_id) + TokenHolding::new(&definition.account_id) } else { TokenHolding::parse(&token_holding.account.data).expect("Holding account must be valid") }; + if !is_mintable(definition_values.account_type) { + panic!("Token Definition's standard does not permit minting additional supply"); + } + if definition.account_id != token_holding_values.definition_id { - panic!("Mismatch token definition and token holding"); + panic!("Mismatch Token Definition and Token Holding"); } let token_holding_post_data = TokenHolding { @@ -356,6 +618,7 @@ fn mint_additional_supply( account_type: definition_values.account_type, name: definition_values.name, total_supply: post_total_supply, + metadata_id: definition_values.metadata_id, }; let post_definition = { @@ -378,7 +641,60 @@ fn mint_additional_supply( vec![post_definition, token_holding_post] } -type Instruction = [u8; 23]; +fn print_nft(pre_states: &[AccountWithMetadata]) -> Vec { + if pre_states.len() != 2 { + panic!("Invalid number of accounts"); + } + + let master_account = &pre_states[0]; + let printed_account = &pre_states[1]; + + if !master_account.is_authorized { + panic!("Master NFT Account must be authorized"); + } + + if printed_account.account != Account::default() { + panic!("Printed Account must be uninitialized"); + } + + let mut master_account_data = + TokenHolding::parse(&master_account.account.data).expect("Invalid Token Holding data"); + + if master_account_data.account_type != TOKEN_HOLDING_NFT_MASTER { + panic!("Invalid Token Holding provided as NFT Master Account"); + } + + if master_account_data.balance < 2 { + panic!("Insufficient balance to print another NFT copy"); + } + + let definition_id = master_account_data.definition_id; + + let post_master_account = { + let mut this = master_account.account.clone(); + master_account_data.balance -= 1; + this.data = master_account_data.into_data(); + AccountPostState::new(this) + }; + + let post_printed_account = { + let mut this = printed_account.account.clone(); + + let printed_data = TokenHolding { + account_type: TOKEN_HOLDING_NFT_PRINTED_COPY, + definition_id, + balance: 1, + }; + + this.data = TokenHolding::into_data(printed_data); + + AccountPostState::new_claimed(this) + }; + + vec![post_master_account, post_printed_account] +} + +type Instruction = Vec; fn main() { let ( @@ -455,6 +771,48 @@ fn main() { // Execute mint_additional_supply(&pre_states, balance_to_mint) } + 5 => { + if instruction.len() != 474 { + panic!("Invalid instruction length") + } + + // Parse instruction + let total_supply = u128::from_le_bytes( + instruction[1..17] + .try_into() + .expect("Total supply must be 16 bytes little-endian"), + ); + let name = instruction[17..23] + .try_into() + .expect("Name must be 6 bytes long"); + assert_ne!(name, [0; 6]); + let token_standard = instruction[23]; + let metadata_standard = instruction[24]; + let metadata_values: Data = + Data::try_from(instruction[25..474].to_vec()).expect("Invalid metadata"); + + // Execute + new_definition_with_metadata( + &pre_states, + name, + total_supply, + token_standard, + metadata_standard, + &metadata_values, + ) + } + 6 => { + if instruction.len() != 23 { + panic!("Invalid instruction length"); + } + + // Initialize account + if instruction[1..] != [0; 22] { + panic!("Invalid instruction for initialize account"); + } + + print_nft(&pre_states) + } _ => panic!("Invalid instruction"), }; @@ -463,14 +821,545 @@ fn main() { #[cfg(test)] mod tests { - use nssa_core::account::{Account, AccountId, AccountWithMetadata}; + use nssa_core::account::{Account, AccountId, AccountWithMetadata, Data}; use crate::{ - TOKEN_DEFINITION_DATA_SIZE, TOKEN_DEFINITION_TYPE, TOKEN_HOLDING_DATA_SIZE, - TOKEN_HOLDING_TYPE, TokenDefinition, TokenHolding, burn, initialize_account, - mint_additional_supply, new_definition, transfer, + TOKEN_DEFINITION_DATA_SIZE, TOKEN_HOLDING_DATA_SIZE, TOKEN_HOLDING_NFT_MASTER, + TOKEN_HOLDING_NFT_PRINTED_COPY, TOKEN_HOLDING_STANDARD, TOKEN_STANDARD_FUNGIBLE_TOKEN, + TOKEN_STANDARD_NONFUNGIBLE, TokenDefinition, TokenHolding, burn, mint_additional_supply, + new_definition, new_definition_with_metadata, print_nft, transfer, }; + struct BalanceForTests; + struct IdForTests; + + struct AccountForTests; + + impl AccountForTests { + fn definition_account_auth() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenDefinition::into_data(TokenDefinition { + account_type: TOKEN_STANDARD_FUNGIBLE_TOKEN, + name: [2; 6], + total_supply: BalanceForTests::init_supply(), + metadata_id: AccountId::new([0; 32]), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::pool_definition_id(), + } + } + + fn definition_account_without_auth() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenDefinition::into_data(TokenDefinition { + account_type: TOKEN_STANDARD_FUNGIBLE_TOKEN, + name: [2; 6], + total_supply: BalanceForTests::init_supply(), + metadata_id: AccountId::new([0; 32]), + }), + nonce: 0, + }, + is_authorized: false, + account_id: IdForTests::pool_definition_id(), + } + } + + fn holding_different_definition() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_STANDARD, + definition_id: IdForTests::pool_definition_id_diff(), + balance: BalanceForTests::holding_balance(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn holding_same_definition_with_authorization() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_STANDARD, + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::holding_balance(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn holding_same_definition_without_authorization() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_STANDARD, + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::holding_balance(), + }), + nonce: 0, + }, + is_authorized: false, + account_id: IdForTests::holding_id(), + } + } + + fn holding_same_definition_without_authorization_overflow() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_STANDARD, + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::init_supply(), + }), + nonce: 0, + }, + is_authorized: false, + account_id: IdForTests::holding_id(), + } + } + + fn definition_account_post_burn() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenDefinition::into_data(TokenDefinition { + account_type: TOKEN_STANDARD_FUNGIBLE_TOKEN, + name: [2; 6], + total_supply: BalanceForTests::init_supply_burned(), + metadata_id: AccountId::new([0; 32]), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::pool_definition_id(), + } + } + + fn holding_account_post_burn() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_STANDARD, + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::holding_balance_burned(), + }), + nonce: 0, + }, + is_authorized: false, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account_uninit() -> AccountWithMetadata { + AccountWithMetadata { + account: Account::default(), + is_authorized: false, + account_id: IdForTests::holding_id_2(), + } + } + + fn init_mint() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [0u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_STANDARD, + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::mint_success(), + }), + nonce: 0, + }, + is_authorized: false, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account_same_definition_mint() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_STANDARD, + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::holding_balance_mint(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::pool_definition_id(), + } + } + + fn definition_account_mint() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenDefinition::into_data(TokenDefinition { + account_type: TOKEN_STANDARD_FUNGIBLE_TOKEN, + name: [2; 6], + total_supply: BalanceForTests::init_supply_mint(), + metadata_id: AccountId::new([0; 32]), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::pool_definition_id(), + } + } + + fn holding_same_definition_with_authorization_and_large_balance() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_STANDARD, + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::mint_overflow(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::pool_definition_id(), + } + } + + fn definition_account_with_authorization_nonfungible() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenDefinition::into_data(TokenDefinition { + account_type: TOKEN_STANDARD_NONFUNGIBLE, + name: [2; 6], + total_supply: 1, + metadata_id: AccountId::new([0; 32]), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::pool_definition_id(), + } + } + + fn definition_account_uninit() -> AccountWithMetadata { + AccountWithMetadata { + account: Account::default(), + is_authorized: false, + account_id: IdForTests::pool_definition_id(), + } + } + + fn holding_account_init() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_STANDARD, + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::init_supply(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn definition_account_unclaimed() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [0u32; 8], + balance: 0u128, + data: TokenDefinition::into_data(TokenDefinition { + account_type: TOKEN_STANDARD_FUNGIBLE_TOKEN, + name: [2; 6], + total_supply: BalanceForTests::init_supply(), + metadata_id: AccountId::new([0; 32]), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::pool_definition_id(), + } + } + + fn holding_account_unclaimed() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [0u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_STANDARD, + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::init_supply(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account2_init() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_STANDARD, + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::init_supply(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id_2(), + } + } + + fn holding_account2_init_post_transfer() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_STANDARD, + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::recipient_post_transfer(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id_2(), + } + } + + fn holding_account_init_post_transfer() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_STANDARD, + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::sender_post_transfer(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account_master_nft() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_NFT_MASTER, + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::printable_copies(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account_master_nft_insufficient_balance() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_NFT_MASTER, + definition_id: IdForTests::pool_definition_id(), + balance: 1, + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account_master_nft_after_print() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_NFT_MASTER, + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::printable_copies() - 1, + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account_printed_nft() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [0u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_NFT_PRINTED_COPY, + definition_id: IdForTests::pool_definition_id(), + balance: 1, + }), + nonce: 0, + }, + is_authorized: false, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account_with_master_nft_transferred_to() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [0u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_NFT_MASTER, + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::printable_copies(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id_2(), + } + } + + fn holding_account_master_nft_post_transfer() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: TokenHolding::into_data(TokenHolding { + account_type: TOKEN_HOLDING_NFT_MASTER, + definition_id: IdForTests::pool_definition_id(), + balance: 0, + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + } + + impl BalanceForTests { + fn init_supply() -> u128 { + 100_000 + } + + fn holding_balance() -> u128 { + 1_000 + } + + fn init_supply_burned() -> u128 { + 99_500 + } + + fn holding_balance_burned() -> u128 { + 500 + } + + fn burn_success() -> u128 { + 500 + } + + fn burn_insufficient() -> u128 { + 1_500 + } + + fn mint_success() -> u128 { + 50_000 + } + + fn holding_balance_mint() -> u128 { + 51_000 + } + + fn mint_overflow() -> u128 { + u128::MAX - 40_000 + } + + fn init_supply_mint() -> u128 { + 150_000 + } + + fn sender_post_transfer() -> u128 { + 95_000 + } + + fn recipient_post_transfer() -> u128 { + 105_000 + } + + fn transfer_amount() -> u128 { + 5_000 + } + + fn printable_copies() -> u128 { + 10 + } + } + + impl IdForTests { + fn pool_definition_id() -> AccountId { + AccountId::new([15; 32]) + } + + fn pool_definition_id_diff() -> AccountId { + AccountId::new([16; 32]) + } + + fn holding_id() -> AccountId { + AccountId::new([17; 32]) + } + + fn holding_id_2() -> AccountId { + AccountId::new([42; 32]) + } + } + #[should_panic(expected = "Invalid number of input accounts")] #[test] fn test_call_new_definition_with_invalid_number_of_accounts_1() { @@ -550,40 +1439,19 @@ mod tests { #[test] fn test_new_definition_with_valid_inputs_succeeds() { let pre_states = vec![ - AccountWithMetadata { - account: Account::default(), - is_authorized: false, - account_id: AccountId::new([ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - ]), - }, - AccountWithMetadata { - account: Account { - ..Account::default() - }, - is_authorized: false, - account_id: AccountId::new([2; 32]), - }, + AccountForTests::definition_account_uninit(), + AccountForTests::holding_account_uninit(), ]; - let post_states = new_definition(&pre_states, [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe], 10); + let post_states = new_definition(&pre_states, [2u8; 6], BalanceForTests::init_supply()); + let [definition_account, holding_account] = post_states.try_into().ok().unwrap(); - assert_eq!( - definition_account.account().data.as_ref(), - &[ - 0, 0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0 - ] - ); - assert_eq!( - holding_account.account().data.as_ref(), - &[ - 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0 - ] + assert!( + *definition_account.account() + == AccountForTests::definition_account_unclaimed().account ); + + assert!(*holding_account.account() == AccountForTests::holding_account_unclaimed().account); } #[should_panic(expected = "Invalid number of input accounts")] @@ -623,14 +1491,13 @@ mod tests { #[should_panic(expected = "Invalid sender data")] #[test] fn test_transfer_invalid_instruction_type_should_fail() { - let invalid_type = TOKEN_HOLDING_TYPE ^ 1; + let invalid_type = TOKEN_HOLDING_STANDARD ^ 1; let pre_states = vec![ AccountWithMetadata { account: Account { - // First byte should be `TOKEN_HOLDING_TYPE` for token holding accounts - data: vec![invalid_type; TOKEN_HOLDING_DATA_SIZE] - .try_into() - .unwrap(), + // First byte should be `TOKEN_HOLDING_STANDARD` for token holding accounts + data: Data::try_from(vec![invalid_type; TOKEN_HOLDING_DATA_SIZE]) + .expect("Invalid data"), ..Account::default() }, is_authorized: true, @@ -652,7 +1519,7 @@ mod tests { AccountWithMetadata { account: Account { // Data must be of exact length `TOKEN_HOLDING_DATA_SIZE` - data: vec![1; TOKEN_HOLDING_DATA_SIZE - 1].try_into().unwrap(), + data: Data::try_from(vec![1; TOKEN_HOLDING_DATA_SIZE - 1]).unwrap(), ..Account::default() }, is_authorized: true, @@ -674,7 +1541,7 @@ mod tests { AccountWithMetadata { account: Account { // Data must be of exact length `TOKEN_HOLDING_DATA_SIZE` - data: vec![1; TOKEN_HOLDING_DATA_SIZE + 1].try_into().unwrap(), + data: Data::try_from(vec![1; TOKEN_HOLDING_DATA_SIZE - 1]).unwrap(), ..Account::default() }, is_authorized: true, @@ -693,27 +1560,8 @@ mod tests { #[test] fn test_transfer_with_different_definition_ids_should_fail() { let pre_states = vec![ - AccountWithMetadata { - account: Account { - data: vec![1; TOKEN_HOLDING_DATA_SIZE].try_into().unwrap(), - ..Account::default() - }, - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account { - data: [1] - .into_iter() - .chain(vec![2; TOKEN_HOLDING_DATA_SIZE - 1]) - .collect::>() - .try_into() - .unwrap(), - ..Account::default() - }, - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, + AccountForTests::holding_same_definition_with_authorization(), + AccountForTests::holding_different_definition(), ]; let _post_states = transfer(&pre_states, 10); } @@ -722,46 +1570,25 @@ mod tests { #[test] fn test_transfer_with_insufficient_balance_should_fail() { let pre_states = vec![ - AccountWithMetadata { - account: Account { - // Account with balance 37 - data: [1; TOKEN_HOLDING_DATA_SIZE - 16] - .into_iter() - .chain(u128::to_le_bytes(37)) - .collect::>() - .try_into() - .unwrap(), - ..Account::default() - }, - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account { - data: vec![1; TOKEN_HOLDING_DATA_SIZE].try_into().unwrap(), - ..Account::default() - }, - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, + AccountForTests::holding_same_definition_with_authorization(), + AccountForTests::holding_account_same_definition_mint(), ]; // Attempt to transfer 38 tokens - let _post_states = transfer(&pre_states, 38); + let _post_states = transfer(&pre_states, BalanceForTests::burn_insufficient()); } #[should_panic(expected = "Sender authorization is missing")] #[test] fn test_transfer_without_sender_authorization_should_fail() { + let mut def_data = Vec::::new(); + def_data.extend_from_slice(&[1; TOKEN_DEFINITION_DATA_SIZE - 16]); + def_data.extend_from_slice(&u128::to_le_bytes(37)); + let pre_states = vec![ AccountWithMetadata { account: Account { // Account with balance 37 - data: [1; TOKEN_HOLDING_DATA_SIZE - 16] - .into_iter() - .chain(u128::to_le_bytes(37)) - .collect::>() - .try_into() - .unwrap(), + data: Data::try_from(def_data).unwrap(), ..Account::default() }, is_authorized: false, @@ -769,7 +1596,7 @@ mod tests { }, AccountWithMetadata { account: Account { - data: vec![1; TOKEN_HOLDING_DATA_SIZE].try_into().unwrap(), + data: Data::try_from(vec![1; TOKEN_HOLDING_DATA_SIZE - 1]).unwrap(), ..Account::default() }, is_authorized: true, @@ -782,511 +1609,229 @@ mod tests { #[test] fn test_transfer_with_valid_inputs_succeeds() { let pre_states = vec![ - AccountWithMetadata { - account: Account { - // Account with balance 37 - data: [1; TOKEN_HOLDING_DATA_SIZE - 16] - .into_iter() - .chain(u128::to_le_bytes(37)) - .collect::>() - .try_into() - .unwrap(), - ..Account::default() - }, - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account { - // Account with balance 255 - data: [1; TOKEN_HOLDING_DATA_SIZE - 16] - .into_iter() - .chain(u128::to_le_bytes(255)) - .collect::>() - .try_into() - .unwrap(), - ..Account::default() - }, - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, + AccountForTests::holding_account_init(), + AccountForTests::holding_account2_init(), ]; - let post_states = transfer(&pre_states, 11); + let post_states = transfer(&pre_states, BalanceForTests::transfer_amount()); let [sender_post, recipient_post] = post_states.try_into().ok().unwrap(); - assert_eq!( - sender_post.account().data.as_ref(), - [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] + + assert!( + *sender_post.account() == AccountForTests::holding_account_init_post_transfer().account ); - assert_eq!( - recipient_post.account().data.as_ref(), - [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 10, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] + assert!( + *recipient_post.account() + == AccountForTests::holding_account2_init_post_transfer().account + ); + } + + #[should_panic(expected = "Invalid balance for NFT Master transfer")] + #[test] + fn test_transfer_with_master_nft_invalid_balance() { + let pre_states = vec![ + AccountForTests::holding_account_master_nft(), + AccountForTests::holding_account_uninit(), + ]; + let _post_states = transfer(&pre_states, BalanceForTests::transfer_amount()); + } + + #[should_panic(expected = "Invalid balance in recipient account for NFT transfer")] + #[test] + fn test_transfer_with_master_nft_invalid_recipient_balance() { + let pre_states = vec![ + AccountForTests::holding_account_master_nft(), + AccountForTests::holding_account_with_master_nft_transferred_to(), + ]; + let _post_states = transfer(&pre_states, BalanceForTests::printable_copies()); + } + + #[test] + fn test_transfer_with_master_nft_success() { + let pre_states = vec![ + AccountForTests::holding_account_master_nft(), + AccountForTests::holding_account_uninit(), + ]; + let post_states = transfer(&pre_states, BalanceForTests::printable_copies()); + let [sender_post, recipient_post] = post_states.try_into().ok().unwrap(); + + assert!( + *sender_post.account() + == AccountForTests::holding_account_master_nft_post_transfer().account + ); + assert!( + *recipient_post.account() + == AccountForTests::holding_account_with_master_nft_transferred_to().account ); } #[test] fn test_token_initialize_account_succeeds() { let pre_states = vec![ - AccountWithMetadata { - account: Account { - // Definition ID with - data: [0; TOKEN_DEFINITION_DATA_SIZE - 16] - .into_iter() - .chain(u128::to_le_bytes(1000)) - .collect::>() - .try_into() - .unwrap(), - ..Account::default() - }, - is_authorized: false, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: false, - account_id: AccountId::new([2; 32]), - }, + AccountForTests::holding_account_init(), + AccountForTests::holding_account2_init(), ]; - let post_states = initialize_account(&pre_states); - let [definition, holding] = post_states.try_into().ok().unwrap(); - assert_eq!( - definition.account().data.as_ref(), - pre_states[0].account.data.as_ref() + let post_states = transfer(&pre_states, BalanceForTests::transfer_amount()); + let [sender_post, recipient_post] = post_states.try_into().ok().unwrap(); + + assert!( + *sender_post.account() == AccountForTests::holding_account_init_post_transfer().account ); - assert_eq!( - holding.account().data.as_ref(), - [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] + assert!( + *recipient_post.account() + == AccountForTests::holding_account2_init_post_transfer().account ); } - enum BalanceEnum { - InitSupply, - HoldingBalance, - InitSupplyBurned, - HoldingBalanceBurned, - BurnSuccess, - BurnInsufficient, - MintSuccess, - InitSupplyMint, - HoldingBalanceMint, - MintOverflow, - } - - enum AccountsEnum { - DefinitionAccountAuth, - DefinitionAccountNotAuth, - HoldingDiffDef, - HoldingSameDefAuth, - HoldingSameDefNotAuth, - HoldingSameDefNotAuthOverflow, - DefinitionAccountPostBurn, - HoldingAccountPostBurn, - Uninit, - InitMint, - DefinitionAccountMint, - HoldingSameDefMint, - HoldingSameDefAuthLargeBalance, - } - - enum IdEnum { - PoolDefinitionId, - PoolDefinitionIdDiff, - HoldingId, - } - - fn helper_account_constructor(selection: AccountsEnum) -> AccountWithMetadata { - match selection { - AccountsEnum::DefinitionAccountAuth => AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: TOKEN_DEFINITION_TYPE, - name: [2; 6], - total_supply: helper_balance_constructor(BalanceEnum::InitSupply), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountsEnum::DefinitionAccountNotAuth => AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: TOKEN_DEFINITION_TYPE, - name: [2; 6], - total_supply: helper_balance_constructor(BalanceEnum::InitSupply), - }), - nonce: 0, - }, - is_authorized: false, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountsEnum::HoldingDiffDef => AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_TYPE, - definition_id: helper_id_constructor(IdEnum::PoolDefinitionIdDiff), - balance: helper_balance_constructor(BalanceEnum::HoldingBalance), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::HoldingId), - }, - AccountsEnum::HoldingSameDefAuth => AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_TYPE, - definition_id: helper_id_constructor(IdEnum::PoolDefinitionId), - balance: helper_balance_constructor(BalanceEnum::HoldingBalance), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::HoldingId), - }, - AccountsEnum::HoldingSameDefNotAuth => AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_TYPE, - definition_id: helper_id_constructor(IdEnum::PoolDefinitionId), - balance: helper_balance_constructor(BalanceEnum::HoldingBalance), - }), - nonce: 0, - }, - is_authorized: false, - account_id: helper_id_constructor(IdEnum::HoldingId), - }, - AccountsEnum::HoldingSameDefNotAuthOverflow => AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_TYPE, - definition_id: helper_id_constructor(IdEnum::PoolDefinitionId), - balance: helper_balance_constructor(BalanceEnum::InitSupply), - }), - nonce: 0, - }, - is_authorized: false, - account_id: helper_id_constructor(IdEnum::HoldingId), - }, - AccountsEnum::DefinitionAccountPostBurn => AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: TOKEN_DEFINITION_TYPE, - name: [2; 6], - total_supply: helper_balance_constructor(BalanceEnum::InitSupplyBurned), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountsEnum::HoldingAccountPostBurn => AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_TYPE, - definition_id: helper_id_constructor(IdEnum::PoolDefinitionId), - balance: helper_balance_constructor(BalanceEnum::HoldingBalanceBurned), - }), - nonce: 0, - }, - is_authorized: false, - account_id: helper_id_constructor(IdEnum::HoldingId), - }, - AccountsEnum::Uninit => AccountWithMetadata { - account: Account::default(), - is_authorized: false, - account_id: helper_id_constructor(IdEnum::HoldingId), - }, - AccountsEnum::InitMint => AccountWithMetadata { - account: Account { - program_owner: [0u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_TYPE, - definition_id: helper_id_constructor(IdEnum::PoolDefinitionId), - balance: helper_balance_constructor(BalanceEnum::MintSuccess), - }), - nonce: 0, - }, - is_authorized: false, - account_id: helper_id_constructor(IdEnum::HoldingId), - }, - AccountsEnum::HoldingSameDefMint => AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_TYPE, - definition_id: helper_id_constructor(IdEnum::PoolDefinitionId), - balance: helper_balance_constructor(BalanceEnum::HoldingBalanceMint), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountsEnum::DefinitionAccountMint => AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: TOKEN_DEFINITION_TYPE, - name: [2; 6], - total_supply: helper_balance_constructor(BalanceEnum::InitSupplyMint), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - AccountsEnum::HoldingSameDefAuthLargeBalance => AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_TYPE, - definition_id: helper_id_constructor(IdEnum::PoolDefinitionId), - balance: helper_balance_constructor(BalanceEnum::MintOverflow), - }), - nonce: 0, - }, - is_authorized: true, - account_id: helper_id_constructor(IdEnum::PoolDefinitionId), - }, - } - } - - fn helper_balance_constructor(selection: BalanceEnum) -> u128 { - match selection { - BalanceEnum::InitSupply => 100_000, - BalanceEnum::HoldingBalance => 1_000, - BalanceEnum::InitSupplyBurned => 99_500, - BalanceEnum::HoldingBalanceBurned => 500, - BalanceEnum::BurnSuccess => 500, - BalanceEnum::BurnInsufficient => 1_500, - BalanceEnum::MintSuccess => 50_000, - BalanceEnum::InitSupplyMint => 150_000, - BalanceEnum::HoldingBalanceMint => 51_000, - BalanceEnum::MintOverflow => u128::MAX - 40_000, - } - } - - fn helper_id_constructor(selection: IdEnum) -> AccountId { - match selection { - IdEnum::PoolDefinitionId => AccountId::new([15; 32]), - IdEnum::PoolDefinitionIdDiff => AccountId::new([16; 32]), - IdEnum::HoldingId => AccountId::new([17; 32]), - } - } - #[test] #[should_panic(expected = "Invalid number of accounts")] fn test_burn_invalid_number_of_accounts() { - let pre_states = vec![helper_account_constructor( - AccountsEnum::DefinitionAccountAuth, - )]; - let _post_states = burn( - &pre_states, - helper_balance_constructor(BalanceEnum::BurnSuccess), - ); + let pre_states = vec![AccountForTests::definition_account_auth()]; + let _post_states = burn(&pre_states, BalanceForTests::burn_success()); } #[test] - #[should_panic(expected = "Mismatch token definition and token holding")] + #[should_panic(expected = "Mismatch Token Definition and Token Holding")] fn test_burn_mismatch_def() { let pre_states = vec![ - helper_account_constructor(AccountsEnum::DefinitionAccountAuth), - helper_account_constructor(AccountsEnum::HoldingDiffDef), + AccountForTests::definition_account_auth(), + AccountForTests::holding_different_definition(), ]; - let _post_states = burn( - &pre_states, - helper_balance_constructor(BalanceEnum::BurnSuccess), - ); + let _post_states = burn(&pre_states, BalanceForTests::burn_success()); } #[test] #[should_panic(expected = "Authorization is missing")] fn test_burn_missing_authorization() { let pre_states = vec![ - helper_account_constructor(AccountsEnum::DefinitionAccountAuth), - helper_account_constructor(AccountsEnum::HoldingSameDefNotAuth), + AccountForTests::definition_account_auth(), + AccountForTests::holding_same_definition_without_authorization(), ]; - let _post_states = burn( - &pre_states, - helper_balance_constructor(BalanceEnum::BurnSuccess), - ); + let _post_states = burn(&pre_states, BalanceForTests::burn_success()); } #[test] #[should_panic(expected = "Insufficient balance to burn")] fn test_burn_insufficient_balance() { let pre_states = vec![ - helper_account_constructor(AccountsEnum::DefinitionAccountAuth), - helper_account_constructor(AccountsEnum::HoldingSameDefAuth), + AccountForTests::definition_account_auth(), + AccountForTests::holding_same_definition_with_authorization(), ]; - let _post_states = burn( - &pre_states, - helper_balance_constructor(BalanceEnum::BurnInsufficient), - ); + let _post_states = burn(&pre_states, BalanceForTests::burn_insufficient()); } #[test] #[should_panic(expected = "Total supply underflow")] fn test_burn_total_supply_underflow() { let pre_states = vec![ - helper_account_constructor(AccountsEnum::DefinitionAccountAuth), - helper_account_constructor(AccountsEnum::HoldingSameDefAuthLargeBalance), + AccountForTests::definition_account_auth(), + AccountForTests::holding_same_definition_with_authorization_and_large_balance(), ]; - let _post_states = burn( - &pre_states, - helper_balance_constructor(BalanceEnum::MintOverflow), - ); + let _post_states = burn(&pre_states, BalanceForTests::mint_overflow()); } #[test] fn test_burn_success() { let pre_states = vec![ - helper_account_constructor(AccountsEnum::DefinitionAccountAuth), - helper_account_constructor(AccountsEnum::HoldingSameDefAuth), + AccountForTests::definition_account_auth(), + AccountForTests::holding_same_definition_with_authorization(), ]; - let post_states = burn( - &pre_states, - helper_balance_constructor(BalanceEnum::BurnSuccess), - ); + let post_states = burn(&pre_states, BalanceForTests::burn_success()); let def_post = post_states[0].clone(); let holding_post = post_states[1].clone(); - assert!( - *def_post.account() - == helper_account_constructor(AccountsEnum::DefinitionAccountPostBurn).account - ); - assert!( - *holding_post.account() - == helper_account_constructor(AccountsEnum::HoldingAccountPostBurn).account - ); + assert!(*def_post.account() == AccountForTests::definition_account_post_burn().account); + assert!(*holding_post.account() == AccountForTests::holding_account_post_burn().account); } #[test] #[should_panic(expected = "Invalid number of accounts")] - fn test_mint_invalid_number_of_accounts() { - let pre_states = vec![helper_account_constructor( - AccountsEnum::DefinitionAccountAuth, - )]; - let _post_states = mint_additional_supply( - &pre_states, - helper_balance_constructor(BalanceEnum::MintSuccess), - ); + fn test_mint_invalid_number_of_accounts_1() { + let pre_states = vec![AccountForTests::definition_account_auth()]; + let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); + } + + #[test] + #[should_panic(expected = "Invalid number of accounts")] + fn test_mint_invalid_number_of_accounts_2() { + let pre_states = vec![ + AccountForTests::definition_account_auth(), + AccountForTests::holding_account_same_definition_mint(), + AccountForTests::holding_same_definition_with_authorization(), + ]; + let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); } #[test] #[should_panic(expected = "Holding account must be valid")] fn test_mint_not_valid_holding_account() { let pre_states = vec![ - helper_account_constructor(AccountsEnum::DefinitionAccountAuth), - helper_account_constructor(AccountsEnum::DefinitionAccountNotAuth), + AccountForTests::definition_account_auth(), + AccountForTests::definition_account_without_auth(), ]; - let _post_states = mint_additional_supply( - &pre_states, - helper_balance_constructor(BalanceEnum::MintSuccess), - ); + let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); + } + + #[test] + #[should_panic(expected = "Definition account must be valid")] + fn test_mint_not_valid_definition_account() { + let pre_states = vec![ + AccountForTests::holding_same_definition_with_authorization(), + AccountForTests::holding_same_definition_without_authorization(), + ]; + let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); } #[test] #[should_panic(expected = "Definition authorization is missing")] fn test_mint_missing_authorization() { let pre_states = vec![ - helper_account_constructor(AccountsEnum::DefinitionAccountNotAuth), - helper_account_constructor(AccountsEnum::HoldingSameDefNotAuth), + AccountForTests::definition_account_without_auth(), + AccountForTests::holding_same_definition_without_authorization(), ]; - let _post_states = mint_additional_supply( - &pre_states, - helper_balance_constructor(BalanceEnum::MintSuccess), - ); + let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); } #[test] - #[should_panic(expected = "Mismatch token definition and token holding")] + #[should_panic(expected = "Mismatch Token Definition and Token Holding")] fn test_mint_mismatched_token_definition() { let pre_states = vec![ - helper_account_constructor(AccountsEnum::DefinitionAccountAuth), - helper_account_constructor(AccountsEnum::HoldingDiffDef), + AccountForTests::definition_account_auth(), + AccountForTests::holding_different_definition(), ]; - let _post_states = mint_additional_supply( - &pre_states, - helper_balance_constructor(BalanceEnum::MintSuccess), - ); + let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); } #[test] fn test_mint_success() { let pre_states = vec![ - helper_account_constructor(AccountsEnum::DefinitionAccountAuth), - helper_account_constructor(AccountsEnum::HoldingSameDefNotAuth), + AccountForTests::definition_account_auth(), + AccountForTests::holding_same_definition_without_authorization(), ]; - let post_states = mint_additional_supply( - &pre_states, - helper_balance_constructor(BalanceEnum::MintSuccess), - ); + let post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); let def_post = post_states[0].clone(); let holding_post = post_states[1].clone(); - assert!( - *def_post.account() - == helper_account_constructor(AccountsEnum::DefinitionAccountMint).account - ); + assert!(*def_post.account() == AccountForTests::definition_account_mint().account); assert!( *holding_post.account() - == helper_account_constructor(AccountsEnum::HoldingSameDefMint).account + == AccountForTests::holding_account_same_definition_mint().account ); } #[test] fn test_mint_uninit_holding_success() { let pre_states = vec![ - helper_account_constructor(AccountsEnum::DefinitionAccountAuth), - helper_account_constructor(AccountsEnum::Uninit), + AccountForTests::definition_account_auth(), + AccountForTests::holding_account_uninit(), ]; - let post_states = mint_additional_supply( - &pre_states, - helper_balance_constructor(BalanceEnum::MintSuccess), - ); + let post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); let def_post = post_states[0].clone(); let holding_post = post_states[1].clone(); - assert!( - *def_post.account() - == helper_account_constructor(AccountsEnum::DefinitionAccountMint).account - ); - assert!( - *holding_post.account() == helper_account_constructor(AccountsEnum::InitMint).account - ); + assert!(*def_post.account() == AccountForTests::definition_account_mint().account); + assert!(*holding_post.account() == AccountForTests::init_mint().account); assert!(holding_post.requires_claim()); } @@ -1294,25 +1839,488 @@ mod tests { #[should_panic(expected = "Total supply overflow")] fn test_mint_total_supply_overflow() { let pre_states = vec![ - helper_account_constructor(AccountsEnum::DefinitionAccountAuth), - helper_account_constructor(AccountsEnum::HoldingSameDefNotAuth), + AccountForTests::definition_account_auth(), + AccountForTests::holding_same_definition_without_authorization(), ]; - let _post_states = mint_additional_supply( - &pre_states, - helper_balance_constructor(BalanceEnum::MintOverflow), - ); + let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_overflow()); } #[test] #[should_panic(expected = "New balance overflow")] fn test_mint_holding_account_overflow() { let pre_states = vec![ - helper_account_constructor(AccountsEnum::DefinitionAccountAuth), - helper_account_constructor(AccountsEnum::HoldingSameDefNotAuthOverflow), + AccountForTests::definition_account_auth(), + AccountForTests::holding_same_definition_without_authorization_overflow(), ]; - let _post_states = mint_additional_supply( + let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_overflow()); + } + + #[test] + #[should_panic( + expected = "Token Definition's standard does not permit minting additional supply" + )] + fn test_mint_cannot_mint_unmintable_tokens() { + let pre_states = vec![ + AccountForTests::definition_account_with_authorization_nonfungible(), + AccountForTests::holding_same_definition_without_authorization(), + ]; + let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); + } + + #[should_panic(expected = "Invalid number of input accounts")] + #[test] + fn test_call_new_definition_metadata_with_invalid_number_of_accounts_1() { + let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; + let total_supply = 15u128; + let token_standard = 0u8; + let metadata_standard = 0u8; + let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); + + let pre_states = vec![AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([1; 32]), + }]; + let _post_states = new_definition_with_metadata( &pre_states, - helper_balance_constructor(BalanceEnum::MintOverflow), + name, + total_supply, + token_standard, + metadata_standard, + &metadata_values, ); } + + #[should_panic(expected = "Invalid number of input accounts")] + #[test] + fn test_call_new_definition_metadata_with_invalid_number_of_accounts_2() { + let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; + let total_supply = 15u128; + let token_standard = 0u8; + let metadata_standard = 0u8; + let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); + + let pre_states = vec![ + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([1; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([2; 32]), + }, + ]; + let _post_states = new_definition_with_metadata( + &pre_states, + name, + total_supply, + token_standard, + metadata_standard, + &metadata_values, + ); + } + + #[should_panic(expected = "Invalid number of input accounts")] + #[test] + fn test_call_new_definition_metadata_with_invalid_number_of_accounts_3() { + let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; + let total_supply = 15u128; + let token_standard = 0u8; + let metadata_standard = 0u8; + let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); + + let pre_states = vec![ + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([1; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([2; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([3; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([4; 32]), + }, + ]; + let _post_states = new_definition_with_metadata( + &pre_states, + name, + total_supply, + token_standard, + metadata_standard, + &metadata_values, + ); + } + + #[should_panic(expected = "Definition target account must have default values")] + #[test] + fn test_call_new_definition_metadata_with_init_definition() { + let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; + let total_supply = 15u128; + let token_standard = 0u8; + let metadata_standard = 0u8; + let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); + + let pre_states = vec![ + AccountForTests::definition_account_auth(), + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([2; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([3; 32]), + }, + ]; + let _post_states = new_definition_with_metadata( + &pre_states, + name, + total_supply, + token_standard, + metadata_standard, + &metadata_values, + ); + } + + #[should_panic(expected = "Metadata target account must have default values")] + #[test] + fn test_call_new_definition_metadata_with_init_metadata() { + let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; + let total_supply = 15u128; + let token_standard = 0u8; + let metadata_standard = 0u8; + let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); + + let pre_states = vec![ + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([1; 32]), + }, + AccountForTests::holding_account_same_definition_mint(), + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([3; 32]), + }, + ]; + let _post_states = new_definition_with_metadata( + &pre_states, + name, + total_supply, + token_standard, + metadata_standard, + &metadata_values, + ); + } + + #[should_panic(expected = "Holding target account must have default values")] + #[test] + fn test_call_new_definition_metadata_with_init_holding() { + let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; + let total_supply = 15u128; + let token_standard = 0u8; + let metadata_standard = 0u8; + let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); + + let pre_states = vec![ + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([1; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([2; 32]), + }, + AccountForTests::holding_account_same_definition_mint(), + ]; + let _post_states = new_definition_with_metadata( + &pre_states, + name, + total_supply, + token_standard, + metadata_standard, + &metadata_values, + ); + } + + #[should_panic(expected = "Metadata values data should be 450 bytes")] + #[test] + fn test_call_new_definition_metadata_with_too_short_metadata_length() { + let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; + let total_supply = 15u128; + let token_standard = 0u8; + let metadata_standard = 0u8; + let metadata_values: Data = Data::try_from([1u8; 449].to_vec()).unwrap(); + + let pre_states = vec![ + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([1; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([2; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([3; 32]), + }, + ]; + let _post_states = new_definition_with_metadata( + &pre_states, + name, + total_supply, + token_standard, + metadata_standard, + &metadata_values, + ); + } + + #[should_panic(expected = "Metadata values data should be 450 bytes")] + #[test] + fn test_call_new_definition_metadata_with_too_long_metadata_length() { + let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; + let total_supply = 15u128; + let token_standard = 0u8; + let metadata_standard = 0u8; + let metadata_values: Data = Data::try_from([1u8; 451].to_vec()).unwrap(); + + let pre_states = vec![ + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([1; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([2; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([3; 32]), + }, + ]; + let _post_states = new_definition_with_metadata( + &pre_states, + name, + total_supply, + token_standard, + metadata_standard, + &metadata_values, + ); + } + + #[should_panic(expected = "Invalid Token Standard provided")] + #[test] + fn test_call_new_definition_metadata_with_invalid_token_standard() { + let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; + let total_supply = 15u128; + let token_standard = 14u8; + let metadata_standard = 0u8; + let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); + + let pre_states = vec![ + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([1; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([2; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([3; 32]), + }, + ]; + let _post_states = new_definition_with_metadata( + &pre_states, + name, + total_supply, + token_standard, + metadata_standard, + &metadata_values, + ); + } + + #[should_panic(expected = "Invalid Metadata Standadard provided")] + #[test] + fn test_call_new_definition_metadata_with_invalid_metadata_standard() { + let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; + let total_supply = 15u128; + let token_standard = 0u8; + let metadata_standard = 14u8; + let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); + + let pre_states = vec![ + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([1; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([2; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([3; 32]), + }, + ]; + let _post_states = new_definition_with_metadata( + &pre_states, + name, + total_supply, + token_standard, + metadata_standard, + &metadata_values, + ); + } + + #[should_panic(expected = "Invalid total supply for the specified token supply")] + #[test] + fn test_call_new_definition_metadata_invalid_supply_for_nonfungible() { + let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; + let total_supply = 15u128; + let token_standard = TOKEN_STANDARD_NONFUNGIBLE; + let metadata_standard = 0u8; + let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); + + let pre_states = vec![ + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([1; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([2; 32]), + }, + AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([3; 32]), + }, + ]; + let _post_states = new_definition_with_metadata( + &pre_states, + name, + total_supply, + token_standard, + metadata_standard, + &metadata_values, + ); + } + + #[should_panic(expected = "Invalid number of accounts")] + #[test] + fn test_print_nft_invalid_number_of_accounts_1() { + let pre_states = vec![AccountForTests::holding_account_master_nft()]; + let _post_states = print_nft(&pre_states); + } + + #[should_panic(expected = "Invalid number of accounts")] + #[test] + fn test_print_nft_invalid_number_of_accounts_2() { + let pre_states = vec![ + AccountForTests::holding_account_master_nft(), + AccountForTests::definition_account_auth(), + AccountForTests::holding_account_uninit(), + ]; + let _post_states = print_nft(&pre_states); + } + + #[should_panic(expected = "Master NFT Account must be authorized")] + #[test] + fn test_print_nft_master_account_must_be_authorized() { + let pre_states = vec![ + AccountForTests::holding_account_uninit(), + AccountForTests::holding_account_uninit(), + ]; + let _post_states = print_nft(&pre_states); + } + + #[should_panic(expected = "Printed Account must be uninitialized")] + #[test] + fn test_print_nft_print_account_initialized() { + let pre_states = vec![ + AccountForTests::holding_account_master_nft(), + AccountForTests::holding_account_init(), + ]; + let _post_states = print_nft(&pre_states); + } + + #[should_panic(expected = "Invalid Token Holding data")] + #[test] + fn test_print_nft_master_nft_invalid_token_holding() { + let pre_states = vec![ + AccountForTests::definition_account_auth(), + AccountForTests::holding_account_uninit(), + ]; + let _post_states = print_nft(&pre_states); + } + + #[should_panic(expected = "Invalid Token Holding provided as NFT Master Account")] + #[test] + fn test_print_nft_master_nft_not_nft_master_account() { + let pre_states = vec![ + AccountForTests::holding_account_init(), + AccountForTests::holding_account_uninit(), + ]; + let _post_states = print_nft(&pre_states); + } + + #[should_panic(expected = "Insufficient balance to print another NFT copy")] + #[test] + fn test_print_nft_master_nft_insufficient_balance() { + let pre_states = vec![ + AccountForTests::holding_account_master_nft_insufficient_balance(), + AccountForTests::holding_account_uninit(), + ]; + let _post_states = print_nft(&pre_states); + } + + #[test] + fn test_print_nft_success() { + let pre_states = vec![ + AccountForTests::holding_account_master_nft(), + AccountForTests::holding_account_uninit(), + ]; + let post_states = print_nft(&pre_states); + + let post_master_nft = post_states[0].account(); + let post_printed = post_states[1].account(); + + assert!( + *post_master_nft == AccountForTests::holding_account_master_nft_after_print().account + ); + assert!(*post_printed == AccountForTests::holding_account_printed_nft().account); + } } diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index 7e8a005..d10c8c5 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -289,6 +289,8 @@ impl WalletSubcommand for AccountSubcommand { #[cfg(test)] mod tests { + use nssa::AccountId; + use crate::cli::account::{TokedDefinitionAccountView, TokenDefinition}; #[test] @@ -297,6 +299,7 @@ mod tests { account_type: 1, name: [137, 12, 14, 3, 5, 4], total_supply: 100, + metadata_id: AccountId::new([0; 32]), }; let token_def_view: TokedDefinitionAccountView = token_def.into(); @@ -310,6 +313,7 @@ mod tests { account_type: 1, name: [240, 159, 146, 150, 66, 66], total_supply: 100, + metadata_id: AccountId::new([0; 32]), }; let token_def_view: TokedDefinitionAccountView = token_def.into(); @@ -323,6 +327,7 @@ mod tests { account_type: 1, name: [78, 65, 77, 69, 0, 0], total_supply: 100, + metadata_id: AccountId::new([0; 32]), }; let token_def_view: TokedDefinitionAccountView = token_def.into(); diff --git a/wallet/src/cli/programs/token.rs b/wallet/src/cli/programs/token.rs index 880c2c1..25d61ff 100644 --- a/wallet/src/cli/programs/token.rs +++ b/wallet/src/cli/programs/token.rs @@ -50,6 +50,48 @@ pub enum TokenProgramAgnosticSubcommand { #[arg(long)] amount: u128, }, + /// Burn tokens on `holder`, modify `definition`. + /// + /// `holder` is owned + /// + /// Also if `definition` is private then it is owned, because + /// we can not modify foreign accounts. + Burn { + /// definition - valid 32 byte base58 string with privacy prefix + #[arg(long)] + definition: String, + /// holder - valid 32 byte base58 string with privacy prefix + #[arg(long)] + holder: String, + /// amount - amount of balance to burn + #[arg(long)] + amount: u128, + }, + /// Mint tokens on `holder`, modify `definition`. + /// + /// `definition` is owned + /// + /// If `holder` is private, then `holder` and (`holder_npk` , `holder_ipk`) is a mutually + /// exclusive patterns. + /// + /// First is used for owned accounts, second otherwise. + Mint { + /// definition - valid 32 byte base58 string with privacy prefix + #[arg(long)] + definition: String, + /// holder - valid 32 byte base58 string with privacy prefix + #[arg(long)] + holder: Option, + /// holder_npk - valid 32 byte hex string + #[arg(long)] + holder_npk: Option, + /// to_ipk - valid 33 byte hex string + #[arg(long)] + holder_ipk: Option, + /// amount - amount of balance to mint + #[arg(long)] + amount: u128, + }, } impl WalletSubcommand for TokenProgramAgnosticSubcommand { @@ -202,6 +244,150 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { } }; + underlying_subcommand.handle_subcommand(wallet_core).await + } + TokenProgramAgnosticSubcommand::Burn { + definition, + holder, + amount, + } => { + let underlying_subcommand = { + let (definition, definition_privacy) = + parse_addr_with_privacy_prefix(&definition)?; + let (holder, holder_privacy) = parse_addr_with_privacy_prefix(&holder)?; + + match (definition_privacy, holder_privacy) { + (AccountPrivacyKind::Public, AccountPrivacyKind::Public) => { + TokenProgramSubcommand::Public( + TokenProgramSubcommandPublic::BurnToken { + definition_account_id: definition, + holder_account_id: holder, + amount, + }, + ) + } + (AccountPrivacyKind::Private, AccountPrivacyKind::Private) => { + TokenProgramSubcommand::Private( + TokenProgramSubcommandPrivate::BurnTokenPrivateOwned { + definition_account_id: definition, + holder_account_id: holder, + amount, + }, + ) + } + (AccountPrivacyKind::Private, AccountPrivacyKind::Public) => { + TokenProgramSubcommand::Deshielded( + TokenProgramSubcommandDeshielded::BurnTokenDeshieldedOwned { + definition_account_id: definition, + holder_account_id: holder, + amount, + }, + ) + } + (AccountPrivacyKind::Public, AccountPrivacyKind::Private) => { + TokenProgramSubcommand::Shielded( + TokenProgramSubcommandShielded::BurnTokenShielded { + definition_account_id: definition, + holder_account_id: holder, + amount, + }, + ) + } + } + }; + + underlying_subcommand.handle_subcommand(wallet_core).await + } + TokenProgramAgnosticSubcommand::Mint { + definition, + holder, + holder_npk, + holder_ipk, + amount, + } => { + let underlying_subcommand = match (holder, holder_npk, holder_ipk) { + (None, None, None) => { + anyhow::bail!( + "Provide either account account_id of holder or their public keys" + ); + } + (Some(_), Some(_), Some(_)) => { + anyhow::bail!( + "Provide only one variant: either account_id of holder or their public keys" + ); + } + (_, Some(_), None) | (_, None, Some(_)) => { + anyhow::bail!("List of public keys is uncomplete"); + } + (Some(holder), None, None) => { + let (definition, definition_privacy) = + parse_addr_with_privacy_prefix(&definition)?; + let (holder, holder_privacy) = parse_addr_with_privacy_prefix(&holder)?; + + match (definition_privacy, holder_privacy) { + (AccountPrivacyKind::Public, AccountPrivacyKind::Public) => { + TokenProgramSubcommand::Public( + TokenProgramSubcommandPublic::MintToken { + definition_account_id: definition, + holder_account_id: holder, + amount, + }, + ) + } + (AccountPrivacyKind::Private, AccountPrivacyKind::Private) => { + TokenProgramSubcommand::Private( + TokenProgramSubcommandPrivate::MintTokenPrivateOwned { + definition_account_id: definition, + holder_account_id: holder, + amount, + }, + ) + } + (AccountPrivacyKind::Private, AccountPrivacyKind::Public) => { + TokenProgramSubcommand::Deshielded( + TokenProgramSubcommandDeshielded::MintTokenDeshielded { + definition_account_id: definition, + holder_account_id: holder, + amount, + }, + ) + } + (AccountPrivacyKind::Public, AccountPrivacyKind::Private) => { + TokenProgramSubcommand::Shielded( + TokenProgramSubcommandShielded::MintTokenShieldedOwned { + definition_account_id: definition, + holder_account_id: holder, + amount, + }, + ) + } + } + } + (None, Some(holder_npk), Some(holder_ipk)) => { + let (definition, definition_privacy) = + parse_addr_with_privacy_prefix(&definition)?; + + match definition_privacy { + AccountPrivacyKind::Private => TokenProgramSubcommand::Private( + TokenProgramSubcommandPrivate::MintTokenPrivateForeign { + definition_account_id: definition, + holder_npk, + holder_ipk, + amount, + }, + ), + AccountPrivacyKind::Public => TokenProgramSubcommand::Shielded( + TokenProgramSubcommandShielded::MintTokenShieldedForeign { + definition_account_id: definition, + holder_npk, + holder_ipk, + amount, + }, + ), + } + } + }; + underlying_subcommand.handle_subcommand(wallet_core).await } } @@ -240,6 +426,24 @@ pub enum TokenProgramSubcommandPublic { #[arg(short, long)] balance_to_move: u128, }, + // Burn tokens using the token program + BurnToken { + #[arg(short, long)] + definition_account_id: String, + #[arg(short, long)] + holder_account_id: String, + #[arg(short, long)] + amount: u128, + }, + // Transfer tokens using the token program + MintToken { + #[arg(short, long)] + definition_account_id: String, + #[arg(short, long)] + holder_account_id: String, + #[arg(short, long)] + amount: u128, + }, } /// Represents generic private CLI subcommand for a wallet working with token_program @@ -267,6 +471,35 @@ pub enum TokenProgramSubcommandPrivate { #[arg(short, long)] balance_to_move: u128, }, + // Burn tokens using the token program + BurnTokenPrivateOwned { + #[arg(short, long)] + definition_account_id: String, + #[arg(short, long)] + holder_account_id: String, + #[arg(short, long)] + amount: u128, + }, + // Transfer tokens using the token program + MintTokenPrivateOwned { + #[arg(short, long)] + definition_account_id: String, + #[arg(short, long)] + holder_account_id: String, + #[arg(short, long)] + amount: u128, + }, + // Transfer tokens using the token program + MintTokenPrivateForeign { + #[arg(short, long)] + definition_account_id: String, + #[arg(short, long)] + holder_npk: String, + #[arg(short, long)] + holder_ipk: String, + #[arg(short, long)] + amount: u128, + }, } /// Represents deshielded public CLI subcommand for a wallet working with token_program @@ -281,6 +514,24 @@ pub enum TokenProgramSubcommandDeshielded { #[arg(short, long)] balance_to_move: u128, }, + // Burn tokens using the token program + BurnTokenDeshieldedOwned { + #[arg(short, long)] + definition_account_id: String, + #[arg(short, long)] + holder_account_id: String, + #[arg(short, long)] + amount: u128, + }, + // Transfer tokens using the token program + MintTokenDeshielded { + #[arg(short, long)] + definition_account_id: String, + #[arg(short, long)] + holder_account_id: String, + #[arg(short, long)] + amount: u128, + }, } /// Represents generic shielded CLI subcommand for a wallet working with token_program @@ -308,6 +559,35 @@ pub enum TokenProgramSubcommandShielded { #[arg(short, long)] balance_to_move: u128, }, + // Burn tokens using the token program + BurnTokenShielded { + #[arg(short, long)] + definition_account_id: String, + #[arg(short, long)] + holder_account_id: String, + #[arg(short, long)] + amount: u128, + }, + // Transfer tokens using the token program + MintTokenShieldedOwned { + #[arg(short, long)] + definition_account_id: String, + #[arg(short, long)] + holder_account_id: String, + #[arg(short, long)] + amount: u128, + }, + // Transfer tokens using the token program + MintTokenShieldedForeign { + #[arg(short, long)] + definition_account_id: String, + #[arg(short, long)] + holder_npk: String, + #[arg(short, long)] + holder_ipk: String, + #[arg(short, long)] + amount: u128, + }, } /// Represents generic initialization subcommand for a wallet working with token_program @@ -387,6 +667,34 @@ impl WalletSubcommand for TokenProgramSubcommandPublic { .await?; Ok(SubcommandReturnValue::Empty) } + TokenProgramSubcommandPublic::BurnToken { + definition_account_id, + holder_account_id, + amount, + } => { + Token(wallet_core) + .send_burn_transaction( + definition_account_id.parse().unwrap(), + holder_account_id.parse().unwrap(), + amount, + ) + .await?; + Ok(SubcommandReturnValue::Empty) + } + TokenProgramSubcommandPublic::MintToken { + definition_account_id, + holder_account_id, + amount, + } => { + Token(wallet_core) + .send_mint_transaction( + definition_account_id.parse().unwrap(), + holder_account_id.parse().unwrap(), + amount, + ) + .await?; + Ok(SubcommandReturnValue::Empty) + } } } } @@ -486,6 +794,139 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { println!("Stored persistent accounts at {path:#?}"); + Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) + } + TokenProgramSubcommandPrivate::BurnTokenPrivateOwned { + definition_account_id, + holder_account_id, + amount, + } => { + let definition_account_id: AccountId = definition_account_id.parse().unwrap(); + let holder_account_id: AccountId = holder_account_id.parse().unwrap(); + + let (res, [secret_definition, secret_holder]) = Token(wallet_core) + .send_burn_transaction_private_owned_account( + definition_account_id, + holder_account_id, + amount, + ) + .await?; + + println!("Results of tx send are {res:#?}"); + + let tx_hash = res.tx_hash; + let transfer_tx = wallet_core + .poll_native_token_transfer(tx_hash.clone()) + .await?; + + if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + let acc_decode_data = vec![ + Decode(secret_definition, definition_account_id), + Decode(secret_holder, holder_account_id), + ]; + + wallet_core.decode_insert_privacy_preserving_transaction_results( + tx, + &acc_decode_data, + )?; + } + + let path = wallet_core.store_persistent_data().await?; + + println!("Stored persistent accounts at {path:#?}"); + + Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) + } + TokenProgramSubcommandPrivate::MintTokenPrivateOwned { + definition_account_id, + holder_account_id, + amount, + } => { + let definition_account_id: AccountId = definition_account_id.parse().unwrap(); + let holder_account_id: AccountId = holder_account_id.parse().unwrap(); + + let (res, [secret_definition, secret_holder]) = Token(wallet_core) + .send_mint_transaction_private_owned_account( + definition_account_id, + holder_account_id, + amount, + ) + .await?; + + println!("Results of tx send are {res:#?}"); + + let tx_hash = res.tx_hash; + let transfer_tx = wallet_core + .poll_native_token_transfer(tx_hash.clone()) + .await?; + + if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + let acc_decode_data = vec![ + Decode(secret_definition, definition_account_id), + Decode(secret_holder, holder_account_id), + ]; + + wallet_core.decode_insert_privacy_preserving_transaction_results( + tx, + &acc_decode_data, + )?; + } + + let path = wallet_core.store_persistent_data().await?; + + println!("Stored persistent accounts at {path:#?}"); + + Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) + } + TokenProgramSubcommandPrivate::MintTokenPrivateForeign { + definition_account_id, + holder_npk, + holder_ipk, + amount, + } => { + let definition_account_id: AccountId = definition_account_id.parse().unwrap(); + + let holder_npk_res = hex::decode(holder_npk)?; + let mut holder_npk = [0; 32]; + holder_npk.copy_from_slice(&holder_npk_res); + let holder_npk = nssa_core::NullifierPublicKey(holder_npk); + + let holder_ipk_res = hex::decode(holder_ipk)?; + let mut holder_ipk = [0u8; 33]; + holder_ipk.copy_from_slice(&holder_ipk_res); + let holder_ipk = nssa_core::encryption::shared_key_derivation::Secp256k1Point( + holder_ipk.to_vec(), + ); + + let (res, [secret_definition, _]) = Token(wallet_core) + .send_mint_transaction_private_foreign_account( + definition_account_id, + holder_npk, + holder_ipk, + amount, + ) + .await?; + + println!("Results of tx send are {res:#?}"); + + let tx_hash = res.tx_hash; + let transfer_tx = wallet_core + .poll_native_token_transfer(tx_hash.clone()) + .await?; + + if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + let acc_decode_data = vec![Decode(secret_definition, definition_account_id)]; + + wallet_core.decode_insert_privacy_preserving_transaction_results( + tx, + &acc_decode_data, + )?; + } + + let path = wallet_core.store_persistent_data().await?; + + println!("Stored persistent accounts at {path:#?}"); + Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) } } @@ -534,6 +975,82 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { println!("Stored persistent accounts at {path:#?}"); + Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) + } + TokenProgramSubcommandDeshielded::BurnTokenDeshieldedOwned { + definition_account_id, + holder_account_id, + amount, + } => { + let definition_account_id: AccountId = definition_account_id.parse().unwrap(); + let holder_account_id: AccountId = holder_account_id.parse().unwrap(); + + let (res, secret_definition) = Token(wallet_core) + .send_burn_transaction_deshielded_owned_account( + definition_account_id, + holder_account_id, + amount, + ) + .await?; + + println!("Results of tx send are {res:#?}"); + + let tx_hash = res.tx_hash; + let transfer_tx = wallet_core + .poll_native_token_transfer(tx_hash.clone()) + .await?; + + if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + let acc_decode_data = vec![Decode(secret_definition, definition_account_id)]; + + wallet_core.decode_insert_privacy_preserving_transaction_results( + tx, + &acc_decode_data, + )?; + } + + let path = wallet_core.store_persistent_data().await?; + + println!("Stored persistent accounts at {path:#?}"); + + Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) + } + TokenProgramSubcommandDeshielded::MintTokenDeshielded { + definition_account_id, + holder_account_id, + amount, + } => { + let definition_account_id: AccountId = definition_account_id.parse().unwrap(); + let holder_account_id: AccountId = holder_account_id.parse().unwrap(); + + let (res, secret_definition) = Token(wallet_core) + .send_mint_transaction_deshielded( + definition_account_id, + holder_account_id, + amount, + ) + .await?; + + println!("Results of tx send are {res:#?}"); + + let tx_hash = res.tx_hash; + let transfer_tx = wallet_core + .poll_native_token_transfer(tx_hash.clone()) + .await?; + + if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + let acc_decode_data = vec![Decode(secret_definition, definition_account_id)]; + + wallet_core.decode_insert_privacy_preserving_transaction_results( + tx, + &acc_decode_data, + )?; + } + + let path = wallet_core.store_persistent_data().await?; + + println!("Stored persistent accounts at {path:#?}"); + Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) } } @@ -627,6 +1144,128 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { println!("Stored persistent accounts at {path:#?}"); + Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) + } + TokenProgramSubcommandShielded::BurnTokenShielded { + definition_account_id, + holder_account_id, + amount, + } => { + let definition_account_id: AccountId = definition_account_id.parse().unwrap(); + let holder_account_id: AccountId = holder_account_id.parse().unwrap(); + + let (res, secret_holder) = Token(wallet_core) + .send_burn_transaction_shielded( + definition_account_id, + holder_account_id, + amount, + ) + .await?; + + println!("Results of tx send are {res:#?}"); + + let tx_hash = res.tx_hash; + let transfer_tx = wallet_core + .poll_native_token_transfer(tx_hash.clone()) + .await?; + + if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + let acc_decode_data = vec![Decode(secret_holder, holder_account_id)]; + + wallet_core.decode_insert_privacy_preserving_transaction_results( + tx, + &acc_decode_data, + )?; + } + + let path = wallet_core.store_persistent_data().await?; + + println!("Stored persistent accounts at {path:#?}"); + + Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) + } + TokenProgramSubcommandShielded::MintTokenShieldedOwned { + definition_account_id, + holder_account_id, + amount, + } => { + let definition_account_id: AccountId = definition_account_id.parse().unwrap(); + let holder_account_id: AccountId = holder_account_id.parse().unwrap(); + + let (res, secret_holder) = Token(wallet_core) + .send_mint_transaction_shielded_owned_account( + definition_account_id, + holder_account_id, + amount, + ) + .await?; + + println!("Results of tx send are {res:#?}"); + + let tx_hash = res.tx_hash; + let transfer_tx = wallet_core + .poll_native_token_transfer(tx_hash.clone()) + .await?; + + if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + let acc_decode_data = vec![Decode(secret_holder, holder_account_id)]; + + wallet_core.decode_insert_privacy_preserving_transaction_results( + tx, + &acc_decode_data, + )?; + } + + let path = wallet_core.store_persistent_data().await?; + + println!("Stored persistent accounts at {path:#?}"); + + Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) + } + TokenProgramSubcommandShielded::MintTokenShieldedForeign { + definition_account_id, + holder_npk, + holder_ipk, + amount, + } => { + let definition_account_id: AccountId = definition_account_id.parse().unwrap(); + + let holder_npk_res = hex::decode(holder_npk)?; + let mut holder_npk = [0; 32]; + holder_npk.copy_from_slice(&holder_npk_res); + let holder_npk = nssa_core::NullifierPublicKey(holder_npk); + + let holder_ipk_res = hex::decode(holder_ipk)?; + let mut holder_ipk = [0u8; 33]; + holder_ipk.copy_from_slice(&holder_ipk_res); + let holder_ipk = nssa_core::encryption::shared_key_derivation::Secp256k1Point( + holder_ipk.to_vec(), + ); + + let (res, _) = Token(wallet_core) + .send_mint_transaction_shielded_foreign_account( + definition_account_id, + holder_npk, + holder_ipk, + amount, + ) + .await?; + + println!("Results of tx send are {res:#?}"); + + let tx_hash = res.tx_hash; + let transfer_tx = wallet_core + .poll_native_token_transfer(tx_hash.clone()) + .await?; + + if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + println!("Transaction data is {:?}", tx.message); + } + + let path = wallet_core.store_persistent_data().await?; + + println!("Stored persistent accounts at {path:#?}"); + Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) } } diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 383806e..bad6435 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -18,7 +18,9 @@ use nssa::{ circuit::ProgramWithDependencies, message::EncryptedAccountData, }, }; -use nssa_core::{Commitment, MembershipProof, SharedSecretKey, program::InstructionData}; +use nssa_core::{ + Commitment, MembershipProof, SharedSecretKey, account::Data, program::InstructionData, +}; pub use privacy_preserving_tx::PrivacyPreservingAccount; use tokio::io::AsyncWriteExt; @@ -45,45 +47,67 @@ pub enum AccDecodeData { Decode(nssa_core::SharedSecretKey, AccountId), } -const TOKEN_DEFINITION_TYPE: u8 = 0; -const TOKEN_DEFINITION_DATA_SIZE: usize = 23; +const TOKEN_DEFINITION_DATA_SIZE: usize = 55; const TOKEN_HOLDING_TYPE: u8 = 1; const TOKEN_HOLDING_DATA_SIZE: usize = 49; +const TOKEN_STANDARD_FUNGIBLE_TOKEN: u8 = 0; +const TOKEN_STANDARD_NONFUNGIBLE: u8 = 2; struct TokenDefinition { #[allow(unused)] account_type: u8, name: [u8; 6], total_supply: u128, + #[allow(unused)] + metadata_id: AccountId, } -pub struct TokenHolding { - pub account_type: u8, - pub definition_id: AccountId, - pub balance: u128, +struct TokenHolding { + #[allow(unused)] + account_type: u8, + definition_id: AccountId, + balance: u128, } impl TokenDefinition { - fn parse(data: &[u8]) -> Option { - if data.len() != TOKEN_DEFINITION_DATA_SIZE || data[0] != TOKEN_DEFINITION_TYPE { + fn parse(data: &Data) -> Option { + let data = Vec::::from(data.clone()); + + if data.len() != TOKEN_DEFINITION_DATA_SIZE { 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()); + let name = data[1..7].try_into().expect("Name must be a 6 bytes"); + let total_supply = u128::from_le_bytes( + data[7..23] + .try_into() + .expect("Total supply must be 16 bytes little-endian"), + ); + let metadata_id = AccountId::new( + data[23..TOKEN_DEFINITION_DATA_SIZE] + .try_into() + .expect("Token Program expects valid Account Id for Metadata"), + ); - Some(Self { + let this = Some(Self { account_type, name, total_supply, - }) + metadata_id, + }); + + match account_type { + TOKEN_STANDARD_NONFUNGIBLE if total_supply != 1 => None, + TOKEN_STANDARD_FUNGIBLE_TOKEN if metadata_id != AccountId::new([0; 32]) => None, + _ => this, + } } } } impl TokenHolding { - pub fn parse(data: &[u8]) -> Option { + fn parse(data: &[u8]) -> Option { if data.len() != TOKEN_HOLDING_DATA_SIZE || data[0] != TOKEN_HOLDING_TYPE { None } else { diff --git a/wallet/src/program_facades/token.rs b/wallet/src/program_facades/token.rs index e7bdca9..fc03a0a 100644 --- a/wallet/src/program_facades/token.rs +++ b/wallet/src/program_facades/token.rs @@ -1,9 +1,6 @@ use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse}; use nssa::{AccountId, program::Program}; -use nssa_core::{ - NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey, - program::InstructionData, -}; +use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey}; use crate::{PrivacyPreservingAccount, WalletCore}; @@ -20,7 +17,7 @@ impl Token<'_> { let account_ids = vec![definition_account_id, supply_account_id]; let program_id = nssa::program::Program::token().id(); // Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)] - let mut instruction = [0; 23]; + let mut instruction = vec![0u8; 23]; instruction[1..17].copy_from_slice(&total_supply.to_le_bytes()); instruction[17..].copy_from_slice(&name); let message = nssa::public_transaction::Message::try_new( @@ -45,7 +42,9 @@ impl Token<'_> { name: [u8; 6], total_supply: u128, ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let (instruction_data, program) = token_program_preparation_definition(name, total_supply); + let instruction = token_program_preparation_definition(name, total_supply); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); self.0 .send_privacy_preserving_tx( @@ -54,7 +53,7 @@ impl Token<'_> { PrivacyPreservingAccount::PrivateOwned(supply_account_id), ], &instruction_data, - &program.into(), + &Program::token().into(), ) .await .map(|(resp, secrets)| { @@ -73,7 +72,9 @@ impl Token<'_> { name: [u8; 6], total_supply: u128, ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let (instruction_data, program) = token_program_preparation_definition(name, total_supply); + let instruction = token_program_preparation_definition(name, total_supply); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); self.0 .send_privacy_preserving_tx( @@ -82,7 +83,7 @@ impl Token<'_> { PrivacyPreservingAccount::Public(supply_account_id), ], &instruction_data, - &program.into(), + &Program::token().into(), ) .await .map(|(resp, secrets)| { @@ -101,7 +102,9 @@ impl Token<'_> { name: [u8; 6], total_supply: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let (instruction_data, program) = token_program_preparation_definition(name, total_supply); + let instruction = token_program_preparation_definition(name, total_supply); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); self.0 .send_privacy_preserving_tx( @@ -110,7 +113,7 @@ impl Token<'_> { PrivacyPreservingAccount::PrivateOwned(supply_account_id), ], &instruction_data, - &program.into(), + &Program::token().into(), ) .await .map(|(resp, secrets)| { @@ -131,7 +134,7 @@ impl Token<'_> { let program_id = nssa::program::Program::token().id(); // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || // 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; + let mut instruction = vec![0u8; 23]; instruction[0] = 0x01; instruction[1..17].copy_from_slice(&amount.to_le_bytes()); let Ok(nonces) = self.0.get_accounts_nonces(vec![sender_account_id]).await else { @@ -167,7 +170,9 @@ impl Token<'_> { recipient_account_id: AccountId, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let (instruction_data, program) = token_program_preparation_transfer(amount); + let instruction = token_program_preparation_transfer(amount); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); self.0 .send_privacy_preserving_tx( @@ -176,7 +181,7 @@ impl Token<'_> { PrivacyPreservingAccount::PrivateOwned(recipient_account_id), ], &instruction_data, - &program.into(), + &Program::token().into(), ) .await .map(|(resp, secrets)| { @@ -194,7 +199,9 @@ impl Token<'_> { recipient_ipk: IncomingViewingPublicKey, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let (instruction_data, program) = token_program_preparation_transfer(amount); + let instruction = token_program_preparation_transfer(amount); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); self.0 .send_privacy_preserving_tx( @@ -206,7 +213,7 @@ impl Token<'_> { }, ], &instruction_data, - &program.into(), + &Program::token().into(), ) .await .map(|(resp, secrets)| { @@ -223,7 +230,9 @@ impl Token<'_> { recipient_account_id: AccountId, amount: u128, ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let (instruction_data, program) = token_program_preparation_transfer(amount); + let instruction = token_program_preparation_transfer(amount); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); self.0 .send_privacy_preserving_tx( @@ -232,7 +241,7 @@ impl Token<'_> { PrivacyPreservingAccount::Public(recipient_account_id), ], &instruction_data, - &program.into(), + &Program::token().into(), ) .await .map(|(resp, secrets)| { @@ -250,7 +259,9 @@ impl Token<'_> { recipient_account_id: AccountId, amount: u128, ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let (instruction_data, program) = token_program_preparation_transfer(amount); + let instruction = token_program_preparation_transfer(amount); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); self.0 .send_privacy_preserving_tx( @@ -259,7 +270,7 @@ impl Token<'_> { PrivacyPreservingAccount::PrivateOwned(recipient_account_id), ], &instruction_data, - &program.into(), + &Program::token().into(), ) .await .map(|(resp, secrets)| { @@ -278,7 +289,9 @@ impl Token<'_> { recipient_ipk: IncomingViewingPublicKey, amount: u128, ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let (instruction_data, program) = token_program_preparation_transfer(amount); + let instruction = token_program_preparation_transfer(amount); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); self.0 .send_privacy_preserving_tx( @@ -290,7 +303,7 @@ impl Token<'_> { }, ], &instruction_data, - &program.into(), + &Program::token().into(), ) .await .map(|(resp, secrets)| { @@ -301,30 +314,354 @@ impl Token<'_> { (resp, first) }) } + + pub async fn send_burn_transaction( + &self, + definition_account_id: AccountId, + holder_account_id: AccountId, + amount: u128, + ) -> Result { + let account_ids = vec![definition_account_id, holder_account_id]; + let instruction = token_program_preparation_burn(amount); + + let Ok(nonces) = self.0.get_accounts_nonces(vec![holder_account_id]).await else { + return Err(ExecutionFailureKind::SequencerError); + }; + let message = nssa::public_transaction::Message::try_new( + Program::token().id(), + account_ids, + nonces, + instruction, + ) + .expect("Instruction should serialize"); + + let signing_key = self + .0 + .storage + .user_data + .get_pub_account_signing_key(&holder_account_id) + .ok_or(ExecutionFailureKind::KeyNotFoundError)?; + let witness_set = + nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]); + + let tx = nssa::PublicTransaction::new(message, witness_set); + + Ok(self.0.sequencer_client.send_tx_public(tx).await?) + } + + pub async fn send_burn_transaction_private_owned_account( + &self, + definition_account_id: AccountId, + holder_account_id: AccountId, + amount: u128, + ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + let instruction = token_program_preparation_burn(amount); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); + + self.0 + .send_privacy_preserving_tx( + vec![ + PrivacyPreservingAccount::PrivateOwned(definition_account_id), + PrivacyPreservingAccount::PrivateOwned(holder_account_id), + ], + &instruction_data, + &Program::token().into(), + ) + .await + .map(|(resp, secrets)| { + let mut iter = secrets.into_iter(); + let first = iter.next().expect("expected definition's secret"); + let second = iter.next().expect("expected holder's secret"); + (resp, [first, second]) + }) + } + + pub async fn send_burn_transaction_deshielded_owned_account( + &self, + definition_account_id: AccountId, + holder_account_id: AccountId, + amount: u128, + ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + let instruction = token_program_preparation_burn(amount); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); + + self.0 + .send_privacy_preserving_tx( + vec![ + PrivacyPreservingAccount::PrivateOwned(definition_account_id), + PrivacyPreservingAccount::Public(holder_account_id), + ], + &instruction_data, + &Program::token().into(), + ) + .await + .map(|(resp, secrets)| { + let first = secrets + .into_iter() + .next() + .expect("expected definition's secret"); + (resp, first) + }) + } + + pub async fn send_burn_transaction_shielded( + &self, + definition_account_id: AccountId, + holder_account_id: AccountId, + amount: u128, + ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + let instruction = token_program_preparation_burn(amount); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); + + self.0 + .send_privacy_preserving_tx( + vec![ + PrivacyPreservingAccount::Public(definition_account_id), + PrivacyPreservingAccount::PrivateOwned(holder_account_id), + ], + &instruction_data, + &Program::token().into(), + ) + .await + .map(|(resp, secrets)| { + let first = secrets + .into_iter() + .next() + .expect("expected holder's secret"); + (resp, first) + }) + } + + pub async fn send_mint_transaction( + &self, + definition_account_id: AccountId, + holder_account_id: AccountId, + amount: u128, + ) -> Result { + let account_ids = vec![definition_account_id, holder_account_id]; + let instruction = token_program_preparation_mint(amount); + + let Ok(nonces) = self + .0 + .get_accounts_nonces(vec![definition_account_id]) + .await + else { + return Err(ExecutionFailureKind::SequencerError); + }; + let message = nssa::public_transaction::Message::try_new( + Program::token().id(), + account_ids, + nonces, + instruction, + ) + .unwrap(); + + let Some(signing_key) = self + .0 + .storage + .user_data + .get_pub_account_signing_key(&definition_account_id) + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + let witness_set = + nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]); + + let tx = nssa::PublicTransaction::new(message, witness_set); + + Ok(self.0.sequencer_client.send_tx_public(tx).await?) + } + + pub async fn send_mint_transaction_private_owned_account( + &self, + definition_account_id: AccountId, + holder_account_id: AccountId, + amount: u128, + ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + let instruction = token_program_preparation_mint(amount); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); + + self.0 + .send_privacy_preserving_tx( + vec![ + PrivacyPreservingAccount::PrivateOwned(definition_account_id), + PrivacyPreservingAccount::PrivateOwned(holder_account_id), + ], + &instruction_data, + &Program::token().into(), + ) + .await + .map(|(resp, secrets)| { + let mut iter = secrets.into_iter(); + let first = iter.next().expect("expected definition's secret"); + let second = iter.next().expect("expected holder's secret"); + (resp, [first, second]) + }) + } + + pub async fn send_mint_transaction_private_foreign_account( + &self, + definition_account_id: AccountId, + holder_npk: NullifierPublicKey, + holder_ipk: IncomingViewingPublicKey, + amount: u128, + ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + let instruction = token_program_preparation_mint(amount); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); + + self.0 + .send_privacy_preserving_tx( + vec![ + PrivacyPreservingAccount::PrivateOwned(definition_account_id), + PrivacyPreservingAccount::PrivateForeign { + npk: holder_npk, + ipk: holder_ipk, + }, + ], + &instruction_data, + &Program::token().into(), + ) + .await + .map(|(resp, secrets)| { + let mut iter = secrets.into_iter(); + let first = iter.next().expect("expected definition's secret"); + let second = iter.next().expect("expected holder's secret"); + (resp, [first, second]) + }) + } + + pub async fn send_mint_transaction_deshielded( + &self, + definition_account_id: AccountId, + holder_account_id: AccountId, + amount: u128, + ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + let instruction = token_program_preparation_mint(amount); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); + + self.0 + .send_privacy_preserving_tx( + vec![ + PrivacyPreservingAccount::PrivateOwned(definition_account_id), + PrivacyPreservingAccount::Public(holder_account_id), + ], + &instruction_data, + &Program::token().into(), + ) + .await + .map(|(resp, secrets)| { + let first = secrets + .into_iter() + .next() + .expect("expected definition's secret"); + (resp, first) + }) + } + + pub async fn send_mint_transaction_shielded_owned_account( + &self, + definition_account_id: AccountId, + holder_account_id: AccountId, + amount: u128, + ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + let instruction = token_program_preparation_mint(amount); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); + + self.0 + .send_privacy_preserving_tx( + vec![ + PrivacyPreservingAccount::Public(definition_account_id), + PrivacyPreservingAccount::PrivateOwned(holder_account_id), + ], + &instruction_data, + &Program::token().into(), + ) + .await + .map(|(resp, secrets)| { + let first = secrets + .into_iter() + .next() + .expect("expected holder's secret"); + (resp, first) + }) + } + + pub async fn send_mint_transaction_shielded_foreign_account( + &self, + definition_account_id: AccountId, + holder_npk: NullifierPublicKey, + holder_ipk: IncomingViewingPublicKey, + amount: u128, + ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + let instruction = token_program_preparation_mint(amount); + let instruction_data = + Program::serialize_instruction(instruction).expect("Instruction should serialize"); + + self.0 + .send_privacy_preserving_tx( + vec![ + PrivacyPreservingAccount::Public(definition_account_id), + PrivacyPreservingAccount::PrivateForeign { + npk: holder_npk, + ipk: holder_ipk, + }, + ], + &instruction_data, + &Program::token().into(), + ) + .await + .map(|(resp, secrets)| { + let first = secrets + .into_iter() + .next() + .expect("expected holder's secret"); + (resp, first) + }) + } } -fn token_program_preparation_transfer(amount: u128) -> (InstructionData, Program) { +fn token_program_preparation_transfer(amount: u128) -> Vec { // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || // 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; + let mut instruction = vec![0u8; 23]; instruction[0] = 0x01; instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - let instruction_data = Program::serialize_instruction(instruction).unwrap(); - let program = Program::token(); - (instruction_data, program) + instruction } -fn token_program_preparation_definition( - name: [u8; 6], - total_supply: u128, -) -> (InstructionData, Program) { +fn token_program_preparation_definition(name: [u8; 6], total_supply: u128) -> Vec { // Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)] - let mut instruction = [0; 23]; + let mut instruction = vec![0u8; 23]; instruction[1..17].copy_from_slice(&total_supply.to_le_bytes()); instruction[17..].copy_from_slice(&name); - let instruction_data = Program::serialize_instruction(instruction).unwrap(); - let program = Program::token(); - (instruction_data, program) + instruction +} + +fn token_program_preparation_burn(amount: u128) -> Vec { + // Instruction must be: [0x03 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || + // 0x00 || 0x00 || 0x00]. + let mut instruction = vec![0; 23]; + instruction[0] = 0x03; + instruction[1..17].copy_from_slice(&amount.to_le_bytes()); + + instruction +} + +fn token_program_preparation_mint(amount: u128) -> Vec { + // Instruction must be: [0x04 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || + // 0x00 || 0x00 || 0x00]. + let mut instruction = vec![0; 23]; + instruction[0] = 0x04; + instruction[1..17].copy_from_slice(&amount.to_le_bytes()); + + instruction }