2025-12-31 04:02:25 +03:00
|
|
|
use std::time::Duration;
|
|
|
|
|
|
|
|
|
|
use anyhow::{Context as _, Result};
|
2026-06-01 17:10:46 -03:00
|
|
|
use common::transaction::LeeTransaction;
|
2025-12-31 04:02:25 +03:00
|
|
|
use integration_tests::{
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, account_balance,
|
|
|
|
|
assert_private_commitment_in_state, fetch_privacy_preserving_tx, get_account, new_account,
|
|
|
|
|
private_mention, public_mention, send, sync_private, verify_commitment_is_in_state,
|
2025-12-31 04:02:25 +03:00
|
|
|
};
|
2026-06-01 17:10:46 -03:00
|
|
|
use lee::{
|
2026-06-19 22:37:36 +04:00
|
|
|
AccountId, execute_and_prove, privacy_preserving_transaction::circuit::ProgramWithDependencies,
|
|
|
|
|
program::Program,
|
2026-05-21 15:52:09 +03:00
|
|
|
};
|
2026-06-01 17:10:46 -03:00
|
|
|
use lee_core::{
|
2026-07-10 11:58:05 +00:00
|
|
|
DUMMY_COMMITMENT_HASH, InputAccountIdentity, Nullifier, NullifierPublicKey,
|
2026-07-01 10:14:32 -04:00
|
|
|
account::{Account, AccountWithMetadata},
|
2026-06-19 22:37:36 +04:00
|
|
|
encryption::ViewingPublicKey,
|
2026-05-21 15:52:09 +03:00
|
|
|
};
|
2026-06-01 17:10:46 -03:00
|
|
|
use log::info;
|
2026-03-24 12:04:13 +11:00
|
|
|
use sequencer_service_rpc::RpcClient as _;
|
2025-12-31 04:02:25 +03:00
|
|
|
use tokio::test;
|
2026-04-10 20:23:25 +03:00
|
|
|
use wallet::{
|
|
|
|
|
account::Label,
|
|
|
|
|
cli::{
|
|
|
|
|
CliAccountMention, Command, SubcommandReturnValue,
|
|
|
|
|
account::{AccountSubcommand, NewSubcommand},
|
|
|
|
|
programs::native_token_transfer::AuthTransferSubcommand,
|
|
|
|
|
},
|
2025-12-31 04:02:25 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
async fn private_transfer_to_owned_account() -> Result<()> {
|
|
|
|
|
let mut ctx = TestContext::new().await?;
|
|
|
|
|
|
2026-01-29 22:20:42 +03:00
|
|
|
let from: AccountId = ctx.existing_private_accounts()[0];
|
|
|
|
|
let to: AccountId = ctx.existing_private_accounts()[1];
|
2025-12-31 04:02:25 +03:00
|
|
|
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
send(&mut ctx, private_mention(from), private_mention(to), 100).await?;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
info!("Waiting for next block creation");
|
|
|
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
|
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
assert_private_commitment_in_state(&ctx, from, "sender").await?;
|
|
|
|
|
assert_private_commitment_in_state(&ctx, to, "receiver").await?;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
info!("Successfully transferred privately to owned account");
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
async fn private_transfer_to_foreign_account() -> Result<()> {
|
|
|
|
|
let mut ctx = TestContext::new().await?;
|
|
|
|
|
|
2026-01-29 22:20:42 +03:00
|
|
|
let from: AccountId = ctx.existing_private_accounts()[0];
|
2025-12-31 04:02:25 +03:00
|
|
|
let to_npk = NullifierPublicKey([42; 32]);
|
|
|
|
|
let to_npk_string = hex::encode(to_npk.0);
|
2026-06-03 14:40:06 -04:00
|
|
|
let to_vpk = ViewingPublicKey::from_seed(&[0_u8; 32], &[1_u8; 32]);
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
2026-04-10 20:23:25 +03:00
|
|
|
from: private_mention(from),
|
2025-12-31 04:02:25 +03:00
|
|
|
to: None,
|
|
|
|
|
to_npk: Some(to_npk_string),
|
2026-06-03 14:40:06 -04:00
|
|
|
to_vpk: Some(hex::encode(to_vpk.to_bytes())),
|
|
|
|
|
to_keys: None,
|
2026-04-23 23:31:21 -03:00
|
|
|
to_identifier: Some(0),
|
2025-12-31 04:02:25 +03:00
|
|
|
amount: 100,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
2026-07-01 19:06:52 +03:00
|
|
|
let SubcommandReturnValue::TransactionExecuted { tx_hash } = result else {
|
|
|
|
|
anyhow::bail!("Expected TransactionExecuted return value");
|
2025-12-31 04:02:25 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
info!("Waiting for next block creation");
|
|
|
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
|
|
|
|
|
|
let new_commitment1 = ctx
|
|
|
|
|
.wallet()
|
2026-01-29 22:20:42 +03:00
|
|
|
.get_private_account_commitment(from)
|
2025-12-31 04:02:25 +03:00
|
|
|
.context("Failed to get private account commitment for sender")?;
|
|
|
|
|
|
2026-01-29 22:20:42 +03:00
|
|
|
let tx = fetch_privacy_preserving_tx(ctx.sequencer_client(), tx_hash).await;
|
2025-12-31 04:02:25 +03:00
|
|
|
assert_eq!(tx.message.new_commitments[0], new_commitment1);
|
|
|
|
|
|
2026-03-24 14:37:29 +11:00
|
|
|
for commitment in tx.message.new_commitments {
|
2025-12-31 04:02:25 +03:00
|
|
|
assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
info!("Successfully transferred privately to foreign account");
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
async fn deshielded_transfer_to_public_account() -> Result<()> {
|
|
|
|
|
let mut ctx = TestContext::new().await?;
|
|
|
|
|
|
2026-01-29 22:20:42 +03:00
|
|
|
let from: AccountId = ctx.existing_private_accounts()[0];
|
|
|
|
|
let to: AccountId = ctx.existing_public_accounts()[1];
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
// Check initial balance of the private sender
|
|
|
|
|
let from_acc = ctx
|
|
|
|
|
.wallet()
|
2026-01-29 22:20:42 +03:00
|
|
|
.get_account_private(from)
|
2025-12-31 04:02:25 +03:00
|
|
|
.context("Failed to get sender's private account")?;
|
|
|
|
|
assert_eq!(from_acc.balance, 10000);
|
|
|
|
|
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
send(&mut ctx, private_mention(from), public_mention(to), 100).await?;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
info!("Waiting for next block creation");
|
|
|
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
|
|
|
|
|
|
let from_acc = ctx
|
|
|
|
|
.wallet()
|
2026-01-29 22:20:42 +03:00
|
|
|
.get_account_private(from)
|
2025-12-31 04:02:25 +03:00
|
|
|
.context("Failed to get sender's private account")?;
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
assert_private_commitment_in_state(&ctx, from, "sender").await?;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
let acc_2_balance = account_balance(&ctx, to).await?;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
assert_eq!(from_acc.balance, 9900);
|
2026-03-24 12:04:13 +11:00
|
|
|
assert_eq!(acc_2_balance, 20100);
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
info!("Successfully deshielded transfer to public account");
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
async fn private_transfer_to_owned_account_using_claiming_path() -> Result<()> {
|
|
|
|
|
let mut ctx = TestContext::new().await?;
|
|
|
|
|
|
2026-01-29 22:20:42 +03:00
|
|
|
let from: AccountId = ctx.existing_private_accounts()[0];
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
// Create a new private account
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
let to_account_id = new_account(&mut ctx, true, None).await?;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
// Get the keys for the newly created account
|
2026-04-10 20:23:25 +03:00
|
|
|
let to = ctx
|
2025-12-31 04:02:25 +03:00
|
|
|
.wallet()
|
|
|
|
|
.storage()
|
2026-04-10 20:23:25 +03:00
|
|
|
.key_chain()
|
|
|
|
|
.private_account(to_account_id)
|
2025-12-31 04:02:25 +03:00
|
|
|
.context("Failed to get private account")?;
|
|
|
|
|
|
2026-01-21 17:27:23 -05:00
|
|
|
// Send to this account using claiming path (using npk and vpk instead of account ID)
|
2025-12-31 04:02:25 +03:00
|
|
|
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
2026-04-10 20:23:25 +03:00
|
|
|
from: private_mention(from),
|
2025-12-31 04:02:25 +03:00
|
|
|
to: None,
|
2026-04-10 20:23:25 +03:00
|
|
|
to_npk: Some(hex::encode(to.key_chain.nullifier_public_key.0)),
|
2026-06-03 14:40:06 -04:00
|
|
|
to_vpk: Some(hex::encode(to.key_chain.viewing_public_key.to_bytes())),
|
|
|
|
|
to_keys: None,
|
2026-04-10 20:23:25 +03:00
|
|
|
to_identifier: Some(to.kind.identifier()),
|
2025-12-31 04:02:25 +03:00
|
|
|
amount: 100,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let sub_ret = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
2026-07-01 19:06:52 +03:00
|
|
|
let SubcommandReturnValue::TransactionExecuted { tx_hash } = sub_ret else {
|
|
|
|
|
anyhow::bail!("Expected TransactionExecuted return value");
|
2025-12-31 04:02:25 +03:00
|
|
|
};
|
|
|
|
|
|
2026-01-29 22:20:42 +03:00
|
|
|
let tx = fetch_privacy_preserving_tx(ctx.sequencer_client(), tx_hash).await;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
// Sync the wallet to claim the new account
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
sync_private(&mut ctx).await?;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
let sender_commitment = ctx
|
2025-12-31 04:02:25 +03:00
|
|
|
.wallet()
|
2026-01-29 22:20:42 +03:00
|
|
|
.get_private_account_commitment(from)
|
2025-12-31 04:02:25 +03:00
|
|
|
.context("Failed to get private account commitment for sender")?;
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
assert_eq!(tx.message.new_commitments[0], sender_commitment);
|
2025-12-31 04:02:25 +03:00
|
|
|
|
2026-03-24 14:37:29 +11:00
|
|
|
for commitment in tx.message.new_commitments {
|
2025-12-31 04:02:25 +03:00
|
|
|
assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let to_res_acc = ctx
|
|
|
|
|
.wallet()
|
2026-01-29 22:20:42 +03:00
|
|
|
.get_account_private(to_account_id)
|
2025-12-31 04:02:25 +03:00
|
|
|
.context("Failed to get recipient's private account")?;
|
|
|
|
|
assert_eq!(to_res_acc.balance, 100);
|
|
|
|
|
|
|
|
|
|
info!("Successfully transferred using claiming path");
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
async fn shielded_transfer_to_owned_private_account() -> Result<()> {
|
|
|
|
|
let mut ctx = TestContext::new().await?;
|
|
|
|
|
|
2026-01-29 22:20:42 +03:00
|
|
|
let from: AccountId = ctx.existing_public_accounts()[0];
|
|
|
|
|
let to: AccountId = ctx.existing_private_accounts()[1];
|
2025-12-31 04:02:25 +03:00
|
|
|
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
send(&mut ctx, public_mention(from), private_mention(to), 100).await?;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
info!("Waiting for next block creation");
|
|
|
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
|
|
|
|
|
|
let acc_to = ctx
|
|
|
|
|
.wallet()
|
2026-01-29 22:20:42 +03:00
|
|
|
.get_account_private(to)
|
2025-12-31 04:02:25 +03:00
|
|
|
.context("Failed to get receiver's private account")?;
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
assert_private_commitment_in_state(&ctx, to, "receiver").await?;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
let acc_from_balance = account_balance(&ctx, from).await?;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
2026-03-24 12:04:13 +11:00
|
|
|
assert_eq!(acc_from_balance, 9900);
|
2025-12-31 04:02:25 +03:00
|
|
|
assert_eq!(acc_to.balance, 20100);
|
|
|
|
|
|
|
|
|
|
info!("Successfully shielded transfer to owned private account");
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
async fn shielded_transfer_to_foreign_account() -> Result<()> {
|
|
|
|
|
let mut ctx = TestContext::new().await?;
|
|
|
|
|
|
|
|
|
|
let to_npk = NullifierPublicKey([42; 32]);
|
|
|
|
|
let to_npk_string = hex::encode(to_npk.0);
|
2026-06-03 14:40:06 -04:00
|
|
|
let to_vpk = ViewingPublicKey::from_seed(&[0_u8; 32], &[1_u8; 32]);
|
2026-01-29 22:20:42 +03:00
|
|
|
let from: AccountId = ctx.existing_public_accounts()[0];
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
2026-04-10 20:23:25 +03:00
|
|
|
from: public_mention(from),
|
2025-12-31 04:02:25 +03:00
|
|
|
to: None,
|
|
|
|
|
to_npk: Some(to_npk_string),
|
2026-06-03 14:40:06 -04:00
|
|
|
to_vpk: Some(hex::encode(to_vpk.to_bytes())),
|
|
|
|
|
to_keys: None,
|
2026-04-23 23:31:21 -03:00
|
|
|
to_identifier: Some(0),
|
2025-12-31 04:02:25 +03:00
|
|
|
amount: 100,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
2026-07-01 19:06:52 +03:00
|
|
|
let SubcommandReturnValue::TransactionExecuted { tx_hash } = result else {
|
|
|
|
|
anyhow::bail!("Expected TransactionExecuted return value");
|
2025-12-31 04:02:25 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
info!("Waiting for next block creation");
|
|
|
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
|
|
|
|
|
|
let tx = fetch_privacy_preserving_tx(ctx.sequencer_client(), tx_hash).await;
|
|
|
|
|
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
let acc_1_balance = account_balance(&ctx, from).await?;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
assert!(
|
2026-07-14 13:10:32 +03:00
|
|
|
verify_commitment_is_in_state(tx.message.new_commitments[0], ctx.sequencer_client()).await
|
2025-12-31 04:02:25 +03:00
|
|
|
);
|
|
|
|
|
|
2026-03-24 12:04:13 +11:00
|
|
|
assert_eq!(acc_1_balance, 9900);
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
info!("Successfully shielded transfer to foreign account");
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[ignore = "Flaky, TODO: #197"]
|
|
|
|
|
async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> {
|
|
|
|
|
let mut ctx = TestContext::new().await?;
|
|
|
|
|
|
|
|
|
|
// NOTE: This test needs refactoring - continuous run mode doesn't work well with TestContext
|
|
|
|
|
// The original implementation spawned wallet::cli::execute_continuous_run() in background
|
|
|
|
|
// but this conflicts with TestContext's wallet management
|
|
|
|
|
|
2026-01-29 22:20:42 +03:00
|
|
|
let from: AccountId = ctx.existing_private_accounts()[0];
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
// Create a new private account
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
let to_account_id = new_account(&mut ctx, true, None).await?;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
// Get the newly created account's keys
|
2026-04-10 20:23:25 +03:00
|
|
|
let to = ctx
|
2025-12-31 04:02:25 +03:00
|
|
|
.wallet()
|
|
|
|
|
.storage()
|
2026-04-10 20:23:25 +03:00
|
|
|
.key_chain()
|
|
|
|
|
.private_account(to_account_id)
|
2025-12-31 04:02:25 +03:00
|
|
|
.context("Failed to get private account")?;
|
|
|
|
|
|
2026-01-21 17:27:23 -05:00
|
|
|
// Send transfer using nullifier and viewing public keys
|
2025-12-31 04:02:25 +03:00
|
|
|
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
2026-04-10 20:23:25 +03:00
|
|
|
from: private_mention(from),
|
2025-12-31 04:02:25 +03:00
|
|
|
to: None,
|
2026-04-10 20:23:25 +03:00
|
|
|
to_npk: Some(hex::encode(to.key_chain.nullifier_public_key.0)),
|
2026-06-03 14:40:06 -04:00
|
|
|
to_vpk: Some(hex::encode(to.key_chain.viewing_public_key.to_bytes())),
|
|
|
|
|
to_keys: None,
|
2026-04-10 20:23:25 +03:00
|
|
|
to_identifier: Some(to.kind.identifier()),
|
2025-12-31 04:02:25 +03:00
|
|
|
amount: 100,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let sub_ret = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
2026-07-01 19:06:52 +03:00
|
|
|
let SubcommandReturnValue::TransactionExecuted { tx_hash } = sub_ret else {
|
2025-12-31 04:02:25 +03:00
|
|
|
anyhow::bail!("Failed to send transaction");
|
|
|
|
|
};
|
|
|
|
|
|
2026-01-29 22:20:42 +03:00
|
|
|
let tx = fetch_privacy_preserving_tx(ctx.sequencer_client(), tx_hash).await;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
info!("Waiting for next blocks to check if continuous run fetches account");
|
|
|
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
|
|
|
|
|
|
// Verify commitments are in state
|
2026-03-24 14:37:29 +11:00
|
|
|
for commitment in tx.message.new_commitments {
|
2025-12-31 04:02:25 +03:00
|
|
|
assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify receiver account balance
|
|
|
|
|
let to_res_acc = ctx
|
|
|
|
|
.wallet()
|
2026-01-29 22:20:42 +03:00
|
|
|
.get_account_private(to_account_id)
|
2025-12-31 04:02:25 +03:00
|
|
|
.context("Failed to get receiver account")?;
|
|
|
|
|
|
|
|
|
|
assert_eq!(to_res_acc.balance, 100);
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
async fn initialize_private_account() -> Result<()> {
|
|
|
|
|
let mut ctx = TestContext::new().await?;
|
|
|
|
|
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
let account_id = new_account(&mut ctx, true, None).await?;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
let command = Command::AuthTransfer(AuthTransferSubcommand::Init {
|
2026-04-10 20:23:25 +03:00
|
|
|
account_id: private_mention(account_id),
|
2025-12-31 04:02:25 +03:00
|
|
|
});
|
|
|
|
|
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
|
|
|
|
|
|
|
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
|
|
|
|
|
|
info!("Syncing private accounts");
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
sync_private(&mut ctx).await?;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
assert_private_commitment_in_state(&ctx, account_id, "account").await?;
|
2025-12-31 04:02:25 +03:00
|
|
|
|
|
|
|
|
let account = ctx
|
|
|
|
|
.wallet()
|
2026-01-29 22:20:42 +03:00
|
|
|
.get_account_private(account_id)
|
2025-12-31 04:02:25 +03:00
|
|
|
.context("Failed to get private account")?;
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
account.program_owner,
|
2026-06-09 16:02:56 +03:00
|
|
|
programs::authenticated_transfer().id()
|
2025-12-31 04:02:25 +03:00
|
|
|
);
|
|
|
|
|
assert_eq!(account.balance, 0);
|
|
|
|
|
assert!(account.data.is_empty());
|
|
|
|
|
|
|
|
|
|
info!("Successfully initialized private account");
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2026-03-24 12:04:13 +11:00
|
|
|
|
|
|
|
|
#[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
|
2026-04-10 20:23:25 +03:00
|
|
|
let label = Label::new("private-sender-label");
|
2026-03-24 12:04:13 +11:00
|
|
|
let command = Command::Account(AccountSubcommand::Label {
|
2026-04-10 20:23:25 +03:00
|
|
|
account_id: private_mention(from),
|
2026-03-24 12:04:13 +11:00
|
|
|
label: label.clone(),
|
|
|
|
|
});
|
|
|
|
|
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
|
|
|
|
|
|
|
|
|
// Send using the label instead of account ID
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
send(
|
|
|
|
|
&mut ctx,
|
|
|
|
|
CliAccountMention::Label(label),
|
|
|
|
|
private_mention(to),
|
|
|
|
|
100,
|
|
|
|
|
)
|
|
|
|
|
.await?;
|
2026-03-24 12:04:13 +11:00
|
|
|
|
|
|
|
|
info!("Waiting for next block creation");
|
|
|
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
|
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
assert_private_commitment_in_state(&ctx, from, "sender").await?;
|
|
|
|
|
assert_private_commitment_in_state(&ctx, to, "receiver").await?;
|
2026-03-24 12:04:13 +11:00
|
|
|
|
|
|
|
|
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
|
2026-04-10 20:23:25 +03:00
|
|
|
let label = Label::new("init-private-label");
|
2026-04-21 02:09:30 -03:00
|
|
|
let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private {
|
2026-03-24 12:04:13 +11:00
|
|
|
cci: None,
|
2026-04-21 02:09:30 -03:00
|
|
|
label: Some(label.clone()),
|
2026-03-24 12:04:13 +11:00
|
|
|
}));
|
|
|
|
|
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 {
|
2026-04-10 20:23:25 +03:00
|
|
|
account_id: label.into(),
|
2026-03-24 12:04:13 +11:00
|
|
|
});
|
|
|
|
|
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
|
|
|
|
|
|
|
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
|
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
sync_private(&mut ctx).await?;
|
2026-03-24 12:04:13 +11:00
|
|
|
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
assert_private_commitment_in_state(&ctx, account_id, "account").await?;
|
2026-03-24 12:04:13 +11:00
|
|
|
|
|
|
|
|
let account = ctx
|
|
|
|
|
.wallet()
|
|
|
|
|
.get_account_private(account_id)
|
|
|
|
|
.context("Failed to get private account")?;
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
account.program_owner,
|
2026-06-09 16:02:56 +03:00
|
|
|
programs::authenticated_transfer().id()
|
2026-03-24 12:04:13 +11:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
info!("Successfully initialized private account using label");
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2026-04-28 00:04:42 -03:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
async fn shielded_transfers_to_two_identifiers_same_npk() -> Result<()> {
|
|
|
|
|
let mut ctx = TestContext::new().await?;
|
|
|
|
|
|
|
|
|
|
// Both transfers below will target this same node with distinct identifiers.
|
|
|
|
|
let chain_index = ctx.wallet_mut().create_private_accounts_key(None);
|
|
|
|
|
let (npk, vpk) = {
|
2026-04-10 20:23:25 +03:00
|
|
|
let key_chain = ctx
|
2026-04-28 00:04:42 -03:00
|
|
|
.wallet()
|
|
|
|
|
.storage()
|
2026-04-10 20:23:25 +03:00
|
|
|
.key_chain()
|
|
|
|
|
.private_account_key_chain_by_index(&chain_index)
|
|
|
|
|
.expect("Failed to get private account key chain for chain index");
|
2026-04-28 00:18:57 -03:00
|
|
|
(
|
|
|
|
|
key_chain.nullifier_public_key,
|
|
|
|
|
key_chain.viewing_public_key.clone(),
|
|
|
|
|
)
|
2026-04-28 00:04:42 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let npk_hex = hex::encode(npk.0);
|
2026-06-03 14:40:06 -04:00
|
|
|
let vpk_hex = hex::encode(vpk.to_bytes());
|
2026-04-28 00:04:42 -03:00
|
|
|
|
|
|
|
|
let identifier_1 = 1_u128;
|
|
|
|
|
let identifier_2 = 2_u128;
|
|
|
|
|
|
|
|
|
|
let sender_0: AccountId = ctx.existing_public_accounts()[0];
|
|
|
|
|
let sender_1: AccountId = ctx.existing_public_accounts()[1];
|
|
|
|
|
|
|
|
|
|
wallet::cli::execute_subcommand(
|
|
|
|
|
ctx.wallet_mut(),
|
|
|
|
|
Command::AuthTransfer(AuthTransferSubcommand::Send {
|
2026-04-10 20:23:25 +03:00
|
|
|
from: public_mention(sender_0),
|
2026-04-28 00:04:42 -03:00
|
|
|
to: None,
|
|
|
|
|
to_npk: Some(npk_hex.clone()),
|
|
|
|
|
to_vpk: Some(vpk_hex.clone()),
|
2026-06-03 14:40:06 -04:00
|
|
|
to_keys: None,
|
2026-04-28 00:04:42 -03:00
|
|
|
to_identifier: Some(identifier_1),
|
|
|
|
|
amount: 100,
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
wallet::cli::execute_subcommand(
|
|
|
|
|
ctx.wallet_mut(),
|
|
|
|
|
Command::AuthTransfer(AuthTransferSubcommand::Send {
|
2026-04-10 20:23:25 +03:00
|
|
|
from: public_mention(sender_1),
|
2026-04-28 00:04:42 -03:00
|
|
|
to: None,
|
|
|
|
|
to_npk: Some(npk_hex),
|
|
|
|
|
to_vpk: Some(vpk_hex),
|
2026-06-03 14:40:06 -04:00
|
|
|
to_keys: None,
|
2026-04-28 00:04:42 -03:00
|
|
|
to_identifier: Some(identifier_2),
|
|
|
|
|
amount: 200,
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
info!("Waiting for next block creation");
|
|
|
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
|
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
sync_private(&mut ctx).await?;
|
2026-04-28 00:04:42 -03:00
|
|
|
|
|
|
|
|
// Both accounts must be discovered with the correct balances.
|
2026-06-19 22:37:36 +04:00
|
|
|
let account_id_1 = AccountId::for_regular_private_account(&npk, &vpk, identifier_1);
|
2026-04-28 00:04:42 -03:00
|
|
|
let acc_1 = ctx
|
|
|
|
|
.wallet()
|
|
|
|
|
.get_account_private(account_id_1)
|
|
|
|
|
.context("account for identifier 1 not found after sync")?;
|
|
|
|
|
assert_eq!(acc_1.balance, 100);
|
|
|
|
|
|
2026-06-19 22:37:36 +04:00
|
|
|
let account_id_2 = AccountId::for_regular_private_account(&npk, &vpk, identifier_2);
|
2026-04-28 00:04:42 -03:00
|
|
|
let acc_2 = ctx
|
|
|
|
|
.wallet()
|
|
|
|
|
.get_account_private(account_id_2)
|
|
|
|
|
.context("account for identifier 2 not found after sync")?;
|
|
|
|
|
assert_eq!(acc_2.balance, 200);
|
|
|
|
|
|
|
|
|
|
// Both account ids must resolve to the same key node.
|
2026-04-10 20:23:25 +03:00
|
|
|
let found_acc1 = ctx
|
|
|
|
|
.wallet()
|
|
|
|
|
.storage()
|
|
|
|
|
.key_chain()
|
|
|
|
|
.private_account(account_id_1)
|
|
|
|
|
.context("account_id_1 not found in key chain")?;
|
|
|
|
|
let found_acc2 = ctx
|
|
|
|
|
.wallet()
|
|
|
|
|
.storage()
|
|
|
|
|
.key_chain()
|
|
|
|
|
.private_account(account_id_2)
|
|
|
|
|
.context("account_id_2 not found in key chain")?;
|
2026-04-28 00:04:42 -03:00
|
|
|
assert_eq!(
|
2026-04-10 20:23:25 +03:00
|
|
|
found_acc1.chain_index, found_acc2.chain_index,
|
2026-04-28 00:04:42 -03:00
|
|
|
"identifiers 1 and 2 under the same NPK must share a single chain_index"
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
2026-04-10 20:23:25 +03:00
|
|
|
found_acc1.chain_index,
|
|
|
|
|
Some(chain_index),
|
2026-04-28 00:04:42 -03:00
|
|
|
"both accounts must resolve to the key node created at the start of the test"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
info!("Successfully transferred to two distinct identifiers under the same NPK");
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2026-05-15 20:56:21 -03:00
|
|
|
|
|
|
|
|
#[test]
|
2026-05-21 15:52:09 +03:00
|
|
|
async fn ppt_cant_chain_call_faucet() -> Result<()> {
|
2026-05-15 20:56:21 -03:00
|
|
|
let ctx = TestContext::new().await?;
|
|
|
|
|
|
2026-06-09 16:02:56 +03:00
|
|
|
let faucet_chain_caller = test_programs::faucet_chain_caller();
|
2026-06-01 17:10:46 -03:00
|
|
|
let deploy_tx = LeeTransaction::ProgramDeployment(lee::ProgramDeploymentTransaction::new(
|
2026-06-09 16:02:56 +03:00
|
|
|
lee::program_deployment_transaction::Message::new(faucet_chain_caller.elf().to_owned()),
|
2026-05-15 20:56:21 -03:00
|
|
|
));
|
|
|
|
|
ctx.sequencer_client().send_transaction(deploy_tx).await?;
|
|
|
|
|
|
|
|
|
|
info!("Waiting for deploy block creation");
|
|
|
|
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
|
|
|
|
2026-06-09 16:02:56 +03:00
|
|
|
let faucet_account_id = system_accounts::faucet_account_id();
|
2026-05-15 20:56:21 -03:00
|
|
|
let attacker_id = ctx.existing_public_accounts()[0];
|
2026-06-09 16:02:56 +03:00
|
|
|
let faucet_program_id = programs::faucet().id();
|
|
|
|
|
let vault_program_id = programs::vault().id();
|
|
|
|
|
let auth_transfer_program_id = programs::authenticated_transfer().id();
|
2026-06-01 17:10:46 -03:00
|
|
|
let nsk: lee_core::NullifierSecretKey = [3; 32];
|
2026-05-15 20:56:21 -03:00
|
|
|
let npk = NullifierPublicKey::from(&nsk);
|
2026-06-10 22:14:09 +04:00
|
|
|
let vpk = ViewingPublicKey::from_bytes(vec![4_u8; 1184]).unwrap();
|
2026-05-15 20:56:21 -03:00
|
|
|
let attacker_vault_id = {
|
|
|
|
|
let seed = vault_core::compute_vault_seed(attacker_id);
|
2026-06-19 22:37:36 +04:00
|
|
|
AccountId::for_private_pda(&vault_program_id, &seed, &npk, &vpk, 1337)
|
2026-05-15 20:56:21 -03:00
|
|
|
};
|
|
|
|
|
let amount: u128 = 1;
|
|
|
|
|
|
|
|
|
|
let faucet_pre = AccountWithMetadata::new(
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
get_account(&ctx, faucet_account_id).await?,
|
2026-05-15 20:56:21 -03:00
|
|
|
false,
|
|
|
|
|
faucet_account_id,
|
|
|
|
|
);
|
|
|
|
|
let vault_pda_pre = AccountWithMetadata::new(
|
refactor(integration_tests): cleaning up long functions (#533)
* refactoring integration_tests::keys
* refactor integration_tests: extract new_account/send/restored_private_account helpers
Move repeated account-creation and transfer boilerplate into four public
helpers in integration_tests/src/lib.rs (new_account, send,
restored_private_account, assert_public_account_restored), then apply them
across keys.rs, ata.rs, auth_transfer/public.rs, auth_transfer/private.rs,
token.rs, and amm.rs. Net result: -816 lines of boilerplate.
* Additional refactors
* refactor(integration_tests): apply shared helpers to remaining test files
Use account_balance, get_account, new_account, send, and sync_private
helpers in public.rs, pinata.rs, private_pda.rs, program_deployment.rs,
and token.rs to reduce boilerplate and improve consistency.
2026-07-01 12:13:51 -04:00
|
|
|
get_account(&ctx, attacker_vault_id).await?,
|
2026-05-15 20:56:21 -03:00
|
|
|
false,
|
|
|
|
|
attacker_vault_id,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let program_with_deps = ProgramWithDependencies::new(
|
|
|
|
|
faucet_chain_caller,
|
|
|
|
|
[
|
2026-06-09 16:02:56 +03:00
|
|
|
(faucet_program_id, programs::faucet()),
|
|
|
|
|
(vault_program_id, programs::vault()),
|
|
|
|
|
(auth_transfer_program_id, programs::authenticated_transfer()),
|
2026-05-15 20:56:21 -03:00
|
|
|
]
|
|
|
|
|
.into(),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let instruction =
|
|
|
|
|
Program::serialize_instruction((faucet_program_id, vault_program_id, attacker_id, amount))?;
|
|
|
|
|
|
2026-05-21 15:52:09 +03:00
|
|
|
let res = execute_and_prove(
|
2026-05-15 20:56:21 -03:00
|
|
|
vec![faucet_pre, vault_pda_pre],
|
|
|
|
|
instruction,
|
|
|
|
|
vec![
|
|
|
|
|
InputAccountIdentity::Public,
|
|
|
|
|
InputAccountIdentity::PrivatePdaInit {
|
2026-06-19 22:37:36 +04:00
|
|
|
vpk,
|
2026-06-26 14:21:40 -04:00
|
|
|
random_seed: [0; 32],
|
2026-05-15 20:56:21 -03:00
|
|
|
npk,
|
|
|
|
|
identifier: 1337,
|
2026-07-01 10:14:32 -04:00
|
|
|
commitment_root: DUMMY_COMMITMENT_HASH,
|
2026-05-21 01:45:10 -03:00
|
|
|
seed: None,
|
2026-05-15 20:56:21 -03:00
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
&program_with_deps,
|
2026-05-21 15:52:09 +03:00
|
|
|
);
|
2026-05-15 20:56:21 -03:00
|
|
|
|
2026-05-21 15:52:09 +03:00
|
|
|
assert!(res.is_err());
|
2026-05-15 20:56:21 -03:00
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2026-07-01 10:14:32 -04:00
|
|
|
|
|
|
|
|
async fn prove_init_with_commitment_root(
|
|
|
|
|
ctx: &TestContext,
|
|
|
|
|
commitment_root: lee_core::CommitmentSetDigest,
|
|
|
|
|
) -> Result<lee_core::PrivacyPreservingCircuitOutput> {
|
|
|
|
|
let program = programs::authenticated_transfer();
|
|
|
|
|
let sender_id = ctx.existing_public_accounts()[0];
|
|
|
|
|
let sender_pre = AccountWithMetadata::new(
|
|
|
|
|
ctx.sequencer_client().get_account(sender_id).await?,
|
|
|
|
|
true,
|
|
|
|
|
sender_id,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let nsk: lee_core::NullifierSecretKey = [7; 32];
|
|
|
|
|
let npk = NullifierPublicKey::from(&nsk);
|
|
|
|
|
let vpk = ViewingPublicKey::from_bytes(vec![4_u8; 1184]).unwrap();
|
2026-07-02 20:04:30 +04:00
|
|
|
let recipient_account_id = AccountId::for_regular_private_account(&npk, &vpk, 0);
|
refactor: `PrivateUnauthorized` authorization changed to true (#621)
* refactor: rename PrivateUnauthorized to PrivateForeignInit
The account_identity's is_authorized flag no longer determines
authorization for this variant, so keep the name tied to what
actually distinguishes it: no nsk, only npk (a foreign account init).
* chore: rebuild guest artifacts and bump spin to clear yanked advisory
Regenerate ELF artifacts after the PrivateForeignInit rename in lee_core
(compiled into every guest program), and update spin 0.9.8 -> 0.9.9 since
0.9.8 was yanked from crates.io, per cargo deny check advisories.
* test: align is_authorized with PrivateForeignInit's flipped semantics
Recipient pre-states built for PrivateForeignInit now need is_authorized:
true to match the assertion in output.rs. Also rewrites the boundary test
that checked the old invalid case to check the new one, and updates
stale "unauthorized" wording left over from the PrivateUnauthorized name.
* chore: rebuild guest artifacts
Reproducible across repeated local builds; likely toolchain drift since
the prior artifact commit rather than a source change, since no
guest-relevant source or Cargo.lock changed in between.
* fix(tests): align integration tests with PrivateForeignInit and regenerate fixture
prove_init_with_commitment_root (private.rs) and build_privacy_transaction
(tps.rs) still built PrivateForeignInit recipients with is_authorized: false,
same stale-semantics bug fixed earlier in the lee crate's own tests.
The prebuilt sequencer DB dump embeds program IDs derived from guest ELF
bytes, which shifted once the PrivateForeignInit rename changed lee_core
(compiled into every guest program). The stale dump caused widespread
"Unknown program" failures across integration test suites that exercise
deployed programs (wallet_ffi, auth_transfer, bridge, amm, token, pinata,
ata, indexer state-consistency checks). Regenerated via
`just regenerate-test-fixture`.
* fix(tests): rename leftover PrivateUnauthorized to PrivateForeignInit and regenerate fixture
* test: align is_authorized with PrivateForeignInit's flipped semantics
* chore: regenerate test fixture after rebase onto dev
* chore: regenerate test fixture after rebase onto dev
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 17:32:01 -04:00
|
|
|
let recipient = AccountWithMetadata::new(Account::default(), true, recipient_account_id);
|
2026-07-01 10:14:32 -04:00
|
|
|
|
|
|
|
|
let (output, _) = execute_and_prove(
|
|
|
|
|
vec![sender_pre, recipient],
|
|
|
|
|
Program::serialize_instruction(authenticated_transfer_core::Instruction::Transfer {
|
|
|
|
|
amount: 1,
|
|
|
|
|
})?,
|
|
|
|
|
vec![
|
|
|
|
|
InputAccountIdentity::Public,
|
refactor: `PrivateUnauthorized` authorization changed to true (#621)
* refactor: rename PrivateUnauthorized to PrivateForeignInit
The account_identity's is_authorized flag no longer determines
authorization for this variant, so keep the name tied to what
actually distinguishes it: no nsk, only npk (a foreign account init).
* chore: rebuild guest artifacts and bump spin to clear yanked advisory
Regenerate ELF artifacts after the PrivateForeignInit rename in lee_core
(compiled into every guest program), and update spin 0.9.8 -> 0.9.9 since
0.9.8 was yanked from crates.io, per cargo deny check advisories.
* test: align is_authorized with PrivateForeignInit's flipped semantics
Recipient pre-states built for PrivateForeignInit now need is_authorized:
true to match the assertion in output.rs. Also rewrites the boundary test
that checked the old invalid case to check the new one, and updates
stale "unauthorized" wording left over from the PrivateUnauthorized name.
* chore: rebuild guest artifacts
Reproducible across repeated local builds; likely toolchain drift since
the prior artifact commit rather than a source change, since no
guest-relevant source or Cargo.lock changed in between.
* fix(tests): align integration tests with PrivateForeignInit and regenerate fixture
prove_init_with_commitment_root (private.rs) and build_privacy_transaction
(tps.rs) still built PrivateForeignInit recipients with is_authorized: false,
same stale-semantics bug fixed earlier in the lee crate's own tests.
The prebuilt sequencer DB dump embeds program IDs derived from guest ELF
bytes, which shifted once the PrivateForeignInit rename changed lee_core
(compiled into every guest program). The stale dump caused widespread
"Unknown program" failures across integration test suites that exercise
deployed programs (wallet_ffi, auth_transfer, bridge, amm, token, pinata,
ata, indexer state-consistency checks). Regenerated via
`just regenerate-test-fixture`.
* fix(tests): rename leftover PrivateUnauthorized to PrivateForeignInit and regenerate fixture
* test: align is_authorized with PrivateForeignInit's flipped semantics
* chore: regenerate test fixture after rebase onto dev
* chore: regenerate test fixture after rebase onto dev
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 17:32:01 -04:00
|
|
|
InputAccountIdentity::PrivateForeignInit {
|
2026-07-02 20:04:30 +04:00
|
|
|
vpk,
|
|
|
|
|
random_seed: [0; 32],
|
2026-07-01 10:14:32 -04:00
|
|
|
npk,
|
|
|
|
|
identifier: 0,
|
|
|
|
|
commitment_root,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
&program.into(),
|
|
|
|
|
)?;
|
|
|
|
|
|
|
|
|
|
Ok(output)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
async fn init_with_dummy_commitment_root_produces_valid_root() -> Result<()> {
|
|
|
|
|
let ctx = TestContext::new().await?;
|
|
|
|
|
|
2026-07-10 11:58:05 +00:00
|
|
|
let (_, expected_digest) = ctx.sequencer_client().get_proofs_and_root(vec![]).await?;
|
2026-07-01 10:14:32 -04:00
|
|
|
|
|
|
|
|
let nsk: lee_core::NullifierSecretKey = [7; 32];
|
|
|
|
|
let npk = NullifierPublicKey::from(&nsk);
|
2026-07-02 20:04:30 +04:00
|
|
|
let vpk = ViewingPublicKey::from_bytes(vec![4_u8; 1184]).unwrap();
|
|
|
|
|
let recipient_account_id = AccountId::for_regular_private_account(&npk, &vpk, 0);
|
2026-07-01 10:14:32 -04:00
|
|
|
|
|
|
|
|
let output = prove_init_with_commitment_root(&ctx, expected_digest).await?;
|
|
|
|
|
|
|
|
|
|
assert_eq!(output.new_nullifiers.len(), 1);
|
|
|
|
|
let (nullifier, digest) = &output.new_nullifiers[0];
|
|
|
|
|
assert_eq!(
|
|
|
|
|
*nullifier,
|
|
|
|
|
Nullifier::for_account_initialization(&recipient_account_id)
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(*digest, expected_digest);
|
|
|
|
|
assert_ne!(*digest, DUMMY_COMMITMENT_HASH);
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
async fn init_nullifier_digest_is_bound_to_commitment_root() -> Result<()> {
|
|
|
|
|
let ctx = TestContext::new().await?;
|
|
|
|
|
|
2026-07-10 11:58:05 +00:00
|
|
|
let (_, expected_digest) = ctx.sequencer_client().get_proofs_and_root(vec![]).await?;
|
2026-07-01 10:14:32 -04:00
|
|
|
|
|
|
|
|
let output_with_root = prove_init_with_commitment_root(&ctx, expected_digest).await?;
|
|
|
|
|
let output_without_root = prove_init_with_commitment_root(&ctx, DUMMY_COMMITMENT_HASH).await?;
|
|
|
|
|
|
|
|
|
|
assert_eq!(output_with_root.new_nullifiers[0].1, expected_digest);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
output_without_root.new_nullifiers[0].1,
|
|
|
|
|
DUMMY_COMMITMENT_HASH
|
|
|
|
|
);
|
|
|
|
|
assert_ne!(
|
|
|
|
|
output_with_root.new_nullifiers[0].1,
|
|
|
|
|
output_without_root.new_nullifiers[0].1,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|