From 5212d456abb4d0e60c81dee5172411a8532e20b8 Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Fri, 12 Dec 2025 13:40:56 +0200 Subject: [PATCH] fix: integration tests --- integration_tests/src/test_suite_map.rs | 781 ++++++++++++++++-------- wallet/src/cli/programs/token.rs | 240 ++------ wallet/src/program_facades/token.rs | 61 -- 3 files changed, 575 insertions(+), 507 deletions(-) diff --git a/integration_tests/src/test_suite_map.rs b/integration_tests/src/test_suite_map.rs index ccd7906..758bec2 100644 --- a/integration_tests/src/test_suite_map.rs +++ b/integration_tests/src/test_suite_map.rs @@ -434,6 +434,90 @@ 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 + ] + ); + + // 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 + ] + ); + + // 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 @@ -590,6 +674,188 @@ 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 + ] + ); + + 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 + ] + ); + + 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 + ] + ); + + 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 @@ -673,6 +939,277 @@ 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 + ] + ); + + // 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 + ] + ); + + 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 + ] + ); + + 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 + ] + ); + + // 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 + ] + ); + + 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 @@ -1548,250 +2085,6 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } - /// This test creates a new token using the token program. After creating the token, the test - /// executes a token transfer to a new account then mint, then burn. - #[nssa_integration_test] - pub async fn test_success_token_program_burn_mint() { - info!("########## test_success_token_program_burn_mint ##########"); - let wallet_config = fetch_config().await.unwrap(); - - // Create new account for the token definition - let SubcommandReturnValue::RegisterAccount { - account_id: definition_account_id, - } = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New( - NewSubcommand::Public { cci: None }, - ))) - .await - .unwrap() - else { - panic!("invalid subcommand return value"); - }; - // Create new account for the token supply holder - let SubcommandReturnValue::RegisterAccount { - account_id: supply_account_id, - } = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New( - NewSubcommand::Public { cci: None }, - ))) - .await - .unwrap() - else { - panic!("invalid subcommand return value"); - }; - // Create new account for receiving a token transaction - let SubcommandReturnValue::RegisterAccount { - account_id: recipient_account_id, - } = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New( - NewSubcommand::Public { cci: None }, - ))) - .await - .unwrap() - else { - panic!("invalid subcommand return value"); - }; - - // Create new token - let subcommand = TokenProgramAgnosticSubcommand::New { - definition_account_id: make_public_account_input_from_str( - &definition_account_id.to_string(), - ), - supply_account_id: make_public_account_input_from_str(&supply_account_id.to_string()), - name: "A NAME".to_string(), - total_supply: 37, - }; - wallet::cli::execute_subcommand(Command::Token(subcommand)) - .await - .unwrap(); - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - // 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.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) ] - 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 - ] - ); - - // Check the status of the token holding account with the total supply is the expected after - // the execution - let supply_acc = seq_client - .get_account(supply_account_id.to_string()) - .await - .unwrap() - .account; - - // The account must be owned by the token program - assert_eq!(supply_acc.program_owner, Program::token().id()); - // The data of a token definition account has the following layout: - // [ 0x01 || corresponding_token_definition_id (32 bytes) || balance (little endian 16 - // bytes) ] First byte of the data equal to 1 means it's a token holding account - assert_eq!(supply_acc.data.as_ref()[0], 1); - // Bytes from 1 to 33 represent the id of the token this account is associated with. - // In this example, this is a token account of the newly created token, so it is expected - // to be equal to the account_id of the token definition account. - assert_eq!( - &supply_acc.data.as_ref()[1..33], - definition_account_id.to_bytes() - ); - assert_eq!( - u128::from_le_bytes(supply_acc.data[33..].try_into().unwrap()), - 37 - ); - - // Transfer 7 tokens from `supply_acc` to the account at account_id `recipient_account_id` - let subcommand = TokenProgramAgnosticSubcommand::Send { - from: make_public_account_input_from_str(&supply_account_id.to_string()), - to: Some(make_public_account_input_from_str( - &recipient_account_id.to_string(), - )), - to_npk: None, - to_ipk: None, - amount: 7, - }; - - 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 account at `supply_account_id` is the expected after the - // execution - let supply_acc = seq_client - .get_account(supply_account_id.to_string()) - .await - .unwrap() - .account; - // The account must be owned by the token program - assert_eq!(supply_acc.program_owner, Program::token().id()); - // First byte equal to 1 means it's a token holding account - assert_eq!(supply_acc.data[0], 1); - // Bytes from 1 to 33 represent the id of the token this account is associated with. - assert_eq!(&supply_acc.data[1..33], definition_account_id.to_bytes()); - assert_eq!( - u128::from_le_bytes(supply_acc.data[33..].try_into().unwrap()), - 30 - ); - - // 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; - - // The account must be owned by the token program - assert_eq!(recipient_acc.program_owner, Program::token().id()); - // First byte equal to 1 means it's a token holding account - assert_eq!(recipient_acc.data[0], 1); - // Bytes from 1 to 33 represent the id of the token this account is associated with. - assert_eq!(&recipient_acc.data[1..33], definition_account_id.to_bytes()); - assert_eq!( - u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()), - 7 - ); - - // Burn 3 tokens from `recipient_acc` - let subcommand = TokenProgramAgnosticSubcommand::Burn { - definition: Some(make_public_account_input_from_str( - &definition_account_id.to_string(), - )), - definition_npk: None, - definition_ipk: None, - 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 - ] - ); - - // 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 - ] - ); - - // 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 - ); - } - #[nssa_integration_test] pub async fn test_pinata() { info!("########## test_pinata ##########"); diff --git a/wallet/src/cli/programs/token.rs b/wallet/src/cli/programs/token.rs index 24f314e..1a3b256 100644 --- a/wallet/src/cli/programs/token.rs +++ b/wallet/src/cli/programs/token.rs @@ -4,7 +4,7 @@ use common::transaction::NSSATransaction; use nssa::AccountId; use crate::{ - AccDecodeData::{Decode, Skip}, + AccDecodeData::Decode, WalletCore, cli::{SubcommandReturnValue, WalletSubcommand}, helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix}, @@ -54,20 +54,14 @@ pub enum TokenProgramAgnosticSubcommand { /// /// `holder` is owned /// - /// If `definition` is private, then `definition` and (`definition_npk` , `definition_ipk`) is a - /// mutually exclusive patterns. + /// Also if `definition` is private then it is owned, because + /// we can not modify foreign accounts. /// - /// First is used for owned accounts, second otherwise. + /// ToDo: Return and add foreign variant when we could modify foreign accounts Burn { /// definition - valid 32 byte base58 string with privacy prefix #[arg(long)] - definition: Option, - /// definition_npk - valid 32 byte hex string - #[arg(long)] - definition_npk: Option, - /// definition_ipk - valid 33 byte hex string - #[arg(long)] - definition_ipk: Option, + definition: String, /// holder - valid 32 byte base58 string with privacy prefix #[arg(long)] holder: String, @@ -256,89 +250,50 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { } TokenProgramAgnosticSubcommand::Burn { definition, - definition_npk, - definition_ipk, holder, amount, } => { - let underlying_subcommand = match (definition, definition_npk, definition_ipk) { - (None, None, None) => { - anyhow::bail!( - "Provide either account account_id of definition or their public keys" - ); - } - (Some(_), Some(_), Some(_)) => { - anyhow::bail!( - "Provide only one variant: either account_id of definition or their public keys" - ); - } - (_, Some(_), None) | (_, None, Some(_)) => { - anyhow::bail!("List of public keys is uncomplete"); - } - (Some(definition), None, None) => { - let (definition, definition_privacy) = - parse_addr_with_privacy_prefix(&definition)?; - let (holder, holder_privacy) = parse_addr_with_privacy_prefix(&holder)?; + 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, - }, - ) - } + match (definition_privacy, holder_privacy) { + (AccountPrivacyKind::Public, AccountPrivacyKind::Public) => { + TokenProgramSubcommand::Public( + TokenProgramSubcommandPublic::BurnToken { + definition_account_id: definition, + holder_account_id: holder, + amount, + }, + ) } - } - (None, Some(definition_npk), Some(definition_ipk)) => { - let (holder, holder_privacy) = parse_addr_with_privacy_prefix(&holder)?; - - match holder_privacy { - AccountPrivacyKind::Private => TokenProgramSubcommand::Private( - TokenProgramSubcommandPrivate::BurnTokenPrivateForeign { - definition_npk, - definition_ipk, + (AccountPrivacyKind::Private, AccountPrivacyKind::Private) => { + TokenProgramSubcommand::Private( + TokenProgramSubcommandPrivate::BurnTokenPrivateOwned { + definition_account_id: definition, holder_account_id: holder, amount, }, - ), - AccountPrivacyKind::Public => TokenProgramSubcommand::Deshielded( - TokenProgramSubcommandDeshielded::BurnTokenDeshieldedForeign { - definition_npk, - definition_ipk, + ) + } + (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, + }, + ) } } }; @@ -536,17 +491,6 @@ pub enum TokenProgramSubcommandPrivate { #[arg(short, long)] amount: u128, }, - // Burn tokens using the token program - BurnTokenPrivateForeign { - #[arg(short, long)] - definition_npk: String, - #[arg(short, long)] - definition_ipk: String, - #[arg(short, long)] - holder_account_id: String, - #[arg(short, long)] - amount: u128, - }, // Transfer tokens using the token program MintTokenPrivateForeign { #[arg(short, long)] @@ -590,17 +534,6 @@ pub enum TokenProgramSubcommandDeshielded { #[arg(short, long)] amount: u128, }, - // Burn tokens using the token program - BurnTokenDeshieldedForeign { - #[arg(short, long)] - definition_npk: String, - #[arg(short, long)] - definition_ipk: 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 @@ -906,57 +839,6 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) } - TokenProgramSubcommandPrivate::BurnTokenPrivateForeign { - definition_npk, - definition_ipk, - holder_account_id, - amount, - } => { - let definition_npk_res = hex::decode(definition_npk)?; - let mut definition_npk = [0; 32]; - definition_npk.copy_from_slice(&definition_npk_res); - let definition_npk = nssa_core::NullifierPublicKey(definition_npk); - - let definition_ipk_res = hex::decode(definition_ipk)?; - let mut definition_ipk = [0u8; 33]; - definition_ipk.copy_from_slice(&definition_ipk_res); - let definition_ipk = nssa_core::encryption::shared_key_derivation::Secp256k1Point( - definition_ipk.to_vec(), - ); - - let holder_account_id: AccountId = holder_account_id.parse().unwrap(); - - let (res, [_, secret_holder]) = Token(wallet_core) - .send_burn_transaction_private_foreign_account( - definition_npk, - definition_ipk, - 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![Skip, 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, @@ -1135,52 +1017,6 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) } - TokenProgramSubcommandDeshielded::BurnTokenDeshieldedForeign { - definition_npk, - definition_ipk, - holder_account_id, - amount, - } => { - let definition_npk_res = hex::decode(definition_npk)?; - let mut definition_npk = [0; 32]; - definition_npk.copy_from_slice(&definition_npk_res); - let definition_npk = nssa_core::NullifierPublicKey(definition_npk); - - let definition_ipk_res = hex::decode(definition_ipk)?; - let mut definition_ipk = [0u8; 33]; - definition_ipk.copy_from_slice(&definition_ipk_res); - let definition_ipk = nssa_core::encryption::shared_key_derivation::Secp256k1Point( - definition_ipk.to_vec(), - ); - - let holder_account_id: AccountId = holder_account_id.parse().unwrap(); - - let (res, _) = Token(wallet_core) - .send_burn_transaction_deshielded_foreign_account( - definition_npk, - definition_ipk, - 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 { - 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 }) - } TokenProgramSubcommandDeshielded::MintTokenDeshielded { definition_account_id, holder_account_id, diff --git a/wallet/src/program_facades/token.rs b/wallet/src/program_facades/token.rs index 804924b..a32fef9 100644 --- a/wallet/src/program_facades/token.rs +++ b/wallet/src/program_facades/token.rs @@ -367,36 +367,6 @@ impl Token<'_> { }) } - pub async fn send_burn_transaction_private_foreign_account( - &self, - definition_npk: NullifierPublicKey, - definition_ipk: IncomingViewingPublicKey, - holder_account_id: AccountId, - amount: u128, - ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let (instruction_data, program) = token_program_preparation_burn(amount); - - self.0 - .send_privacy_preserving_tx( - vec![ - PrivacyPreservingAccount::PrivateForeign { - npk: definition_npk, - ipk: definition_ipk, - }, - PrivacyPreservingAccount::PrivateOwned(holder_account_id), - ], - &instruction_data, - &program, - ) - .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, @@ -451,37 +421,6 @@ impl Token<'_> { }) } - pub async fn send_burn_transaction_deshielded_foreign_account( - &self, - definition_npk: NullifierPublicKey, - definition_ipk: IncomingViewingPublicKey, - holder_account_id: AccountId, - amount: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let (instruction_data, program) = token_program_preparation_burn(amount); - - self.0 - .send_privacy_preserving_tx( - vec![ - PrivacyPreservingAccount::PrivateForeign { - npk: definition_npk, - ipk: definition_ipk, - }, - PrivacyPreservingAccount::Public(holder_account_id), - ], - &instruction_data, - &program, - ) - .await - .map(|(resp, secrets)| { - let first = secrets - .into_iter() - .next() - .expect("expected definition's secret"); - (resp, first) - }) - } - pub async fn send_mint_transaction( &self, definition_account_id: AccountId,