mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-08-07 05:23:17 +00:00
Merge pull request #671 from logos-blockchain/Pravdyvy/builtin-programs-integration-tests-removal
ci(integration_tests): Tests removal + Simple retry on fixtures
This commit is contained in:
commit
acd269649a
9
.github/workflows/ci.yml
vendored
9
.github/workflows/ci.yml
vendored
@ -214,7 +214,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
image: ${{ needs.ci-image.outputs.image }}
|
image: ${{ needs.ci-image.outputs.image }}
|
||||||
env: RISC0_DEV_MODE=1
|
env: RISC0_DEV_MODE=1
|
||||||
run: cargo nextest archive -p integration_tests --archive-file integration-tests.tar.zst --no-pager
|
run: |
|
||||||
|
for i in 1 2 3; do
|
||||||
|
cargo nextest archive -p integration_tests --archive-file integration-tests.tar.zst --no-pager && break
|
||||||
|
echo "::warning:: Attempt $i failed, cleaning up and retrying..." >&2
|
||||||
|
rm -rf target/debug/deps/*.o target/debug/incremental 2>/dev/null || true
|
||||||
|
cargo clean -p integration_tests 2>/dev/null || true
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
- name: Upload integration test archive
|
- name: Upload integration test archive
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
|
|||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -4372,7 +4372,6 @@ name = "integration_tests"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"associated_token_account_core",
|
|
||||||
"authenticated_transfer_core",
|
"authenticated_transfer_core",
|
||||||
"bridge_core",
|
"bridge_core",
|
||||||
"bridge_lock_core",
|
"bridge_lock_core",
|
||||||
@ -4402,7 +4401,6 @@ dependencies = [
|
|||||||
"test_fixtures",
|
"test_fixtures",
|
||||||
"test_programs",
|
"test_programs",
|
||||||
"testnet_initial_state",
|
"testnet_initial_state",
|
||||||
"token_core",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"vault_core",
|
"vault_core",
|
||||||
"wallet",
|
"wallet",
|
||||||
|
|||||||
@ -17,8 +17,6 @@ wallet.workspace = true
|
|||||||
common.workspace = true
|
common.workspace = true
|
||||||
key_protocol.workspace = true
|
key_protocol.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
token_core.workspace = true
|
|
||||||
associated_token_account_core.workspace = true
|
|
||||||
vault_core.workspace = true
|
vault_core.workspace = true
|
||||||
faucet_core.workspace = true
|
faucet_core.workspace = true
|
||||||
bridge_core.workspace = true
|
bridge_core.workspace = true
|
||||||
|
|||||||
@ -1,386 +0,0 @@
|
|||||||
#![expect(
|
|
||||||
clippy::shadow_unrelated,
|
|
||||||
clippy::tests_outside_test_module,
|
|
||||||
reason = "We don't care about these in tests"
|
|
||||||
)]
|
|
||||||
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use integration_tests::{
|
|
||||||
TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, create_token, get_account, new_account,
|
|
||||||
public_mention, token_send_claiming_new_account,
|
|
||||||
};
|
|
||||||
use log::info;
|
|
||||||
use tokio::test;
|
|
||||||
use wallet::{
|
|
||||||
account::Label,
|
|
||||||
cli::{
|
|
||||||
Command, SubcommandReturnValue,
|
|
||||||
account::{AccountSubcommand, NewSubcommand},
|
|
||||||
programs::amm::AmmProgramAgnosticSubcommand,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn amm_public() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
// Create new account for the token definition
|
|
||||||
let definition_account_id_1 = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create new account for the token supply holder
|
|
||||||
let supply_account_id_1 = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create new account for receiving a token transaction
|
|
||||||
let recipient_account_id_1 = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create new account for the token definition
|
|
||||||
let definition_account_id_2 = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create new account for the token supply holder
|
|
||||||
let supply_account_id_2 = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create new account for receiving a token transaction
|
|
||||||
let recipient_account_id_2 = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create new token
|
|
||||||
create_token(
|
|
||||||
&mut ctx,
|
|
||||||
public_mention(definition_account_id_1),
|
|
||||||
public_mention(supply_account_id_1),
|
|
||||||
"A NAM1".to_owned(),
|
|
||||||
37,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Transfer 7 tokens from `supply_acc` to the account at account_id `recipient_account_id_1`.
|
|
||||||
// `recipient_account_id_1` is still unclaimed, so this bypasses the wallet CLI (which never
|
|
||||||
// signs with the recipient's key) and signs with the recipient's own key directly.
|
|
||||||
token_send_claiming_new_account(&mut ctx, supply_account_id_1, recipient_account_id_1, 7)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Create new token
|
|
||||||
create_token(
|
|
||||||
&mut ctx,
|
|
||||||
public_mention(definition_account_id_2),
|
|
||||||
public_mention(supply_account_id_2),
|
|
||||||
"A NAM2".to_owned(),
|
|
||||||
37,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Transfer 7 tokens from `supply_acc` to the account at account_id `recipient_account_id_2`.
|
|
||||||
// `recipient_account_id_2` is still unclaimed, so this bypasses the wallet CLI the same way.
|
|
||||||
token_send_claiming_new_account(&mut ctx, supply_account_id_2, recipient_account_id_2, 7)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
info!("=================== SETUP FINISHED ===============");
|
|
||||||
|
|
||||||
// Create new AMM
|
|
||||||
|
|
||||||
// Setup accounts
|
|
||||||
// Create new account for the user holding lp
|
|
||||||
let user_holding_lp = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Send creation tx
|
|
||||||
let subcommand = AmmProgramAgnosticSubcommand::New {
|
|
||||||
user_holding_a: public_mention(recipient_account_id_1),
|
|
||||||
user_holding_b: public_mention(recipient_account_id_2),
|
|
||||||
user_holding_lp: public_mention(user_holding_lp),
|
|
||||||
balance_a: 3,
|
|
||||||
balance_b: 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::AMM(subcommand)).await?;
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
let user_holding_a_acc = get_account(&ctx, recipient_account_id_1).await?;
|
|
||||||
|
|
||||||
let user_holding_b_acc = get_account(&ctx, recipient_account_id_2).await?;
|
|
||||||
|
|
||||||
let user_holding_lp_acc = get_account(&ctx, user_holding_lp).await?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
u128::from_le_bytes(user_holding_a_acc.data[33..].try_into().unwrap()),
|
|
||||||
4
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
u128::from_le_bytes(user_holding_b_acc.data[33..].try_into().unwrap()),
|
|
||||||
4
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
u128::from_le_bytes(user_holding_lp_acc.data[33..].try_into().unwrap()),
|
|
||||||
3
|
|
||||||
);
|
|
||||||
|
|
||||||
info!("=================== AMM DEFINITION FINISHED ===============");
|
|
||||||
|
|
||||||
// Make swap
|
|
||||||
|
|
||||||
let subcommand = AmmProgramAgnosticSubcommand::SwapExactInput {
|
|
||||||
user_holding_a: public_mention(recipient_account_id_1),
|
|
||||||
user_holding_b: public_mention(recipient_account_id_2),
|
|
||||||
amount_in: 2,
|
|
||||||
min_amount_out: 1,
|
|
||||||
token_definition: definition_account_id_1,
|
|
||||||
};
|
|
||||||
|
|
||||||
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::AMM(subcommand)).await?;
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
let user_holding_a_acc = get_account(&ctx, recipient_account_id_1).await?;
|
|
||||||
|
|
||||||
let user_holding_b_acc = get_account(&ctx, recipient_account_id_2).await?;
|
|
||||||
|
|
||||||
let user_holding_lp_acc = get_account(&ctx, user_holding_lp).await?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
u128::from_le_bytes(user_holding_a_acc.data[33..].try_into().unwrap()),
|
|
||||||
2
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
u128::from_le_bytes(user_holding_b_acc.data[33..].try_into().unwrap()),
|
|
||||||
5
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
u128::from_le_bytes(user_holding_lp_acc.data[33..].try_into().unwrap()),
|
|
||||||
3
|
|
||||||
);
|
|
||||||
|
|
||||||
info!("=================== FIRST SWAP FINISHED ===============");
|
|
||||||
|
|
||||||
// Make swap
|
|
||||||
|
|
||||||
let subcommand = AmmProgramAgnosticSubcommand::SwapExactInput {
|
|
||||||
user_holding_a: public_mention(recipient_account_id_1),
|
|
||||||
user_holding_b: public_mention(recipient_account_id_2),
|
|
||||||
amount_in: 2,
|
|
||||||
min_amount_out: 1,
|
|
||||||
token_definition: definition_account_id_2,
|
|
||||||
};
|
|
||||||
|
|
||||||
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::AMM(subcommand)).await?;
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
let user_holding_a_acc = get_account(&ctx, recipient_account_id_1).await?;
|
|
||||||
|
|
||||||
let user_holding_b_acc = get_account(&ctx, recipient_account_id_2).await?;
|
|
||||||
|
|
||||||
let user_holding_lp_acc = get_account(&ctx, user_holding_lp).await?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
u128::from_le_bytes(user_holding_a_acc.data[33..].try_into().unwrap()),
|
|
||||||
4
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
u128::from_le_bytes(user_holding_b_acc.data[33..].try_into().unwrap()),
|
|
||||||
3
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
u128::from_le_bytes(user_holding_lp_acc.data[33..].try_into().unwrap()),
|
|
||||||
3
|
|
||||||
);
|
|
||||||
|
|
||||||
info!("=================== SECOND SWAP FINISHED ===============");
|
|
||||||
|
|
||||||
// Add liquidity
|
|
||||||
|
|
||||||
let subcommand = AmmProgramAgnosticSubcommand::AddLiquidity {
|
|
||||||
user_holding_a: public_mention(recipient_account_id_1),
|
|
||||||
user_holding_b: public_mention(recipient_account_id_2),
|
|
||||||
user_holding_lp: public_mention(user_holding_lp),
|
|
||||||
min_amount_lp: 1,
|
|
||||||
max_amount_a: 2,
|
|
||||||
max_amount_b: 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::AMM(subcommand)).await?;
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
let user_holding_a_acc = get_account(&ctx, recipient_account_id_1).await?;
|
|
||||||
|
|
||||||
let user_holding_b_acc = get_account(&ctx, recipient_account_id_2).await?;
|
|
||||||
|
|
||||||
let user_holding_lp_acc = get_account(&ctx, user_holding_lp).await?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
u128::from_le_bytes(user_holding_a_acc.data[33..].try_into().unwrap()),
|
|
||||||
3
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
u128::from_le_bytes(user_holding_b_acc.data[33..].try_into().unwrap()),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
u128::from_le_bytes(user_holding_lp_acc.data[33..].try_into().unwrap()),
|
|
||||||
4
|
|
||||||
);
|
|
||||||
|
|
||||||
info!("=================== ADD LIQ FINISHED ===============");
|
|
||||||
|
|
||||||
// Remove liquidity
|
|
||||||
|
|
||||||
let subcommand = AmmProgramAgnosticSubcommand::RemoveLiquidity {
|
|
||||||
user_holding_a: public_mention(recipient_account_id_1),
|
|
||||||
user_holding_b: public_mention(recipient_account_id_2),
|
|
||||||
user_holding_lp: public_mention(user_holding_lp),
|
|
||||||
balance_lp: 2,
|
|
||||||
min_amount_a: 1,
|
|
||||||
min_amount_b: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::AMM(subcommand)).await?;
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
let user_holding_a_acc = get_account(&ctx, recipient_account_id_1).await?;
|
|
||||||
|
|
||||||
let user_holding_b_acc = get_account(&ctx, recipient_account_id_2).await?;
|
|
||||||
|
|
||||||
let user_holding_lp_acc = get_account(&ctx, user_holding_lp).await?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
u128::from_le_bytes(user_holding_a_acc.data[33..].try_into().unwrap()),
|
|
||||||
5
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
u128::from_le_bytes(user_holding_b_acc.data[33..].try_into().unwrap()),
|
|
||||||
4
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
u128::from_le_bytes(user_holding_lp_acc.data[33..].try_into().unwrap()),
|
|
||||||
2
|
|
||||||
);
|
|
||||||
|
|
||||||
info!("Success!");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn amm_new_pool_using_labels() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
// Create token 1 accounts
|
|
||||||
let definition_account_id_1 = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
let supply_account_id_1 = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create holding_a with a label
|
|
||||||
let holding_a_label = Label::new("amm-holding-a-label");
|
|
||||||
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(Label::new(holding_a_label.clone())),
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
else {
|
|
||||||
anyhow::bail!("Expected RegisterAccount return value");
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create token 2 accounts
|
|
||||||
let definition_account_id_2 = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
let supply_account_id_2 = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create holding_b with a label
|
|
||||||
let holding_b_label = Label::new("amm-holding-b-label");
|
|
||||||
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(Label::new(holding_b_label.clone())),
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
else {
|
|
||||||
anyhow::bail!("Expected RegisterAccount return value");
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create holding_lp with a label
|
|
||||||
let holding_lp_label = Label::new("amm-holding-lp-label");
|
|
||||||
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(Label::new(holding_lp_label.clone())),
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
else {
|
|
||||||
anyhow::bail!("Expected RegisterAccount return value");
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create token 1 and distribute to holding_a
|
|
||||||
create_token(
|
|
||||||
&mut ctx,
|
|
||||||
public_mention(definition_account_id_1),
|
|
||||||
public_mention(supply_account_id_1),
|
|
||||||
"TOKEN1".to_owned(),
|
|
||||||
10,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// `holding_a_id` is still unclaimed, so bypass the wallet CLI (see
|
|
||||||
// `token_send_claiming_new_account`'s docs for why).
|
|
||||||
token_send_claiming_new_account(&mut ctx, supply_account_id_1, holding_a_id, 5).await?;
|
|
||||||
|
|
||||||
// Create token 2 and distribute to holding_b
|
|
||||||
create_token(
|
|
||||||
&mut ctx,
|
|
||||||
public_mention(definition_account_id_2),
|
|
||||||
public_mention(supply_account_id_2),
|
|
||||||
"TOKEN2".to_owned(),
|
|
||||||
10,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// `holding_b_id` is still unclaimed, so bypass the wallet CLI the same way.
|
|
||||||
token_send_claiming_new_account(&mut ctx, supply_account_id_2, holding_b_id, 5).await?;
|
|
||||||
|
|
||||||
// Create AMM pool using account labels instead of IDs
|
|
||||||
let subcommand = AmmProgramAgnosticSubcommand::New {
|
|
||||||
user_holding_a: holding_a_label.into(),
|
|
||||||
user_holding_b: holding_b_label.into(),
|
|
||||||
user_holding_lp: holding_lp_label.into(),
|
|
||||||
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 = get_account(&ctx, 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(())
|
|
||||||
}
|
|
||||||
@ -1,562 +0,0 @@
|
|||||||
#![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};
|
|
||||||
use associated_token_account_core::{compute_ata_seed, get_associated_token_account_id};
|
|
||||||
use integration_tests::{
|
|
||||||
TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, create_token, get_account, new_account,
|
|
||||||
private_mention, public_mention, token_send, verify_commitment_is_in_state,
|
|
||||||
};
|
|
||||||
use log::info;
|
|
||||||
use sequencer_service_rpc::RpcClient as _;
|
|
||||||
use token_core::{TokenDefinition, TokenHolding};
|
|
||||||
use tokio::test;
|
|
||||||
use wallet::cli::{Command, programs::ata::AtaSubcommand};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn create_ata_initializes_holding_account() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
let definition_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
let supply_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
let owner_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create a fungible token
|
|
||||||
let total_supply = 100_u128;
|
|
||||||
create_token(
|
|
||||||
&mut ctx,
|
|
||||||
public_mention(definition_account_id),
|
|
||||||
public_mention(supply_account_id),
|
|
||||||
"TEST".to_owned(),
|
|
||||||
total_supply,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Create the ATA for owner + definition
|
|
||||||
wallet::cli::execute_subcommand(
|
|
||||||
ctx.wallet_mut(),
|
|
||||||
Command::Ata(AtaSubcommand::Create {
|
|
||||||
owner: public_mention(owner_account_id),
|
|
||||||
token_definition: definition_account_id,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
// Derive expected ATA address and check on-chain state
|
|
||||||
let ata_program_id = programs::ata().id();
|
|
||||||
let ata_id = get_associated_token_account_id(
|
|
||||||
&ata_program_id,
|
|
||||||
&compute_ata_seed(owner_account_id, definition_account_id),
|
|
||||||
);
|
|
||||||
|
|
||||||
let ata_acc = ctx
|
|
||||||
.sequencer_client()
|
|
||||||
.get_account(ata_id)
|
|
||||||
.await
|
|
||||||
.context("ATA account not found")?;
|
|
||||||
|
|
||||||
assert_eq!(ata_acc.program_owner, programs::token().id());
|
|
||||||
let holding = TokenHolding::try_from(&ata_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: 0,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn create_ata_is_idempotent() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
let definition_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
let supply_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
let owner_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create a fungible token
|
|
||||||
create_token(
|
|
||||||
&mut ctx,
|
|
||||||
public_mention(definition_account_id),
|
|
||||||
public_mention(supply_account_id),
|
|
||||||
"TEST".to_owned(),
|
|
||||||
100,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Create the ATA once
|
|
||||||
wallet::cli::execute_subcommand(
|
|
||||||
ctx.wallet_mut(),
|
|
||||||
Command::Ata(AtaSubcommand::Create {
|
|
||||||
owner: public_mention(owner_account_id),
|
|
||||||
token_definition: definition_account_id,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
// Create the ATA a second time — must succeed (idempotent)
|
|
||||||
wallet::cli::execute_subcommand(
|
|
||||||
ctx.wallet_mut(),
|
|
||||||
Command::Ata(AtaSubcommand::Create {
|
|
||||||
owner: public_mention(owner_account_id),
|
|
||||||
token_definition: definition_account_id,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
// State must be unchanged
|
|
||||||
let ata_program_id = programs::ata().id();
|
|
||||||
let ata_id = get_associated_token_account_id(
|
|
||||||
&ata_program_id,
|
|
||||||
&compute_ata_seed(owner_account_id, definition_account_id),
|
|
||||||
);
|
|
||||||
|
|
||||||
let ata_acc = ctx
|
|
||||||
.sequencer_client()
|
|
||||||
.get_account(ata_id)
|
|
||||||
.await
|
|
||||||
.context("ATA account not found")?;
|
|
||||||
|
|
||||||
assert_eq!(ata_acc.program_owner, programs::token().id());
|
|
||||||
let holding = TokenHolding::try_from(&ata_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: 0,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn transfer_and_burn_via_ata() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
let definition_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
let supply_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
let sender_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
let recipient_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
let total_supply = 1000_u128;
|
|
||||||
|
|
||||||
// Create a fungible token, supply goes to supply_account_id
|
|
||||||
create_token(
|
|
||||||
&mut ctx,
|
|
||||||
public_mention(definition_account_id),
|
|
||||||
public_mention(supply_account_id),
|
|
||||||
"TEST".to_owned(),
|
|
||||||
total_supply,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Derive ATA addresses
|
|
||||||
let ata_program_id = programs::ata().id();
|
|
||||||
let sender_ata_id = get_associated_token_account_id(
|
|
||||||
&ata_program_id,
|
|
||||||
&compute_ata_seed(sender_account_id, definition_account_id),
|
|
||||||
);
|
|
||||||
let recipient_ata_id = get_associated_token_account_id(
|
|
||||||
&ata_program_id,
|
|
||||||
&compute_ata_seed(recipient_account_id, definition_account_id),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create ATAs for sender and recipient
|
|
||||||
wallet::cli::execute_subcommand(
|
|
||||||
ctx.wallet_mut(),
|
|
||||||
Command::Ata(AtaSubcommand::Create {
|
|
||||||
owner: public_mention(sender_account_id),
|
|
||||||
token_definition: definition_account_id,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
wallet::cli::execute_subcommand(
|
|
||||||
ctx.wallet_mut(),
|
|
||||||
Command::Ata(AtaSubcommand::Create {
|
|
||||||
owner: public_mention(recipient_account_id),
|
|
||||||
token_definition: definition_account_id,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
// Fund sender's ATA from the supply account (direct token transfer)
|
|
||||||
let fund_amount = 200_u128;
|
|
||||||
token_send(
|
|
||||||
&mut ctx,
|
|
||||||
public_mention(supply_account_id),
|
|
||||||
public_mention(sender_ata_id),
|
|
||||||
fund_amount,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Transfer from sender's ATA to recipient's ATA via the ATA program
|
|
||||||
let transfer_amount = 50_u128;
|
|
||||||
wallet::cli::execute_subcommand(
|
|
||||||
ctx.wallet_mut(),
|
|
||||||
Command::Ata(AtaSubcommand::Send {
|
|
||||||
from: public_mention(sender_account_id),
|
|
||||||
token_definition: definition_account_id,
|
|
||||||
to: recipient_ata_id,
|
|
||||||
amount: transfer_amount,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
// Verify sender ATA balance decreased
|
|
||||||
let sender_ata_acc = get_account(&ctx, sender_ata_id).await?;
|
|
||||||
let sender_holding = TokenHolding::try_from(&sender_ata_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
sender_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: fund_amount - transfer_amount,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify recipient ATA balance increased
|
|
||||||
let recipient_ata_acc = get_account(&ctx, recipient_ata_id).await?;
|
|
||||||
let recipient_holding = TokenHolding::try_from(&recipient_ata_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
recipient_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: transfer_amount,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Burn from sender's ATA
|
|
||||||
let burn_amount = 30_u128;
|
|
||||||
wallet::cli::execute_subcommand(
|
|
||||||
ctx.wallet_mut(),
|
|
||||||
Command::Ata(AtaSubcommand::Burn {
|
|
||||||
holder: public_mention(sender_account_id),
|
|
||||||
token_definition: definition_account_id,
|
|
||||||
amount: burn_amount,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
// Verify sender ATA balance after burn
|
|
||||||
let sender_ata_acc = get_account(&ctx, sender_ata_id).await?;
|
|
||||||
let sender_holding = TokenHolding::try_from(&sender_ata_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
sender_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: fund_amount - transfer_amount - burn_amount,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify the token definition total_supply decreased by burn_amount
|
|
||||||
let definition_acc = get_account(&ctx, definition_account_id).await?;
|
|
||||||
let token_definition = TokenDefinition::try_from(&definition_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
token_definition,
|
|
||||||
TokenDefinition::Fungible {
|
|
||||||
name: "TEST".to_owned(),
|
|
||||||
total_supply: total_supply - burn_amount,
|
|
||||||
metadata_id: None,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn create_ata_with_private_owner() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
let definition_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
let supply_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
let owner_account_id = new_account(&mut ctx, true, None).await?;
|
|
||||||
|
|
||||||
// Create a fungible token
|
|
||||||
create_token(
|
|
||||||
&mut ctx,
|
|
||||||
public_mention(definition_account_id),
|
|
||||||
public_mention(supply_account_id),
|
|
||||||
"TEST".to_owned(),
|
|
||||||
100,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Create the ATA for the private owner + definition
|
|
||||||
wallet::cli::execute_subcommand(
|
|
||||||
ctx.wallet_mut(),
|
|
||||||
Command::Ata(AtaSubcommand::Create {
|
|
||||||
owner: private_mention(owner_account_id),
|
|
||||||
token_definition: definition_account_id,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
// Derive expected ATA address and check on-chain state
|
|
||||||
let ata_program_id = programs::ata().id();
|
|
||||||
let ata_id = get_associated_token_account_id(
|
|
||||||
&ata_program_id,
|
|
||||||
&compute_ata_seed(owner_account_id, definition_account_id),
|
|
||||||
);
|
|
||||||
|
|
||||||
let ata_acc = ctx
|
|
||||||
.sequencer_client()
|
|
||||||
.get_account(ata_id)
|
|
||||||
.await
|
|
||||||
.context("ATA account not found")?;
|
|
||||||
|
|
||||||
assert_eq!(ata_acc.program_owner, programs::token().id());
|
|
||||||
let holding = TokenHolding::try_from(&ata_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: 0,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify the private owner's commitment is in state
|
|
||||||
let commitment = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(owner_account_id)
|
|
||||||
.context("Private owner commitment not found")?;
|
|
||||||
assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn transfer_via_ata_private_owner() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
let definition_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
let supply_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
let sender_account_id = new_account(&mut ctx, true, None).await?;
|
|
||||||
let recipient_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
let total_supply = 1000_u128;
|
|
||||||
|
|
||||||
// Create a fungible token
|
|
||||||
create_token(
|
|
||||||
&mut ctx,
|
|
||||||
public_mention(definition_account_id),
|
|
||||||
public_mention(supply_account_id),
|
|
||||||
"TEST".to_owned(),
|
|
||||||
total_supply,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Derive ATA addresses
|
|
||||||
let ata_program_id = programs::ata().id();
|
|
||||||
let sender_ata_id = get_associated_token_account_id(
|
|
||||||
&ata_program_id,
|
|
||||||
&compute_ata_seed(sender_account_id, definition_account_id),
|
|
||||||
);
|
|
||||||
let recipient_ata_id = get_associated_token_account_id(
|
|
||||||
&ata_program_id,
|
|
||||||
&compute_ata_seed(recipient_account_id, definition_account_id),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create ATAs for sender (private owner) and recipient (public owner)
|
|
||||||
wallet::cli::execute_subcommand(
|
|
||||||
ctx.wallet_mut(),
|
|
||||||
Command::Ata(AtaSubcommand::Create {
|
|
||||||
owner: private_mention(sender_account_id),
|
|
||||||
token_definition: definition_account_id,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
wallet::cli::execute_subcommand(
|
|
||||||
ctx.wallet_mut(),
|
|
||||||
Command::Ata(AtaSubcommand::Create {
|
|
||||||
owner: public_mention(recipient_account_id),
|
|
||||||
token_definition: definition_account_id,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
// Fund sender's ATA from the supply account (direct token transfer)
|
|
||||||
let fund_amount = 200_u128;
|
|
||||||
token_send(
|
|
||||||
&mut ctx,
|
|
||||||
public_mention(supply_account_id),
|
|
||||||
public_mention(sender_ata_id),
|
|
||||||
fund_amount,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Transfer from sender's ATA (private owner) to recipient's ATA
|
|
||||||
let transfer_amount = 50_u128;
|
|
||||||
wallet::cli::execute_subcommand(
|
|
||||||
ctx.wallet_mut(),
|
|
||||||
Command::Ata(AtaSubcommand::Send {
|
|
||||||
from: private_mention(sender_account_id),
|
|
||||||
token_definition: definition_account_id,
|
|
||||||
to: recipient_ata_id,
|
|
||||||
amount: transfer_amount,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
// Verify sender ATA balance decreased
|
|
||||||
let sender_ata_acc = get_account(&ctx, sender_ata_id).await?;
|
|
||||||
let sender_holding = TokenHolding::try_from(&sender_ata_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
sender_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: fund_amount - transfer_amount,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify recipient ATA balance increased
|
|
||||||
let recipient_ata_acc = get_account(&ctx, recipient_ata_id).await?;
|
|
||||||
let recipient_holding = TokenHolding::try_from(&recipient_ata_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
recipient_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: transfer_amount,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify the private sender's commitment is in state
|
|
||||||
let commitment = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(sender_account_id)
|
|
||||||
.context("Private sender commitment not found")?;
|
|
||||||
assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn burn_via_ata_private_owner() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
let definition_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
let supply_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
let holder_account_id = new_account(&mut ctx, true, None).await?;
|
|
||||||
|
|
||||||
let total_supply = 500_u128;
|
|
||||||
|
|
||||||
// Create a fungible token
|
|
||||||
create_token(
|
|
||||||
&mut ctx,
|
|
||||||
public_mention(definition_account_id),
|
|
||||||
public_mention(supply_account_id),
|
|
||||||
"TEST".to_owned(),
|
|
||||||
total_supply,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Derive holder's ATA address
|
|
||||||
let ata_program_id = programs::ata().id();
|
|
||||||
let holder_ata_id = get_associated_token_account_id(
|
|
||||||
&ata_program_id,
|
|
||||||
&compute_ata_seed(holder_account_id, definition_account_id),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create ATA for the private holder
|
|
||||||
wallet::cli::execute_subcommand(
|
|
||||||
ctx.wallet_mut(),
|
|
||||||
Command::Ata(AtaSubcommand::Create {
|
|
||||||
owner: private_mention(holder_account_id),
|
|
||||||
token_definition: definition_account_id,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
// Fund holder's ATA from the supply account
|
|
||||||
let fund_amount = 300_u128;
|
|
||||||
token_send(
|
|
||||||
&mut ctx,
|
|
||||||
public_mention(supply_account_id),
|
|
||||||
public_mention(holder_ata_id),
|
|
||||||
fund_amount,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Burn from holder's ATA (private owner)
|
|
||||||
let burn_amount = 100_u128;
|
|
||||||
wallet::cli::execute_subcommand(
|
|
||||||
ctx.wallet_mut(),
|
|
||||||
Command::Ata(AtaSubcommand::Burn {
|
|
||||||
holder: private_mention(holder_account_id),
|
|
||||||
token_definition: definition_account_id,
|
|
||||||
amount: burn_amount,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
// Verify holder ATA balance after burn
|
|
||||||
let holder_ata_acc = get_account(&ctx, holder_ata_id).await?;
|
|
||||||
let holder_holding = TokenHolding::try_from(&holder_ata_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
holder_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: fund_amount - burn_amount,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify the token definition total_supply decreased by burn_amount
|
|
||||||
let definition_acc = get_account(&ctx, definition_account_id).await?;
|
|
||||||
let token_definition = TokenDefinition::try_from(&definition_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
token_definition,
|
|
||||||
TokenDefinition::Fungible {
|
|
||||||
name: "TEST".to_owned(),
|
|
||||||
total_supply: total_supply - burn_amount,
|
|
||||||
metadata_id: None,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify the private holder's commitment is in state
|
|
||||||
let commitment = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(holder_account_id)
|
|
||||||
.context("Private holder commitment not found")?;
|
|
||||||
assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@ -1,239 +0,0 @@
|
|||||||
#![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};
|
|
||||||
use integration_tests::{
|
|
||||||
TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, account_balance, new_account, private_mention,
|
|
||||||
public_mention, sync_private, verify_commitment_is_in_state, wait_for_indexer_to_catch_up,
|
|
||||||
};
|
|
||||||
use log::info;
|
|
||||||
use tokio::test;
|
|
||||||
use wallet::cli::{
|
|
||||||
Command, SubcommandReturnValue,
|
|
||||||
programs::{
|
|
||||||
native_token_transfer::AuthTransferSubcommand, pinata::PinataProgramAgnosticSubcommand,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn claim_pinata_to_uninitialized_public_account_fails_fast() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
let winner_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
let pinata_balance_pre = account_balance(&ctx, system_accounts::pinata_account_id()).await?;
|
|
||||||
|
|
||||||
let claim_result = wallet::cli::execute_subcommand(
|
|
||||||
ctx.wallet_mut(),
|
|
||||||
Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
|
|
||||||
to: public_mention(winner_account_id),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
claim_result.is_err(),
|
|
||||||
"Expected uninitialized account error"
|
|
||||||
);
|
|
||||||
let err = claim_result.unwrap_err().to_string();
|
|
||||||
assert!(
|
|
||||||
err.contains("wallet auth-transfer init --account-id Public/"),
|
|
||||||
"Expected init guidance, got: {err}",
|
|
||||||
);
|
|
||||||
|
|
||||||
let pinata_balance_post = account_balance(&ctx, system_accounts::pinata_account_id()).await?;
|
|
||||||
|
|
||||||
assert_eq!(pinata_balance_post, pinata_balance_pre);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn claim_pinata_to_uninitialized_private_account_fails_fast() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
let winner_account_id = new_account(&mut ctx, true, None).await?;
|
|
||||||
|
|
||||||
let pinata_balance_pre = account_balance(&ctx, system_accounts::pinata_account_id()).await?;
|
|
||||||
|
|
||||||
let claim_result = wallet::cli::execute_subcommand(
|
|
||||||
ctx.wallet_mut(),
|
|
||||||
Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
|
|
||||||
to: private_mention(winner_account_id),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
claim_result.is_err(),
|
|
||||||
"Expected uninitialized account error"
|
|
||||||
);
|
|
||||||
let err = claim_result.unwrap_err().to_string();
|
|
||||||
assert!(
|
|
||||||
err.contains("wallet auth-transfer init --account-id Private/"),
|
|
||||||
"Expected init guidance, got: {err}",
|
|
||||||
);
|
|
||||||
|
|
||||||
let pinata_balance_post = account_balance(&ctx, system_accounts::pinata_account_id()).await?;
|
|
||||||
|
|
||||||
assert_eq!(pinata_balance_post, pinata_balance_pre);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn claim_pinata_to_existing_public_account() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
let pinata_prize = 150;
|
|
||||||
let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
|
|
||||||
to: public_mention(ctx.existing_public_accounts()[0]),
|
|
||||||
});
|
|
||||||
|
|
||||||
let pinata_balance_pre = account_balance(&ctx, system_accounts::pinata_account_id()).await?;
|
|
||||||
|
|
||||||
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 pinata_balance_post = account_balance(&ctx, system_accounts::pinata_account_id()).await?;
|
|
||||||
|
|
||||||
let winner_balance_post = account_balance(&ctx, ctx.existing_public_accounts()[0]).await?;
|
|
||||||
|
|
||||||
assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize);
|
|
||||||
assert_eq!(winner_balance_post, 10000 + pinata_prize);
|
|
||||||
|
|
||||||
info!("Successfully claimed pinata to public account");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn claim_pinata_indexer_keeps_up() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
|
|
||||||
to: public_mention(ctx.existing_public_accounts()[0]),
|
|
||||||
});
|
|
||||||
|
|
||||||
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!("Waiting for indexer to parse blocks");
|
|
||||||
wait_for_indexer_to_catch_up(&ctx).await?;
|
|
||||||
|
|
||||||
let winner_ind_state = indexer_service_rpc::RpcClient::get_account(
|
|
||||||
&**ctx.indexer_client(),
|
|
||||||
ctx.existing_public_accounts()[0].into(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
let winner_seq_state = sequencer_service_rpc::RpcClient::get_account(
|
|
||||||
ctx.sequencer_client(),
|
|
||||||
ctx.existing_public_accounts()[0],
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
assert_eq!(winner_ind_state, winner_seq_state.into());
|
|
||||||
|
|
||||||
info!("Indexer correctly indexed the pinata claim");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn claim_pinata_to_existing_private_account() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
let pinata_prize = 150;
|
|
||||||
let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
|
|
||||||
to: private_mention(ctx.existing_private_accounts()[0]),
|
|
||||||
});
|
|
||||||
|
|
||||||
let pinata_balance_pre = account_balance(&ctx, system_accounts::pinata_account_id()).await?;
|
|
||||||
|
|
||||||
let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
|
||||||
let SubcommandReturnValue::TransactionExecuted { tx_hash: _ } = result else {
|
|
||||||
anyhow::bail!("Expected TransactionExecuted return value");
|
|
||||||
};
|
|
||||||
|
|
||||||
info!("Waiting for next block creation");
|
|
||||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
|
||||||
|
|
||||||
info!("Syncing private accounts");
|
|
||||||
sync_private(&mut ctx).await?;
|
|
||||||
|
|
||||||
let new_commitment = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(ctx.existing_private_accounts()[0])
|
|
||||||
.context("Failed to get private account commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(new_commitment, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
let pinata_balance_post = account_balance(&ctx, system_accounts::pinata_account_id()).await?;
|
|
||||||
|
|
||||||
assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize);
|
|
||||||
|
|
||||||
info!("Successfully claimed pinata to existing private account");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn claim_pinata_to_new_private_account() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
let pinata_prize = 150;
|
|
||||||
|
|
||||||
// Create new private account
|
|
||||||
let winner_account_id = new_account(&mut ctx, true, None).await?;
|
|
||||||
|
|
||||||
// Initialize account under auth transfer program
|
|
||||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Init {
|
|
||||||
account_id: private_mention(winner_account_id),
|
|
||||||
});
|
|
||||||
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_commitment = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(winner_account_id)
|
|
||||||
.context("Failed to get private account commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(new_commitment, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
// Claim pinata to the new private account
|
|
||||||
let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
|
|
||||||
to: private_mention(winner_account_id),
|
|
||||||
});
|
|
||||||
|
|
||||||
let pinata_balance_pre = account_balance(&ctx, system_accounts::pinata_account_id()).await?;
|
|
||||||
|
|
||||||
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_commitment = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(winner_account_id)
|
|
||||||
.context("Failed to get private account commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(new_commitment, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
let pinata_balance_post = account_balance(&ctx, system_accounts::pinata_account_id()).await?;
|
|
||||||
|
|
||||||
assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize);
|
|
||||||
|
|
||||||
info!("Successfully claimed pinata to new private account");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@ -1,996 +0,0 @@
|
|||||||
#![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};
|
|
||||||
use integration_tests::{
|
|
||||||
TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, get_account, new_account, private_mention,
|
|
||||||
public_mention, sync_private, token_send_claiming_new_account, verify_commitment_is_in_state,
|
|
||||||
};
|
|
||||||
use key_protocol::key_management::key_tree::chain_index::ChainIndex;
|
|
||||||
use log::info;
|
|
||||||
use token_core::{TokenDefinition, TokenHolding};
|
|
||||||
use tokio::test;
|
|
||||||
use wallet::{
|
|
||||||
account::Label,
|
|
||||||
cli::{
|
|
||||||
Command, SubcommandReturnValue,
|
|
||||||
account::{AccountSubcommand, NewSubcommand},
|
|
||||||
programs::token::TokenProgramAgnosticSubcommand,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn create_and_transfer_public_token() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
// Create new account for the token definition
|
|
||||||
let definition_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create new account for the token supply holder
|
|
||||||
let supply_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create new account for receiving a token transaction
|
|
||||||
let recipient_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create new token
|
|
||||||
let name = "A NAME".to_owned();
|
|
||||||
let total_supply = 37;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::New {
|
|
||||||
definition_account_id: public_mention(definition_account_id),
|
|
||||||
supply_account_id: public_mention(supply_account_id),
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Check the status of the token definition account
|
|
||||||
let definition_acc = get_account(&ctx, definition_account_id).await?;
|
|
||||||
let token_definition = TokenDefinition::try_from(&definition_acc.data)?;
|
|
||||||
|
|
||||||
assert_eq!(definition_acc.program_owner, programs::token().id());
|
|
||||||
assert_eq!(
|
|
||||||
token_definition,
|
|
||||||
TokenDefinition::Fungible {
|
|
||||||
name: name.clone(),
|
|
||||||
total_supply,
|
|
||||||
metadata_id: None
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check the status of the token holding account with the total supply
|
|
||||||
let supply_acc = get_account(&ctx, supply_account_id).await?;
|
|
||||||
|
|
||||||
// The account must be owned by the token program
|
|
||||||
assert_eq!(supply_acc.program_owner, programs::token().id());
|
|
||||||
let token_holding = TokenHolding::try_from(&supply_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
token_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: total_supply
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Transfer 7 tokens from supply_acc to recipient_account_id. `recipient_account_id` is
|
|
||||||
// still unclaimed, so this bypasses the wallet CLI (which never signs with the recipient's
|
|
||||||
// key) and signs with the recipient's own key directly.
|
|
||||||
let transfer_amount = 7;
|
|
||||||
token_send_claiming_new_account(
|
|
||||||
&mut ctx,
|
|
||||||
supply_account_id,
|
|
||||||
recipient_account_id,
|
|
||||||
transfer_amount,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Check the status of the supply account after transfer
|
|
||||||
let supply_acc = get_account(&ctx, supply_account_id).await?;
|
|
||||||
assert_eq!(supply_acc.program_owner, programs::token().id());
|
|
||||||
let token_holding = TokenHolding::try_from(&supply_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
token_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: total_supply - transfer_amount
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check the status of the recipient account after transfer
|
|
||||||
let recipient_acc = get_account(&ctx, recipient_account_id).await?;
|
|
||||||
assert_eq!(recipient_acc.program_owner, programs::token().id());
|
|
||||||
let token_holding = TokenHolding::try_from(&recipient_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
token_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: transfer_amount
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Burn 3 tokens from recipient_acc
|
|
||||||
let burn_amount = 3;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::Burn {
|
|
||||||
definition: public_mention(definition_account_id),
|
|
||||||
holder: public_mention(recipient_account_id),
|
|
||||||
amount: burn_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;
|
|
||||||
|
|
||||||
// Check the status of the token definition account after burn
|
|
||||||
let definition_acc = get_account(&ctx, definition_account_id).await?;
|
|
||||||
let token_definition = TokenDefinition::try_from(&definition_acc.data)?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
token_definition,
|
|
||||||
TokenDefinition::Fungible {
|
|
||||||
name: name.clone(),
|
|
||||||
total_supply: total_supply - burn_amount,
|
|
||||||
metadata_id: None
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check the status of the recipient account after burn
|
|
||||||
let recipient_acc = get_account(&ctx, 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 - burn_amount
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Mint 10 tokens at recipient_acc
|
|
||||||
let mint_amount = 10;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::Mint {
|
|
||||||
definition: public_mention(definition_account_id),
|
|
||||||
holder: Some(public_mention(recipient_account_id)),
|
|
||||||
holder_npk: None,
|
|
||||||
holder_vpk: None,
|
|
||||||
holder_keys: None,
|
|
||||||
holder_identifier: None,
|
|
||||||
amount: mint_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;
|
|
||||||
|
|
||||||
// Check the status of the token definition account after mint
|
|
||||||
let definition_acc = get_account(&ctx, definition_account_id).await?;
|
|
||||||
let token_definition = TokenDefinition::try_from(&definition_acc.data)?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
token_definition,
|
|
||||||
TokenDefinition::Fungible {
|
|
||||||
name,
|
|
||||||
total_supply: total_supply - burn_amount + mint_amount,
|
|
||||||
metadata_id: None
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check the status of the recipient account after mint
|
|
||||||
let recipient_acc = get_account(&ctx, 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 - burn_amount + mint_amount
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
info!("Successfully created and transferred public token");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn create_and_transfer_token_with_private_supply() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
// Create new account for the token definition (public)
|
|
||||||
let definition_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create new account for the token supply holder (private)
|
|
||||||
let supply_account_id = new_account(&mut ctx, true, None).await?;
|
|
||||||
|
|
||||||
// Create new account for receiving a token transaction (private)
|
|
||||||
let recipient_account_id = new_account(&mut ctx, true, None).await?;
|
|
||||||
|
|
||||||
// Create new token
|
|
||||||
let name = "A NAME".to_owned();
|
|
||||||
let total_supply = 37;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::New {
|
|
||||||
definition_account_id: public_mention(definition_account_id),
|
|
||||||
supply_account_id: private_mention(supply_account_id),
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Check the status of the token definition account
|
|
||||||
let definition_acc = get_account(&ctx, definition_account_id).await?;
|
|
||||||
let token_definition = TokenDefinition::try_from(&definition_acc.data)?;
|
|
||||||
|
|
||||||
assert_eq!(definition_acc.program_owner, programs::token().id());
|
|
||||||
assert_eq!(
|
|
||||||
token_definition,
|
|
||||||
TokenDefinition::Fungible {
|
|
||||||
name: name.clone(),
|
|
||||||
total_supply,
|
|
||||||
metadata_id: None
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let new_commitment1 = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(supply_account_id)
|
|
||||||
.context("Failed to get supply account commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(new_commitment1, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
// Transfer 7 tokens from supply_acc to recipient_account_id
|
|
||||||
let transfer_amount = 7;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::Send {
|
|
||||||
from: private_mention(supply_account_id),
|
|
||||||
to: Some(private_mention(recipient_account_id)),
|
|
||||||
to_npk: None,
|
|
||||||
to_vpk: None,
|
|
||||||
to_keys: None,
|
|
||||||
to_identifier: Some(0),
|
|
||||||
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 new_commitment1 = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(supply_account_id)
|
|
||||||
.context("Failed to get supply account commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(new_commitment1, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
let new_commitment2 = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(recipient_account_id)
|
|
||||||
.context("Failed to get recipient account commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(new_commitment2, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
// Burn 3 tokens from recipient_acc
|
|
||||||
let burn_amount = 3;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::Burn {
|
|
||||||
definition: public_mention(definition_account_id),
|
|
||||||
holder: private_mention(recipient_account_id),
|
|
||||||
amount: burn_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;
|
|
||||||
|
|
||||||
// Check the token definition account after burn
|
|
||||||
let definition_acc = get_account(&ctx, definition_account_id).await?;
|
|
||||||
let token_definition = TokenDefinition::try_from(&definition_acc.data)?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
token_definition,
|
|
||||||
TokenDefinition::Fungible {
|
|
||||||
name,
|
|
||||||
total_supply: total_supply - burn_amount,
|
|
||||||
metadata_id: None
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let new_commitment2 = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(recipient_account_id)
|
|
||||||
.context("Failed to get recipient account commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(new_commitment2, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
// Check the recipient account balance after burn
|
|
||||||
let recipient_acc = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_account_private(recipient_account_id)
|
|
||||||
.context("Failed to get recipient account")?;
|
|
||||||
let token_holding = TokenHolding::try_from(&recipient_acc.data)?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
token_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: transfer_amount - burn_amount
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
info!("Successfully created and transferred token with private supply");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn create_token_with_private_definition() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
// Create token definition account (private)
|
|
||||||
let definition_account_id = new_account(&mut ctx, true, Some(ChainIndex::root())).await?;
|
|
||||||
|
|
||||||
// Create supply account (public)
|
|
||||||
let supply_account_id = new_account(&mut ctx, false, Some(ChainIndex::root())).await?;
|
|
||||||
|
|
||||||
// Create token with private definition
|
|
||||||
let name = "A NAME".to_owned();
|
|
||||||
let total_supply = 37;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::New {
|
|
||||||
definition_account_id: private_mention(definition_account_id),
|
|
||||||
supply_account_id: public_mention(supply_account_id),
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Verify private definition commitment
|
|
||||||
let new_commitment = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(definition_account_id)
|
|
||||||
.context("Failed to get definition commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(new_commitment, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
// Verify supply account
|
|
||||||
let supply_acc = get_account(&ctx, supply_account_id).await?;
|
|
||||||
|
|
||||||
assert_eq!(supply_acc.program_owner, programs::token().id());
|
|
||||||
let token_holding = TokenHolding::try_from(&supply_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
token_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: total_supply
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create private recipient account
|
|
||||||
let recipient_account_id_private = new_account(&mut ctx, true, None).await?;
|
|
||||||
|
|
||||||
// Create public recipient account
|
|
||||||
let recipient_account_id_public = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Mint to public account
|
|
||||||
let mint_amount_public = 10;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::Mint {
|
|
||||||
definition: private_mention(definition_account_id),
|
|
||||||
holder: Some(public_mention(recipient_account_id_public)),
|
|
||||||
holder_npk: None,
|
|
||||||
holder_vpk: None,
|
|
||||||
holder_keys: None,
|
|
||||||
holder_identifier: None,
|
|
||||||
amount: mint_amount_public,
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Verify definition account has updated supply
|
|
||||||
let definition_acc = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_account_private(definition_account_id)
|
|
||||||
.context("Failed to get definition account")?;
|
|
||||||
let token_definition = TokenDefinition::try_from(&definition_acc.data)?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
token_definition,
|
|
||||||
TokenDefinition::Fungible {
|
|
||||||
name: name.clone(),
|
|
||||||
total_supply: total_supply + mint_amount_public,
|
|
||||||
metadata_id: None
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify public recipient received tokens
|
|
||||||
let recipient_acc = get_account(&ctx, recipient_account_id_public).await?;
|
|
||||||
let token_holding = TokenHolding::try_from(&recipient_acc.data)?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
token_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: mint_amount_public
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Mint to private account
|
|
||||||
let mint_amount_private = 5;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::Mint {
|
|
||||||
definition: private_mention(definition_account_id),
|
|
||||||
holder: Some(private_mention(recipient_account_id_private)),
|
|
||||||
holder_npk: None,
|
|
||||||
holder_vpk: None,
|
|
||||||
holder_keys: None,
|
|
||||||
holder_identifier: None,
|
|
||||||
amount: mint_amount_private,
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Verify private recipient commitment
|
|
||||||
let new_commitment = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(recipient_account_id_private)
|
|
||||||
.context("Failed to get recipient commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(new_commitment, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
// Verify private recipient balance
|
|
||||||
let recipient_acc_private = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_account_private(recipient_account_id_private)
|
|
||||||
.context("Failed to get private recipient account")?;
|
|
||||||
let token_holding = TokenHolding::try_from(&recipient_acc_private.data)?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
token_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: mint_amount_private
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
info!("Successfully created token with private definition and minted to both account types");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn create_token_with_private_definition_and_supply() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
// Create token definition account (private)
|
|
||||||
let definition_account_id = new_account(&mut ctx, true, None).await?;
|
|
||||||
|
|
||||||
// Create supply account (private)
|
|
||||||
let supply_account_id = new_account(&mut ctx, true, None).await?;
|
|
||||||
|
|
||||||
// Create token with both private definition and supply
|
|
||||||
let name = "A NAME".to_owned();
|
|
||||||
let total_supply = 37;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::New {
|
|
||||||
definition_account_id: private_mention(definition_account_id),
|
|
||||||
supply_account_id: private_mention(supply_account_id),
|
|
||||||
name,
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Verify definition commitment
|
|
||||||
let definition_commitment = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(definition_account_id)
|
|
||||||
.context("Failed to get definition commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(definition_commitment, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
// Verify supply commitment
|
|
||||||
let supply_commitment = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(supply_account_id)
|
|
||||||
.context("Failed to get supply commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(supply_commitment, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
// Verify supply balance
|
|
||||||
let supply_acc = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_account_private(supply_account_id)
|
|
||||||
.context("Failed to get supply account")?;
|
|
||||||
let token_holding = TokenHolding::try_from(&supply_acc.data)?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
token_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: total_supply
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create recipient account
|
|
||||||
let recipient_account_id = new_account(&mut ctx, true, None).await?;
|
|
||||||
|
|
||||||
// Transfer tokens
|
|
||||||
let transfer_amount = 7;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::Send {
|
|
||||||
from: private_mention(supply_account_id),
|
|
||||||
to: Some(private_mention(recipient_account_id)),
|
|
||||||
to_npk: None,
|
|
||||||
to_vpk: None,
|
|
||||||
to_keys: None,
|
|
||||||
to_identifier: Some(0),
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Verify both commitments updated
|
|
||||||
let supply_commitment = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(supply_account_id)
|
|
||||||
.context("Failed to get supply commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(supply_commitment, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
let recipient_commitment = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(recipient_account_id)
|
|
||||||
.context("Failed to get recipient commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(recipient_commitment, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
// Verify balances
|
|
||||||
let supply_acc = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_account_private(supply_account_id)
|
|
||||||
.context("Failed to get supply account")?;
|
|
||||||
let token_holding = TokenHolding::try_from(&supply_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
token_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: total_supply - transfer_amount
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let recipient_acc = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_account_private(recipient_account_id)
|
|
||||||
.context("Failed to get recipient account")?;
|
|
||||||
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 created and transferred token with both private definition and supply");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn shielded_token_transfer() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
// Create token definition account (public)
|
|
||||||
let definition_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create supply account (public)
|
|
||||||
let supply_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create recipient account (private) for shielded transfer
|
|
||||||
let recipient_account_id = new_account(&mut ctx, true, None).await?;
|
|
||||||
|
|
||||||
// Create token
|
|
||||||
let name = "A NAME".to_owned();
|
|
||||||
let total_supply = 37;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::New {
|
|
||||||
definition_account_id: public_mention(definition_account_id),
|
|
||||||
supply_account_id: public_mention(supply_account_id),
|
|
||||||
name,
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Perform shielded transfer: public supply -> private recipient
|
|
||||||
let transfer_amount = 7;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::Send {
|
|
||||||
from: public_mention(supply_account_id),
|
|
||||||
to: Some(private_mention(recipient_account_id)),
|
|
||||||
to_npk: None,
|
|
||||||
to_vpk: None,
|
|
||||||
to_keys: None,
|
|
||||||
to_identifier: Some(0),
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Verify supply account balance
|
|
||||||
let supply_acc = get_account(&ctx, 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 - transfer_amount
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify recipient commitment exists
|
|
||||||
let new_commitment = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(recipient_account_id)
|
|
||||||
.context("Failed to get recipient commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(new_commitment, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
// Verify recipient balance
|
|
||||||
let recipient_acc = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_account_private(recipient_account_id)
|
|
||||||
.context("Failed to get recipient account")?;
|
|
||||||
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 performed shielded token transfer");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn deshielded_token_transfer() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
// Create token definition account (public)
|
|
||||||
let definition_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create supply account (private)
|
|
||||||
let supply_account_id = new_account(&mut ctx, true, None).await?;
|
|
||||||
|
|
||||||
// Create recipient account (public) for deshielded transfer
|
|
||||||
let recipient_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create token with private supply
|
|
||||||
let name = "A NAME".to_owned();
|
|
||||||
let total_supply = 37;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::New {
|
|
||||||
definition_account_id: public_mention(definition_account_id),
|
|
||||||
supply_account_id: private_mention(supply_account_id),
|
|
||||||
name,
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Perform deshielded transfer: private supply -> public recipient
|
|
||||||
let transfer_amount = 7;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::Send {
|
|
||||||
from: private_mention(supply_account_id),
|
|
||||||
to: Some(public_mention(recipient_account_id)),
|
|
||||||
to_npk: None,
|
|
||||||
to_vpk: None,
|
|
||||||
to_keys: None,
|
|
||||||
to_identifier: Some(0),
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Verify supply account commitment exists
|
|
||||||
let new_commitment = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(supply_account_id)
|
|
||||||
.context("Failed to get supply commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(new_commitment, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
// Verify supply balance
|
|
||||||
let supply_acc = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_account_private(supply_account_id)
|
|
||||||
.context("Failed to get supply account")?;
|
|
||||||
let token_holding = TokenHolding::try_from(&supply_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
token_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: total_supply - transfer_amount
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify recipient balance
|
|
||||||
let recipient_acc = get_account(&ctx, 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 performed deshielded token transfer");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn token_claiming_path_with_private_accounts() -> Result<()> {
|
|
||||||
let mut ctx = TestContext::new().await?;
|
|
||||||
|
|
||||||
// Create token definition account (private)
|
|
||||||
let definition_account_id = new_account(&mut ctx, true, None).await?;
|
|
||||||
|
|
||||||
// Create supply account (private)
|
|
||||||
let supply_account_id = new_account(&mut ctx, true, None).await?;
|
|
||||||
|
|
||||||
// Create token
|
|
||||||
let name = "A NAME".to_owned();
|
|
||||||
let total_supply = 37;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::New {
|
|
||||||
definition_account_id: private_mention(definition_account_id),
|
|
||||||
supply_account_id: private_mention(supply_account_id),
|
|
||||||
name,
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Create new private account for claiming path
|
|
||||||
let recipient_account_id = new_account(&mut ctx, true, None).await?;
|
|
||||||
|
|
||||||
// Get keys for foreign mint (claiming path)
|
|
||||||
let holder = ctx
|
|
||||||
.wallet()
|
|
||||||
.storage()
|
|
||||||
.key_chain()
|
|
||||||
.private_account(recipient_account_id)
|
|
||||||
.context("Failed to get private account keys")?;
|
|
||||||
|
|
||||||
let holder_keys = holder.key_chain;
|
|
||||||
let holder_identifier = holder.kind.identifier();
|
|
||||||
|
|
||||||
// Mint using claiming path (foreign account)
|
|
||||||
let mint_amount = 9;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::Mint {
|
|
||||||
definition: private_mention(definition_account_id),
|
|
||||||
holder: None,
|
|
||||||
holder_npk: Some(hex::encode(holder_keys.nullifier_public_key.0)),
|
|
||||||
holder_vpk: Some(hex::encode(holder_keys.viewing_public_key.to_bytes())),
|
|
||||||
holder_keys: None,
|
|
||||||
holder_identifier: Some(holder_identifier),
|
|
||||||
amount: mint_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;
|
|
||||||
|
|
||||||
// Sync to claim the account
|
|
||||||
sync_private(&mut ctx).await?;
|
|
||||||
|
|
||||||
// Verify commitment exists
|
|
||||||
let recipient_commitment = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_private_account_commitment(recipient_account_id)
|
|
||||||
.context("Failed to get recipient commitment")?;
|
|
||||||
assert!(verify_commitment_is_in_state(recipient_commitment, ctx.sequencer_client()).await);
|
|
||||||
|
|
||||||
// Verify balance
|
|
||||||
let recipient_acc = ctx
|
|
||||||
.wallet()
|
|
||||||
.get_account_private(recipient_account_id)
|
|
||||||
.context("Failed to get recipient account")?;
|
|
||||||
let token_holding = TokenHolding::try_from(&recipient_acc.data)?;
|
|
||||||
assert_eq!(
|
|
||||||
token_holding,
|
|
||||||
TokenHolding::Fungible {
|
|
||||||
definition_id: definition_account_id,
|
|
||||||
balance: mint_amount
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
info!("Successfully minted tokens using claiming path");
|
|
||||||
|
|
||||||
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 = Label::new("token-definition-label");
|
|
||||||
let supply_label = Label::new("token-supply-label");
|
|
||||||
|
|
||||||
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(Label::new(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_owned();
|
|
||||||
let total_supply = 100;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::New {
|
|
||||||
definition_account_id: def_label.into(),
|
|
||||||
supply_account_id: supply_label.into(),
|
|
||||||
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 = get_account(&ctx, definition_account_id).await?;
|
|
||||||
let token_definition = TokenDefinition::try_from(&definition_acc.data)?;
|
|
||||||
|
|
||||||
assert_eq!(definition_acc.program_owner, programs::token().id());
|
|
||||||
assert_eq!(
|
|
||||||
token_definition,
|
|
||||||
TokenDefinition::Fungible {
|
|
||||||
name,
|
|
||||||
total_supply,
|
|
||||||
metadata_id: None
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let supply_acc = get_account(&ctx, 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 definition_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create supply account with a label
|
|
||||||
let supply_label = Label::new("token-supply-sender");
|
|
||||||
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 recipient_account_id = new_account(&mut ctx, false, None).await?;
|
|
||||||
|
|
||||||
// Create token
|
|
||||||
let total_supply = 50;
|
|
||||||
let subcommand = TokenProgramAgnosticSubcommand::New {
|
|
||||||
definition_account_id: public_mention(definition_account_id),
|
|
||||||
supply_account_id: public_mention(supply_account_id),
|
|
||||||
name: "LABEL TEST TOKEN".to_owned(),
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Confirm the label resolves to the account created for it.
|
|
||||||
let resolved_sender = ctx
|
|
||||||
.wallet()
|
|
||||||
.storage()
|
|
||||||
.resolve_label(&supply_label)
|
|
||||||
.context("supply_label should resolve to an account")?;
|
|
||||||
assert_eq!(
|
|
||||||
resolved_sender,
|
|
||||||
wallet::account::AccountIdWithPrivacy::Public(supply_account_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Transfer token from the label-resolved account. `recipient_account_id` is still
|
|
||||||
// unclaimed, so this bypasses the wallet CLI (which never signs with the recipient's key)
|
|
||||||
// and signs with the recipient's own key directly.
|
|
||||||
let transfer_amount = 20;
|
|
||||||
token_send_claiming_new_account(
|
|
||||||
&mut ctx,
|
|
||||||
supply_account_id,
|
|
||||||
recipient_account_id,
|
|
||||||
transfer_amount,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let recipient_acc = get_account(&ctx, 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(())
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user