From bab6aaf947466892b7faa2accf221241dac5e8c2 Mon Sep 17 00:00:00 2001 From: fryorcraken Date: Tue, 24 Mar 2026 12:04:13 +1100 Subject: [PATCH] revert changes and add tests --- integration_tests/tests/amm.rs | 185 ++++++++++++++ .../tests/auth_transfer/private.rs | 104 +++++++- .../tests/auth_transfer/public.rs | 94 +++++++ integration_tests/tests/indexer.rs | 81 +++++- integration_tests/tests/keys_restoration.rs | 11 +- integration_tests/tests/token.rs | 239 ++++++++++++++++-- 6 files changed, 679 insertions(+), 35 deletions(-) diff --git a/integration_tests/tests/amm.rs b/integration_tests/tests/amm.rs index 1c6c5410..ef5af047 100644 --- a/integration_tests/tests/amm.rs +++ b/integration_tests/tests/amm.rs @@ -420,3 +420,188 @@ async fn amm_public() -> Result<()> { Ok(()) } + +#[test] +async fn amm_new_pool_using_labels() -> Result<()> { + let mut ctx = TestContext::new().await?; + + // Create token 1 accounts + let SubcommandReturnValue::RegisterAccount { + account_id: definition_account_id_1, + } = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), + ) + .await? + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + let SubcommandReturnValue::RegisterAccount { + account_id: supply_account_id_1, + } = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), + ) + .await? + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create holding_a with a label + let holding_a_label = "amm-holding-a-label".to_owned(); + let SubcommandReturnValue::RegisterAccount { + account_id: holding_a_id, + } = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: Some(holding_a_label.clone()), + })), + ) + .await? + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create token 2 accounts + let SubcommandReturnValue::RegisterAccount { + account_id: definition_account_id_2, + } = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), + ) + .await? + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + let SubcommandReturnValue::RegisterAccount { + account_id: supply_account_id_2, + } = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), + ) + .await? + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create holding_b with a label + let holding_b_label = "amm-holding-b-label".to_owned(); + let SubcommandReturnValue::RegisterAccount { + account_id: holding_b_id, + } = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: Some(holding_b_label.clone()), + })), + ) + .await? + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create holding_lp with a label + let holding_lp_label = "amm-holding-lp-label".to_owned(); + let SubcommandReturnValue::RegisterAccount { + account_id: holding_lp_id, + } = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: Some(holding_lp_label.clone()), + })), + ) + .await? + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create token 1 and distribute to holding_a + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_account_id: Some(format_public_account_id(definition_account_id_1)), + definition_account_label: None, + supply_account_id: Some(format_public_account_id(supply_account_id_1)), + supply_account_label: None, + name: "TOKEN1".to_string(), + total_supply: 10, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: Some(format_public_account_id(supply_account_id_1)), + from_label: None, + to: Some(format_public_account_id(holding_a_id)), + to_label: None, + to_npk: None, + to_vpk: None, + amount: 5, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + // Create token 2 and distribute to holding_b + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_account_id: Some(format_public_account_id(definition_account_id_2)), + definition_account_label: None, + supply_account_id: Some(format_public_account_id(supply_account_id_2)), + supply_account_label: None, + name: "TOKEN2".to_string(), + total_supply: 10, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: Some(format_public_account_id(supply_account_id_2)), + from_label: None, + to: Some(format_public_account_id(holding_b_id)), + to_label: None, + to_npk: None, + to_vpk: None, + amount: 5, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + // Create AMM pool using account labels instead of IDs + let subcommand = AmmProgramAgnosticSubcommand::New { + user_holding_a: None, + user_holding_a_label: Some(holding_a_label), + user_holding_b: None, + user_holding_b_label: Some(holding_b_label), + user_holding_lp: None, + user_holding_lp_label: Some(holding_lp_label), + balance_a: 3, + balance_b: 3, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::AMM(subcommand)).await?; + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let holding_lp_acc = ctx.sequencer_client().get_account(holding_lp_id).await?; + + // LP balance should be 3 (geometric mean of 3, 3) + assert_eq!( + u128::from_le_bytes(holding_lp_acc.data[33..].try_into().unwrap()), + 3 + ); + + info!("Successfully created AMM pool using account labels"); + + Ok(()) +} diff --git a/integration_tests/tests/auth_transfer/private.rs b/integration_tests/tests/auth_transfer/private.rs index 01376386..9ffbcb0d 100644 --- a/integration_tests/tests/auth_transfer/private.rs +++ b/integration_tests/tests/auth_transfer/private.rs @@ -8,6 +8,7 @@ use integration_tests::{ use log::info; use nssa::{AccountId, program::Program}; use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point}; +use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::cli::{ Command, SubcommandReturnValue, @@ -141,7 +142,7 @@ async fn deshielded_transfer_to_public_account() -> Result<()> { let acc_2_balance = ctx.sequencer_client().get_account_balance(to).await?; assert_eq!(from_acc.balance, 9900); - assert_eq!(acc_2_balance.balance, 20100); + assert_eq!(acc_2_balance, 20100); info!("Successfully deshielded transfer to public account"); @@ -255,7 +256,7 @@ async fn shielded_transfer_to_owned_private_account() -> Result<()> { let acc_from_balance = ctx.sequencer_client().get_account_balance(from).await?; - assert_eq!(acc_from_balance.balance, 9900); + assert_eq!(acc_from_balance, 9900); assert_eq!(acc_to.balance, 20100); info!("Successfully shielded transfer to owned private account"); @@ -302,7 +303,7 @@ async fn shielded_transfer_to_foreign_account() -> Result<()> { .await ); - assert_eq!(acc_1_balance.balance, 9900); + assert_eq!(acc_1_balance, 9900); info!("Successfully shielded transfer to foreign account"); @@ -429,3 +430,100 @@ async fn initialize_private_account() -> Result<()> { Ok(()) } + +#[test] +async fn private_transfer_using_from_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + let from: AccountId = ctx.existing_private_accounts()[0]; + let to: AccountId = ctx.existing_private_accounts()[1]; + + // Assign a label to the sender account + let label = "private-sender-label".to_owned(); + let command = Command::Account(AccountSubcommand::Label { + account_id: Some(format_private_account_id(from)), + account_label: None, + label: label.clone(), + }); + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + // Send using the label instead of account ID + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: None, + from_label: Some(label), + to: Some(format_private_account_id(to)), + to_label: None, + to_npk: None, + to_vpk: None, + amount: 100, + }); + + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let new_commitment1 = ctx + .wallet() + .get_private_account_commitment(from) + .context("Failed to get private account commitment for sender")?; + assert!(verify_commitment_is_in_state(new_commitment1, ctx.sequencer_client()).await); + + let new_commitment2 = ctx + .wallet() + .get_private_account_commitment(to) + .context("Failed to get private account commitment for receiver")?; + assert!(verify_commitment_is_in_state(new_commitment2, ctx.sequencer_client()).await); + + info!("Successfully transferred privately using from_label"); + + Ok(()) +} + +#[test] +async fn initialize_private_account_using_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + // Create a new private account with a label + let label = "init-private-label".to_owned(); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: Some(label.clone()), + })); + let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + let SubcommandReturnValue::RegisterAccount { account_id } = result else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Initialize using the label instead of account ID + let command = Command::AuthTransfer(AuthTransferSubcommand::Init { + account_id: None, + account_label: Some(label), + }); + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let command = Command::Account(AccountSubcommand::SyncPrivate {}); + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + let new_commitment = ctx + .wallet() + .get_private_account_commitment(account_id) + .context("Failed to get private account commitment")?; + assert!(verify_commitment_is_in_state(new_commitment, ctx.sequencer_client()).await); + + let account = ctx + .wallet() + .get_account_private(account_id) + .context("Failed to get private account")?; + + assert_eq!( + account.program_owner, + Program::authenticated_transfer_program().id() + ); + + info!("Successfully initialized private account using label"); + + Ok(()) +} diff --git a/integration_tests/tests/auth_transfer/public.rs b/integration_tests/tests/auth_transfer/public.rs index 80f9d4e4..416c4490 100644 --- a/integration_tests/tests/auth_transfer/public.rs +++ b/integration_tests/tests/auth_transfer/public.rs @@ -256,3 +256,97 @@ async fn initialize_public_account() -> Result<()> { Ok(()) } + +#[test] +async fn successful_transfer_using_from_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + // Assign a label to the sender account + let label = "sender-label".to_owned(); + let command = Command::Account(AccountSubcommand::Label { + account_id: Some(format_public_account_id(ctx.existing_public_accounts()[0])), + account_label: None, + label: label.clone(), + }); + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + // Send using the label instead of account ID + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: None, + from_label: Some(label), + to: Some(format_public_account_id(ctx.existing_public_accounts()[1])), + to_label: None, + to_npk: None, + to_vpk: None, + amount: 100, + }); + + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + info!("Checking correct balance move"); + let acc_1_balance = ctx + .sequencer_client() + .get_account_balance(ctx.existing_public_accounts()[0]) + .await?; + let acc_2_balance = ctx + .sequencer_client() + .get_account_balance(ctx.existing_public_accounts()[1]) + .await?; + + assert_eq!(acc_1_balance, 9900); + assert_eq!(acc_2_balance, 20100); + + info!("Successfully transferred using from_label"); + + Ok(()) +} + +#[test] +async fn successful_transfer_using_to_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + // Assign a label to the receiver account + let label = "receiver-label".to_owned(); + let command = Command::Account(AccountSubcommand::Label { + account_id: Some(format_public_account_id(ctx.existing_public_accounts()[1])), + account_label: None, + label: label.clone(), + }); + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + // Send using the label for the recipient + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: Some(format_public_account_id(ctx.existing_public_accounts()[0])), + from_label: None, + to: None, + to_label: Some(label), + to_npk: None, + to_vpk: None, + amount: 100, + }); + + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + info!("Checking correct balance move"); + let acc_1_balance = ctx + .sequencer_client() + .get_account_balance(ctx.existing_public_accounts()[0]) + .await?; + let acc_2_balance = ctx + .sequencer_client() + .get_account_balance(ctx.existing_public_accounts()[1]) + .await?; + + assert_eq!(acc_1_balance, 9900); + assert_eq!(acc_2_balance, 20100); + + info!("Successfully transferred using to_label"); + + Ok(()) +} diff --git a/integration_tests/tests/indexer.rs b/integration_tests/tests/indexer.rs index 4c9c5ee6..5f814e32 100644 --- a/integration_tests/tests/indexer.rs +++ b/integration_tests/tests/indexer.rs @@ -5,10 +5,14 @@ use std::time::Duration; -use anyhow::Result; +use anyhow::{Context as _, Result}; use indexer_service_rpc::RpcClient as _; -use integration_tests::{TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, format_public_account_id}; +use integration_tests::{ + TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, format_private_account_id, + format_public_account_id, verify_commitment_is_in_state, +}; use log::info; +use nssa::AccountId; use tokio::test; use wallet::cli::{Command, programs::native_token_transfer::AuthTransferSubcommand}; @@ -181,3 +185,76 @@ async fn indexer_state_consistency() -> Result<()> { Ok(()) } + +#[test] +async fn indexer_state_consistency_with_labels() -> Result<()> { + let mut ctx = TestContext::new().await?; + + // Assign labels to both accounts + let from_label = "idx-sender-label".to_owned(); + let to_label_str = "idx-receiver-label".to_owned(); + + let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label { + account_id: Some(format_public_account_id(ctx.existing_public_accounts()[0])), + account_label: None, + label: from_label.clone(), + }); + wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd).await?; + + let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label { + account_id: Some(format_public_account_id(ctx.existing_public_accounts()[1])), + account_label: None, + label: to_label_str.clone(), + }); + wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd).await?; + + // Send using labels instead of account IDs + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: None, + from_label: Some(from_label), + to: None, + to_label: Some(to_label_str), + to_npk: None, + to_vpk: None, + amount: 100, + }); + + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let acc_1_balance = sequencer_service_rpc::RpcClient::get_account_balance( + ctx.sequencer_client(), + ctx.existing_public_accounts()[0], + ) + .await?; + let acc_2_balance = sequencer_service_rpc::RpcClient::get_account_balance( + ctx.sequencer_client(), + ctx.existing_public_accounts()[1], + ) + .await?; + + assert_eq!(acc_1_balance, 9900); + assert_eq!(acc_2_balance, 20100); + + info!("Waiting for indexer to parse blocks"); + tokio::time::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)).await; + + let acc1_ind_state = ctx + .indexer_client() + .get_account(ctx.existing_public_accounts()[0].into()) + .await + .unwrap(); + let acc1_seq_state = sequencer_service_rpc::RpcClient::get_account( + ctx.sequencer_client(), + ctx.existing_public_accounts()[0], + ) + .await?; + + assert_eq!(acc1_ind_state, acc1_seq_state.into()); + + info!("Indexer state is consistent after label-based transfer"); + + Ok(()) +} diff --git a/integration_tests/tests/keys_restoration.rs b/integration_tests/tests/keys_restoration.rs index 4e8d9bf9..7b9c3ab6 100644 --- a/integration_tests/tests/keys_restoration.rs +++ b/integration_tests/tests/keys_restoration.rs @@ -1,3 +1,9 @@ +#![expect( + clippy::shadow_unrelated, + clippy::tests_outside_test_module, + reason = "We don't care about these in tests" +)] + use std::{str::FromStr, time::Duration}; use anyhow::{Context, Result}; @@ -8,6 +14,7 @@ use integration_tests::{ use key_protocol::key_management::key_tree::chain_index::ChainIndex; use log::info; use nssa::{AccountId, program::Program}; +use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::cli::{ Command, SubcommandReturnValue, @@ -313,8 +320,8 @@ async fn restore_keys_from_seed() -> Result<()> { .get_account_balance(to_account_id4) .await?; - assert_eq!(acc3.balance, 91); // 102 - 11 - assert_eq!(acc4.balance, 114); // 103 + 11 + assert_eq!(acc3, 91); // 102 - 11 + assert_eq!(acc4, 114); // 103 + 11 info!("Successfully restored keys and verified transactions"); diff --git a/integration_tests/tests/token.rs b/integration_tests/tests/token.rs index 43b47ee0..0e89259d 100644 --- a/integration_tests/tests/token.rs +++ b/integration_tests/tests/token.rs @@ -1,3 +1,9 @@ +#![expect( + clippy::shadow_unrelated, + clippy::tests_outside_test_module, + reason = "We don't care about these in tests" +)] + use std::time::Duration; use anyhow::{Context as _, Result}; @@ -8,6 +14,7 @@ use integration_tests::{ use key_protocol::key_management::key_tree::chain_index::ChainIndex; use log::info; use nssa::program::Program; +use sequencer_service_rpc::RpcClient as _; use token_core::{TokenDefinition, TokenHolding}; use tokio::test; use wallet::cli::{ @@ -88,8 +95,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await? - .account; + .await?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!(definition_acc.program_owner, Program::token().id()); @@ -106,8 +112,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await? - .account; + .await?; // The account must be owned by the token program assert_eq!(supply_acc.program_owner, Program::token().id()); @@ -141,8 +146,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await? - .account; + .await?; assert_eq!(supply_acc.program_owner, Program::token().id()); let token_holding = TokenHolding::try_from(&supply_acc.data)?; assert_eq!( @@ -157,8 +161,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await? - .account; + .await?; assert_eq!(recipient_acc.program_owner, Program::token().id()); let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -188,8 +191,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await? - .account; + .await?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( @@ -205,8 +207,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await? - .account; + .await?; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -238,8 +239,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await? - .account; + .await?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( @@ -255,8 +255,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await? - .account; + .await?; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -345,8 +344,7 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await? - .account; + .await?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!(definition_acc.program_owner, Program::token().id()); @@ -413,8 +411,7 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await? - .account; + .await?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( @@ -516,8 +513,7 @@ async fn create_token_with_private_definition() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await? - .account; + .await?; assert_eq!(supply_acc.program_owner, Program::token().id()); let token_holding = TokenHolding::try_from(&supply_acc.data)?; @@ -598,8 +594,7 @@ async fn create_token_with_private_definition() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id_public) - .await? - .account; + .await?; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -904,8 +899,7 @@ async fn shielded_token_transfer() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await? - .account; + .await?; let token_holding = TokenHolding::try_from(&supply_acc.data)?; assert_eq!( token_holding, @@ -1052,8 +1046,7 @@ async fn deshielded_token_transfer() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await? - .account; + .await?; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( token_holding, @@ -1192,3 +1185,193 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { Ok(()) } + +#[test] +async fn create_token_using_labels() -> Result<()> { + let mut ctx = TestContext::new().await?; + + // Create definition and supply accounts with labels + let def_label = "token-definition-label".to_owned(); + let supply_label = "token-supply-label".to_owned(); + + let result = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: Some(def_label.clone()), + })), + ) + .await?; + let SubcommandReturnValue::RegisterAccount { + account_id: definition_account_id, + } = result + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + let result = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: Some(supply_label.clone()), + })), + ) + .await?; + let SubcommandReturnValue::RegisterAccount { + account_id: supply_account_id, + } = result + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create token using account labels instead of IDs + let name = "LABELED TOKEN".to_string(); + let total_supply = 100; + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_account_id: None, + definition_account_label: Some(def_label), + supply_account_id: None, + supply_account_label: Some(supply_label), + name: name.clone(), + total_supply, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let definition_acc = ctx + .sequencer_client() + .get_account(definition_account_id) + .await?; + let token_definition = TokenDefinition::try_from(&definition_acc.data)?; + + assert_eq!(definition_acc.program_owner, Program::token().id()); + assert_eq!( + token_definition, + TokenDefinition::Fungible { + name, + total_supply, + metadata_id: None + } + ); + + let supply_acc = ctx + .sequencer_client() + .get_account(supply_account_id) + .await?; + let token_holding = TokenHolding::try_from(&supply_acc.data)?; + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: total_supply + } + ); + + info!("Successfully created token using definition and supply account labels"); + + Ok(()) +} + +#[test] +async fn transfer_token_using_from_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + // Create definition account + let result = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), + ) + .await?; + let SubcommandReturnValue::RegisterAccount { + account_id: definition_account_id, + } = result + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create supply account with a label + let supply_label = "token-supply-sender".to_owned(); + let result = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: Some(supply_label.clone()), + })), + ) + .await?; + let SubcommandReturnValue::RegisterAccount { + account_id: supply_account_id, + } = result + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create recipient account + let result = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), + ) + .await?; + let SubcommandReturnValue::RegisterAccount { + account_id: recipient_account_id, + } = result + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create token + let total_supply = 50; + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_account_id: Some(format_public_account_id(definition_account_id)), + definition_account_label: None, + supply_account_id: Some(format_public_account_id(supply_account_id)), + supply_account_label: None, + name: "LABEL TEST TOKEN".to_string(), + total_supply, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + // Transfer token using from_label instead of from + let transfer_amount = 20; + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: None, + from_label: Some(supply_label), + to: Some(format_public_account_id(recipient_account_id)), + to_label: None, + to_npk: None, + to_vpk: None, + amount: transfer_amount, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let recipient_acc = ctx + .sequencer_client() + .get_account(recipient_account_id) + .await?; + let token_holding = TokenHolding::try_from(&recipient_acc.data)?; + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: transfer_amount + } + ); + + info!("Successfully transferred token using from_label"); + + Ok(()) +}