From ef096bede4f0f60e5b04ff53479983a98af0557b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thoralf=20M=C3=BCller?= Date: Mon, 18 Mar 2024 11:23:52 +0100 Subject: [PATCH] Update private tangle tests so they work with 2.0 --- .github/workflows/private-tangle-tests.yml | 5 +- bindings/core/tests/combined.rs | 18 +- sdk/src/types/block/output/basic.rs | 9 +- sdk/tests/client/common/constants.rs | 2 +- sdk/tests/client/node_api/core.rs | 21 +- sdk/tests/client/node_api/mod.rs | 61 ++- .../secret_manager/address_generation.rs | 13 +- sdk/tests/client/secret_manager/mnemonic.rs | 1 - sdk/tests/client/secret_manager/stronghold.rs | 1 - sdk/tests/wallet/balance.rs | 29 +- sdk/tests/wallet/burn_outputs.rs | 35 +- sdk/tests/wallet/claim_outputs.rs | 51 ++- sdk/tests/wallet/common/constants.rs | 2 +- sdk/tests/wallet/common/mod.rs | 89 ++++- sdk/tests/wallet/consolidation.rs | 11 +- sdk/tests/wallet/output_preparation.rs | 368 +++++++++--------- sdk/tests/wallet/transactions.rs | 60 +-- 17 files changed, 449 insertions(+), 327 deletions(-) diff --git a/.github/workflows/private-tangle-tests.yml b/.github/workflows/private-tangle-tests.yml index 92a9b8494e..92e7a00a92 100644 --- a/.github/workflows/private-tangle-tests.yml +++ b/.github/workflows/private-tangle-tests.yml @@ -65,10 +65,7 @@ jobs: uses: "./.github/actions/ledger-nano" - name: Run tests - run: | - cargo nextest run test_get_info --all-features --run-ignored ignored-only --profile ci --cargo-profile ci -p iota-sdk -p iota-sdk-bindings-core --no-capture - # TODO: change in the future to run all tests and not only test_get_info - # cargo ci-tangle-test + run: cargo ci-tangle-test - name: Tear down private tangle if: always() diff --git a/bindings/core/tests/combined.rs b/bindings/core/tests/combined.rs index 06e4822fcd..bd71902e31 100644 --- a/bindings/core/tests/combined.rs +++ b/bindings/core/tests/combined.rs @@ -95,17 +95,13 @@ async fn client_from_wallet() -> Result<(), Error> { .build() .await?; - // TODO reenable - // // Send ClientMethod via the client from the wallet - // let response = wallet - // .client() - // .call_method(ClientMethod::GetHealth) - // .await; - - // match response { - // Response::Bool(_) => {} - // _ => panic!("unexpected response {response:?}"), - // } + // Send ClientMethod via the client from the wallet + let response = wallet.client().call_method(ClientMethod::GetNodeInfo).await; + + match response { + Response::NodeInfo(_) => {} + _ => panic!("unexpected response {response:?}"), + } std::fs::remove_dir_all(storage_path).ok(); Ok(()) diff --git a/sdk/src/types/block/output/basic.rs b/sdk/src/types/block/output/basic.rs index e6761ea619..01e10b7934 100644 --- a/sdk/src/types/block/output/basic.rs +++ b/sdk/src/types/block/output/basic.rs @@ -517,14 +517,9 @@ mod tests { use super::*; use crate::types::block::{ - output::{basic::dto::BasicOutputDto, FoundryId, SimpleTokenScheme, TokenId}, + output::basic::dto::BasicOutputDto, protocol::iota_mainnet_protocol_parameters, - rand::{ - address::rand_account_address, - output::{ - feature::rand_allowed_features, rand_basic_output, unlock_condition::rand_address_unlock_condition, - }, - }, + rand::output::{rand_basic_output, unlock_condition::rand_address_unlock_condition}, }; #[test] diff --git a/sdk/tests/client/common/constants.rs b/sdk/tests/client/common/constants.rs index c06eb0d4e6..9fe5aa7574 100644 --- a/sdk/tests/client/common/constants.rs +++ b/sdk/tests/client/common/constants.rs @@ -3,6 +3,6 @@ pub static NODE_LOCAL: &str = "http://localhost:8050"; -pub static FAUCET_URL: &str = "http://localhost:8091/api/enqueue"; +pub static FAUCET_URL: &str = "http://localhost:8088/api/enqueue"; pub static DEFAULT_MNEMONIC: &str = "inhale gorilla deny three celery song category owner lottery rent author wealth penalty crawl hobby obtain glad warm early rain clutch slab august bleak"; diff --git a/sdk/tests/client/node_api/core.rs b/sdk/tests/client/node_api/core.rs index e276993666..7aade154cb 100644 --- a/sdk/tests/client/node_api/core.rs +++ b/sdk/tests/client/node_api/core.rs @@ -55,8 +55,7 @@ async fn test_get_issuance() { #[ignore] #[tokio::test] async fn test_post_block_with_tagged_data() { - let secret_manager = setup_secret_manager(); - let block_id = setup_tagged_data_block(&secret_manager).await; + let block_id = setup_tagged_data_block().await.unwrap(); println!("{block_id}"); } @@ -72,9 +71,8 @@ async fn test_post_block_with_transaction() { #[tokio::test] async fn test_get_block_data() { let client = setup_client_with_node_health_ignored().await; - let secret_manager = setup_secret_manager(); - let block_id = setup_tagged_data_block(&secret_manager).await; + let block_id = setup_tagged_data_block().await.unwrap(); let r = client.get_block(&block_id).await.unwrap(); println!("{r:#?}"); @@ -83,8 +81,7 @@ async fn test_get_block_data() { #[ignore] #[tokio::test] async fn test_get_block_metadata() { - let secret_manager = setup_secret_manager(); - let block_id = setup_tagged_data_block(&secret_manager).await; + let block_id = setup_tagged_data_block().await.unwrap(); let r = setup_client_with_node_health_ignored() .await @@ -98,8 +95,7 @@ async fn test_get_block_metadata() { #[ignore] #[tokio::test] async fn test_get_block_raw() { - let secret_manager = setup_secret_manager(); - let block_id = setup_tagged_data_block(&secret_manager).await; + let block_id = setup_tagged_data_block().await.unwrap(); let r = setup_client_with_node_health_ignored() .await @@ -201,7 +197,7 @@ async fn test_call_plugin_route() { // we call the "custom" plugin "node info" let plugin_res: NodeInfoResponse = c - .call_plugin_route("api/core/v2/", "GET", "info", vec![], None) + .call_plugin_route("api/core/v3/", "GET", "info", vec![], None) .await .unwrap(); @@ -218,7 +214,7 @@ async fn test_get_routes() { let routes_response = client.get_routes().await.unwrap(); // At at least one route, which is not created by plugin, is available - assert!(routes_response.routes.contains(&"core/v2".to_string())); + assert!(routes_response.routes.contains(&"core/v3".to_string())); println!("{routes_response:#?}"); } @@ -231,7 +227,10 @@ async fn test_get_included_block_metadata() { let metadata_response = client.get_included_block_metadata(&transaction_id).await.unwrap(); assert_eq!(metadata_response.block_id, block_id); - assert_eq!(metadata_response.block_state, BlockState::Finalized); + match metadata_response.block_state { + BlockState::Accepted | BlockState::Confirmed | BlockState::Finalized => {} + _ => panic!("block state is not accepted/confirmed/finalized"), + } println!("{metadata_response:#?}"); } diff --git a/sdk/tests/client/node_api/mod.rs b/sdk/tests/client/node_api/mod.rs index 1d5a9edb0c..70883b2713 100644 --- a/sdk/tests/client/node_api/mod.rs +++ b/sdk/tests/client/node_api/mod.rs @@ -11,12 +11,14 @@ use iota_sdk::{ client::{ api::GetAddressesOptions, constants::IOTA_COIN_TYPE, + generate_mnemonic, node_api::indexer::query_parameters::BasicOutputQueryParameters, request_funds_from_faucet, - secret::{SecretManager, SignBlock}, + secret::{mnemonic::MnemonicSecretManager, SecretManager, SignBlock}, Client, }, types::block::{ + address::{Address, Bech32Address, ImplicitAccountCreationAddress}, output::AccountId, payload::{signed_transaction::TransactionId, tagged_data::TaggedDataPayload, Payload}, BlockId, @@ -28,25 +30,64 @@ use crate::client::common::{setup_client_with_node_health_ignored, FAUCET_URL}; // THIS SEED SERVES FOR TESTING PURPOSES! DON'T USE THIS SEED IN PRODUCTION! const DEFAULT_DEVELOPMENT_SEED: &str = "0x256a818b2aac458941f7274985a410e57fb750f3a3a67969ece5bd9ae7eef5b2"; -// Sends a tagged data block to the node to test against it. -async fn setup_tagged_data_block(secret_manager: &SecretManager) -> BlockId { +// Sends a tagged data block to the node to test against it.* +async fn setup_tagged_data_block() -> Result> { let client = setup_client_with_node_health_ignored().await; - let protocol_params = client.get_protocol_parameters().await.unwrap(); + let secret_manager = SecretManager::Mnemonic(MnemonicSecretManager::try_from_mnemonic(generate_mnemonic()?)?); + + let bech32_hrp = client.get_bech32_hrp().await?; + + let address = secret_manager + .generate_ed25519_address(IOTA_COIN_TYPE, 0, 0, bech32_hrp, None) + .await?; + let address = + Address::ImplicitAccountCreation(ImplicitAccountCreationAddress::new(**address.into_inner().as_ed25519())); + let bech32_address = Bech32Address::new(bech32_hrp, address); + + request_funds_from_faucet(FAUCET_URL, &bech32_address).await?; - client + let mut account_id = AccountId::null(); + // Continue only after funds are received + for i in 0..30 { + let output_ids = client + .basic_output_ids(BasicOutputQueryParameters::only_address_unlock_condition( + bech32_address.clone(), + )) + .await? + .items; + if !output_ids.is_empty() { + account_id = AccountId::from(&output_ids[0]); + break; + } + if i == 29 { + panic!("Faucet no longer wants to hand over coins"); + } + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + } + // Wait until account is read to issue blocks + for _ in 0..60 { + if let Ok(_r) = client.get_account_congestion(&account_id, None).await { + break; + } + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + } + + let block = client .build_basic_block( - AccountId::null(), + account_id, Some(Payload::TaggedData(Box::new( TaggedDataPayload::new(b"Hello".to_vec(), b"Tangle".to_vec()).unwrap(), ))), ) .await .unwrap() - .sign_ed25519(secret_manager, Bip44::new(IOTA_COIN_TYPE)) - .await - .unwrap() - .id(&protocol_params) + .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) + .await?; + client.post_block(&block).await?; + + let protocol_params = client.get_protocol_parameters().await.unwrap(); + Ok(block.id(&protocol_params)) } pub fn setup_secret_manager() -> SecretManager { diff --git a/sdk/tests/client/secret_manager/address_generation.rs b/sdk/tests/client/secret_manager/address_generation.rs index 7ff9584cce..85ef64d7c6 100644 --- a/sdk/tests/client/secret_manager/address_generation.rs +++ b/sdk/tests/client/secret_manager/address_generation.rs @@ -3,26 +3,21 @@ #[cfg(feature = "stronghold")] use crypto::keys::bip39::Mnemonic; -use crypto::keys::bip44::Bip44; +#[cfg(feature = "ledger_nano")] +use iota_sdk::client::secret::ledger_nano::LedgerSecretManager; #[cfg(feature = "stronghold")] use iota_sdk::client::secret::stronghold::StrongholdSecretManager; -#[cfg(feature = "ledger_nano")] -use iota_sdk::client::secret::{ledger_nano::LedgerSecretManager, GenerateAddressOptions}; -#[cfg(feature = "events")] -use iota_sdk::wallet::events::{WalletEvent, WalletEventType}; use iota_sdk::{ client::{ - api::GetAddressesOptions, constants::{IOTA_COIN_TYPE, SHIMMER_COIN_TYPE}, secret::{mnemonic::MnemonicSecretManager, SecretManager}, ClientError, }, - types::block::address::{Hrp, ToBech32Ext}, - wallet::{ClientOptions, Wallet}, + types::block::address::ToBech32Ext, }; use pretty_assertions::assert_eq; -use crate::client::common::{setup, tear_down, DEFAULT_MNEMONIC, NODE_LOCAL}; +use crate::client::common::{setup, tear_down, DEFAULT_MNEMONIC}; #[tokio::test] async fn address_generation_mnemonic() -> Result<(), Box> { diff --git a/sdk/tests/client/secret_manager/mnemonic.rs b/sdk/tests/client/secret_manager/mnemonic.rs index 84cf4e6cbe..aad323aa43 100644 --- a/sdk/tests/client/secret_manager/mnemonic.rs +++ b/sdk/tests/client/secret_manager/mnemonic.rs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 use iota_sdk::client::{ - api::GetAddressesOptions, constants::{SHIMMER_COIN_TYPE, SHIMMER_TESTNET_BECH32_HRP}, secret::SecretManager, ClientError, diff --git a/sdk/tests/client/secret_manager/stronghold.rs b/sdk/tests/client/secret_manager/stronghold.rs index bb087859ee..7f304d4b15 100644 --- a/sdk/tests/client/secret_manager/stronghold.rs +++ b/sdk/tests/client/secret_manager/stronghold.rs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 use iota_sdk::client::{ - api::GetAddressesOptions, constants::{SHIMMER_COIN_TYPE, SHIMMER_TESTNET_BECH32_HRP}, secret::SecretManager, ClientError, diff --git a/sdk/tests/wallet/balance.rs b/sdk/tests/wallet/balance.rs index 0fd52dc90b..fde0e9ffe4 100644 --- a/sdk/tests/wallet/balance.rs +++ b/sdk/tests/wallet/balance.rs @@ -141,7 +141,7 @@ async fn balance_expiration() -> Result<(), Box> { request_funds(&wallet_0).await?; - let slots_until_expired = 20; + let slots_until_expired = 5; let outputs = [BasicOutputBuilder::new_with_amount(1_000_000) // Send to account 1 with expiration to account 2, both have no amount yet .with_unlock_conditions([ @@ -162,7 +162,7 @@ async fn balance_expiration() -> Result<(), Box> { balance_before_tx.base_coin().total(), balance_after_tx.base_coin().total() ); - assert_eq!(balance_after_tx.base_coin().available(), 0); + assert_eq!(balance_after_tx.base_coin().available(), 999968300); wallet_0 .wait_for_transaction_acceptance(&tx.transaction_id, None, None) @@ -203,13 +203,6 @@ async fn balance_expiration() -> Result<(), Box> { assert_eq!(balance.base_coin().total(), 1_000_000); assert_eq!(balance.base_coin().available(), 1_000_000); - // It's possible to send the expired output - let outputs = [BasicOutputBuilder::new_with_amount(1_000_000) - // Send to wallet 1 with expiration to wallet 2, both have no amount yet - .with_unlock_conditions([AddressUnlockCondition::new(wallet_1.address().await)]) - .finish_output()?]; - let _tx = wallet_2.send_outputs(outputs, None).await?; - tear_down(storage_path_0)?; tear_down(storage_path_1)?; tear_down(storage_path_2)?; @@ -218,7 +211,7 @@ async fn balance_expiration() -> Result<(), Box> { #[ignore] #[tokio::test] -async fn balance_transfer() -> Result<(), Box> { +async fn available_balance_transfer() -> Result<(), Box> { let storage_path_0 = "test-storage/addresses_balance_0"; let storage_path_1 = "test-storage/addresses_balance_1"; setup(storage_path_0)?; @@ -229,13 +222,11 @@ async fn balance_transfer() -> Result<(), Box> { request_funds(&wallet_0).await?; - let balance_0 = wallet_0.balance().await?; - let balance_0_sync = wallet_0.sync(None).await?; + let balance_0 = wallet_0.sync(None).await?; let to_send = balance_0.base_coin().available(); // Check if 0 has balance and sync() and address_balance() match assert!(to_send > 0); - assert_eq!(balance_0, balance_0_sync); // Make sure 1 is empty let balance_1 = wallet_1.sync(None).await?; @@ -244,20 +235,22 @@ async fn balance_transfer() -> Result<(), Box> { // Send to 1 let tx = wallet_0.send(to_send, wallet_1.address().await, None).await?; - // Balance should update without sync + // Available balance should update without sync let balance_0 = wallet_0.balance().await?; let balance_0_sync = wallet_0.sync(None).await?; assert_eq!(balance_0.base_coin().available(), 0); - assert_eq!(balance_0, balance_0_sync); + assert_eq!( + balance_0.base_coin().available(), + balance_0_sync.base_coin().available() + ); wallet_0 .wait_for_transaction_acceptance(&tx.transaction_id, None, None) .await?; - // Balance should have transferred entirely - let balance_1_sync = wallet_1.sync(None).await?; + // Available balance should have transferred entirely + let balance_1 = wallet_1.sync(None).await?; assert!(balance_1.base_coin().available() > 0); - assert_eq!(balance_1, balance_1_sync); tear_down(storage_path_0)?; tear_down(storage_path_1)?; diff --git a/sdk/tests/wallet/burn_outputs.rs b/sdk/tests/wallet/burn_outputs.rs index 7d7dd7209b..5514340a75 100644 --- a/sdk/tests/wallet/burn_outputs.rs +++ b/sdk/tests/wallet/burn_outputs.rs @@ -6,7 +6,7 @@ use iota_sdk::{ types::block::output::{ feature::MetadataFeature, unlock_condition::{AddressUnlockCondition, ExpirationUnlockCondition}, - NativeToken, NftId, NftOutputBuilder, OutputId, UnlockCondition, + AccountId, NativeToken, NftId, NftOutputBuilder, OutputId, UnlockCondition, }, wallet::{CreateNativeTokenParams, MintNftParams, Wallet}, U256, @@ -60,12 +60,15 @@ async fn mint_and_burn_nft() -> Result<(), Box> { #[ignore] #[tokio::test] async fn mint_and_burn_expired_nft() -> Result<(), Box> { - let storage_path = "test-storage/mint_and_burn_expired_nft"; - setup(storage_path)?; + let storage_path_0 = "test-storage/mint_and_burn_expired_nft_0"; + let storage_path_1 = "test-storage/mint_and_burn_expired_nft_1"; + setup(storage_path_0)?; + setup(storage_path_1)?; - let wallet_0 = make_wallet(storage_path, None, None).await?; - let wallet_1 = make_wallet(storage_path, None, None).await?; + let wallet_0 = make_wallet(storage_path_0, None, None).await?; + let wallet_1 = make_wallet(storage_path_1, None, None).await?; request_funds(&wallet_0).await?; + request_funds(&wallet_1).await?; let amount = 1_000_000; let outputs = [NftOutputBuilder::new_with_amount(amount, NftId::null()) @@ -90,10 +93,10 @@ async fn mint_and_burn_expired_nft() -> Result<(), Box> { .wait_for_transaction_acceptance(&transaction.transaction_id, None, None) .await?; let balance = wallet_1.sync(None).await?; - // After burning the amount is available on account_1 - assert_eq!(balance.base_coin().available(), amount); + assert_eq!(balance.nfts().len(), 0); - tear_down(storage_path) + tear_down(storage_path_0)?; + tear_down(storage_path_1) } #[ignore] @@ -234,12 +237,6 @@ async fn create_and_burn_native_tokens() -> Result<(), Box Result<(), Box Result<(), Box Result<(), Box> setup(storage_path_1)?; let wallet_0 = make_wallet(storage_path_0, None, None).await?; - let wallet_1 = make_wallet(storage_path_0, None, None).await?; + let wallet_1 = make_wallet(storage_path_1, None, None).await?; request_funds(&wallet_0).await?; request_funds(&wallet_1).await?; @@ -447,9 +450,9 @@ async fn claim_2_nft_outputs() -> Result<(), Box> { #[ignore] #[tokio::test] -async fn claim_2_nft_outputs_no_outputs_in_claim_account() -> Result<(), Box> { - let storage_path_0 = "test-storage/claim_2_nft_outputs_no_outputs_in_claim_wallet_0"; - let storage_path_1 = "test-storage/claim_2_nft_outputs_no_outputs_in_claim_wallet_1"; +async fn claim_2_nft_outputs_no_available_in_claim_account() -> Result<(), Box> { + let storage_path_0 = "test-storage/claim_2_nft_outputs_no_available_in_claim_account_0"; + let storage_path_1 = "test-storage/claim_2_nft_outputs_no_available_in_claim_account_1"; setup(storage_path_0)?; setup(storage_path_1)?; @@ -457,6 +460,22 @@ async fn claim_2_nft_outputs_no_outputs_in_claim_account() -> Result<(), Box Result<(), Box Result<(), Box Result<(), Box> { + request_funds_from_faucet(FAUCET_URL, &wallet.implicit_account_creation_address().await?).await?; request_funds_from_faucet(FAUCET_URL, &wallet.address().await).await?; // Continue only after funds are received - for _ in 0..30 { + for i in 0..30 { + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + wallet + .sync(Some(SyncOptions { + sync_implicit_accounts: true, + ..Default::default() + })) + .await?; + if wallet.ledger().await.implicit_accounts().next().is_some() { + break; + } + if i == 29 { + panic!("Faucet no longer wants to hand over coins"); + } + } + + let wallet_ledger = wallet.ledger().await; + let implicit_account = wallet_ledger + .implicit_accounts() + .next() + .expect("No implicit account found") + .clone(); + drop(wallet_ledger); + + let mut tries = 0; + while let Err(ClientError::Node(iota_sdk::client::node_api::error::Error::NotFound(_))) = wallet + .client() + .get_account_congestion(&AccountId::from(&implicit_account.output_id), None) + .await + { + tries += 1; tokio::time::sleep(std::time::Duration::from_secs(2)).await; - let balance = wallet.sync(None).await?; - if balance.base_coin().available() > 0 { - return Ok(()); + if tries > 100 { + panic!("Can't get_account_congestion for implicit account"); } } - panic!("Faucet no longer wants to hand over coins"); + + let transaction = wallet + .implicit_account_transition( + &implicit_account.output_id, + BlockIssuerKeySource::ImplicitAccountAddress, + ) + .await?; + + wallet + .wait_for_transaction_acceptance(&transaction.transaction_id, None, None) + .await?; + + wallet.sync(None).await?; + + // Is this better than using the congestion endpoint? + // prepare a big tx and wait the time it takes until enough mana is generated + #[allow(unused_variables)] + if let Err(WalletError::Client(ClientError::TransactionBuilder(TransactionBuilderError::InsufficientMana { + found, + required, + slots_remaining, + }))) = wallet + .prepare_send(vec![SendParams::new(1_000_000, wallet.address().await)?; 10], None) + .await + { + tokio::time::sleep(std::time::Duration::from_secs( + slots_remaining as u64 + * wallet + .client() + .get_protocol_parameters() + .await? + .slot_duration_in_seconds() as u64, + )) + .await; + } + + Ok(()) } #[allow(dead_code)] diff --git a/sdk/tests/wallet/consolidation.rs b/sdk/tests/wallet/consolidation.rs index 87cb3d3d67..900894b958 100644 --- a/sdk/tests/wallet/consolidation.rs +++ b/sdk/tests/wallet/consolidation.rs @@ -18,6 +18,7 @@ async fn consolidation() -> Result<(), Box> { let wallet_1 = make_wallet(storage_path_1, None, None).await?; request_funds(&wallet_0).await?; + request_funds(&wallet_1).await?; // Send 10 outputs to wallet_1 let amount = 1_000_000; @@ -30,8 +31,8 @@ async fn consolidation() -> Result<(), Box> { .await?; let balance = wallet_1.sync(None).await.unwrap(); - assert_eq!(balance.base_coin().available(), 10 * amount); - assert_eq!(wallet_1.ledger().await.unspent_outputs().len(), 10); + assert_eq!(balance.base_coin().available(), 2009968300); + assert_eq!(wallet_1.ledger().await.unspent_outputs().len(), 12); let tx = wallet_1 .consolidate_outputs(ConsolidationParams::new().with_force(true)) @@ -42,9 +43,9 @@ async fn consolidation() -> Result<(), Box> { let balance = wallet_1.sync(None).await.unwrap(); // Balance still the same - assert_eq!(balance.base_coin().available(), 10 * amount); - // Only one unspent output - assert_eq!(wallet_1.ledger().await.unspent_outputs().len(), 1); + assert_eq!(balance.base_coin().available(), 2009968300); + // Account and basic unspent output + assert_eq!(wallet_1.ledger().await.unspent_outputs().len(), 2); tear_down(storage_path_0)?; tear_down(storage_path_1)?; diff --git a/sdk/tests/wallet/output_preparation.rs b/sdk/tests/wallet/output_preparation.rs index 9d4cfc4829..22f322fd6b 100644 --- a/sdk/tests/wallet/output_preparation.rs +++ b/sdk/tests/wallet/output_preparation.rs @@ -43,11 +43,11 @@ async fn output_preparation() -> Result<(), Box> { None, ) .await?; - assert_eq!(output.amount(), 46800); + assert_eq!(output.amount(), 18300); // address and sdr unlock condition assert_eq!(output.unlock_conditions().unwrap().len(), 2); let sdr = output.unlock_conditions().unwrap().storage_deposit_return().unwrap(); - assert_eq!(sdr.amount(), 46300); + assert_eq!(sdr.amount(), 17800); let output = wallet .prepare_output( @@ -139,13 +139,13 @@ async fn output_preparation() -> Result<(), Box> { None, ) .await?; - assert_eq!(output.amount(), 49000); + let min_amount_with_metadata_and_tag = 21100; + assert_eq!(output.amount(), min_amount_with_metadata_and_tag); let unlock_conditions = output.unlock_conditions().unwrap(); // address + sdr assert_eq!(unlock_conditions.len(), 2); let storage_deposit_return = unlock_conditions.storage_deposit_return().unwrap(); - // output amount -1 - assert_eq!(storage_deposit_return.amount(), 48999); + assert_eq!(storage_deposit_return.amount(), min_amount_with_metadata_and_tag - 1); // metadata and tag features assert_eq!(output.features().unwrap().len(), 2); @@ -168,7 +168,7 @@ async fn output_preparation() -> Result<(), Box> { None, ) .await?; - assert_eq!(output.amount(), 54600); + assert_eq!(output.amount(), 26100); // address and storage deposit unlock condition, because of the metadata feature block, 12000 is not enough for the // required storage deposit assert_eq!(output.unlock_conditions().unwrap().len(), 2); @@ -194,9 +194,9 @@ async fn output_preparation() -> Result<(), Box> { None, ) .await?; - assert_eq!(output.amount(), 49000); + assert_eq!(output.amount(), min_amount_with_metadata_and_tag); let sdr = output.unlock_conditions().unwrap().storage_deposit_return().unwrap(); - assert_eq!(sdr.amount(), 48999); + assert_eq!(sdr.amount(), min_amount_with_metadata_and_tag - 1); // address and storage deposit unlock condition, because of the metadata feature block, 213000 is not enough for the // required storage deposit @@ -279,11 +279,11 @@ async fn output_preparation() -> Result<(), Box> { ) .await?; - assert_eq!(output.kind(), iota_sdk::types::block::output::BasicOutput::KIND); + assert_eq!(output.kind(), BasicOutput::KIND); assert_eq!(output.amount(), 500000); assert_eq!(output.unlock_conditions().unwrap().len(), 1); let features = output.features().unwrap(); - assert_eq!(features.len(), 1); + assert_eq!(features.len(), 2); assert_eq!(features.sender().unwrap().address(), expected_address); // error when adding issuer when building basic output @@ -356,7 +356,7 @@ async fn output_preparation() -> Result<(), Box> { assert!(conditions.is_timelocked(0, 0)); assert_eq!( conditions.is_expired(2, CommittableAgeRange { min: 0, max: 0 }), - Some(false) + Some(true) ); // nft with expiration @@ -387,7 +387,7 @@ async fn output_preparation() -> Result<(), Box> { ) .await?; assert_eq!(output.kind(), iota_sdk::types::block::output::NftOutput::KIND); - assert_eq!(output.amount(), 53900); + assert_eq!(output.amount(), 25400); // address, sdr, expiration assert_eq!(output.unlock_conditions().unwrap().len(), 3); @@ -418,9 +418,9 @@ async fn output_preparation() -> Result<(), Box> { let storage_score_params = wallet.client().get_storage_score_parameters().await?; let minimum_amount = output.minimum_amount(storage_score_params); assert_eq!(output.amount(), minimum_amount); - assert_eq!(output.amount(), 187900); + assert_eq!(output.amount(), 160000); let sdr = output.unlock_conditions().unwrap().storage_deposit_return().unwrap(); - assert_eq!(sdr.amount(), 145300); + assert_eq!(sdr.amount(), 117400); // address and storage deposit unlock condition, because of the metadata feature block, 42600 is not enough for the // required storage deposit assert_eq!(output.unlock_conditions().unwrap().len(), 2); @@ -450,7 +450,7 @@ async fn output_preparation_sdr() -> Result<(), Box> { .prepare_output( OutputParams { recipient_address: recipient_address.clone(), - amount: 8001, + amount: 4001, assets: None, features: None, unlocks: None, @@ -461,17 +461,19 @@ async fn output_preparation_sdr() -> Result<(), Box> { .await?; // Check if the output has enough amount to cover the storage deposit output.verify_storage_deposit(storage_score_params)?; - assert_eq!(output.amount(), 50601); + assert_eq!(output.amount(), 18300); // address and sdr unlock condition assert_eq!(output.unlock_conditions().unwrap().len(), 2); let sdr = output.unlock_conditions().unwrap().storage_deposit_return().unwrap(); - assert_eq!(sdr.amount(), 42600); + assert_eq!(sdr.amount(), 14299); + + let min_amount = 14100; let output = wallet .prepare_output( OutputParams { recipient_address: recipient_address.clone(), - amount: 42599, + amount: min_amount - 1, assets: None, features: None, unlocks: None, @@ -482,18 +484,18 @@ async fn output_preparation_sdr() -> Result<(), Box> { .await?; // Check if the output has enough amount to cover the storage deposit output.verify_storage_deposit(storage_score_params)?; - assert_eq!(output.amount(), 85199); + assert_eq!(output.amount(), (min_amount * 2) - 1); // address and sdr unlock condition assert_eq!(output.unlock_conditions().unwrap().len(), 2); let sdr = output.unlock_conditions().unwrap().storage_deposit_return().unwrap(); - assert_eq!(sdr.amount(), 42600); + assert_eq!(sdr.amount(), min_amount); // ReturnStrategy::Return provided let output = wallet .prepare_output( OutputParams { recipient_address: recipient_address.clone(), - amount: 42599, + amount: min_amount - 1, assets: None, features: None, unlocks: None, @@ -507,18 +509,18 @@ async fn output_preparation_sdr() -> Result<(), Box> { .await?; // Check if the output has enough amount to cover the storage deposit output.verify_storage_deposit(storage_score_params)?; - assert_eq!(output.amount(), 85199); + assert_eq!(output.amount(), (min_amount * 2) - 1); // address and sdr unlock condition assert_eq!(output.unlock_conditions().unwrap().len(), 2); let sdr = output.unlock_conditions().unwrap().storage_deposit_return().unwrap(); - assert_eq!(sdr.amount(), 42600); + assert_eq!(sdr.amount(), min_amount); // ReturnStrategy::Gift provided let output = wallet .prepare_output( OutputParams { recipient_address: recipient_address.clone(), - amount: 42599, + amount: min_amount - 1, assets: None, features: None, unlocks: None, @@ -533,7 +535,7 @@ async fn output_preparation_sdr() -> Result<(), Box> { // Check if the output has enough amount to cover the storage deposit output.verify_storage_deposit(storage_score_params)?; // The additional 1 amount will be added, because the storage deposit should be gifted and not returned - assert_eq!(output.amount(), 42600); + assert_eq!(output.amount(), min_amount); // storage deposit gifted, only address unlock condition assert_eq!(output.unlock_conditions().unwrap().len(), 1); @@ -553,12 +555,22 @@ async fn prepare_nft_output_features_update() -> Result<(), Box Result<(), Box Result<(), Box Result<(), Box> { - let storage_path_0 = "test-storage/prepare_output_remainder_dust_0"; - let storage_path_1 = "test-storage/prepare_output_remainder_dust_1"; - setup(storage_path_0)?; - setup(storage_path_1)?; - - let wallet_0 = make_wallet(storage_path_0, None, None).await?; - let wallet_1 = make_wallet(storage_path_1, None, None).await?; - request_funds(&wallet_0).await?; - request_funds(&wallet_1).await?; - - let storage_score_params = wallet_0.client().get_storage_score_parameters().await?; - - let balance = wallet_0.sync(None).await?; - let minimum_amount = BasicOutput::minimum_amount(&*wallet_1.address().await, storage_score_params); - - // Send away most balance so we can test with leaving dust - let output = wallet_0 - .prepare_output( - OutputParams { - recipient_address: wallet_1.address().await, - amount: balance.base_coin().available() - 63900, - assets: None, - features: None, - unlocks: None, - storage_deposit: None, - }, - None, - ) - .await?; - let transaction = wallet_0.send_outputs(vec![output], None).await?; - wallet_0 - .wait_for_transaction_acceptance(&transaction.transaction_id, None, None) - .await?; - let balance = wallet_0.sync(None).await?; - - // 63900 left - let output = wallet_0 - .prepare_output( - OutputParams { - recipient_address: wallet_1.address().await, - amount: minimum_amount - 1, // Leave less than min. deposit - assets: None, - features: None, - unlocks: None, - storage_deposit: Some(StorageDeposit { - return_strategy: Some(ReturnStrategy::Gift), - use_excess_if_low: Some(true), - }), - }, - None, - ) - .await?; - - // Check if the output has enough amount to cover the storage deposit - output.verify_storage_deposit(storage_score_params)?; - // The left over 21299 is too small to keep, so we donate it - assert_eq!(output.amount(), balance.base_coin().available()); - // storage deposit gifted, only address unlock condition - assert_eq!(output.unlock_conditions().unwrap().len(), 1); - - let result = wallet_0 - .prepare_output( - OutputParams { - recipient_address: wallet_1.address().await, - amount: minimum_amount - 1, // Leave less than min. deposit - assets: None, - features: None, - unlocks: None, - storage_deposit: Some(StorageDeposit { - return_strategy: Some(ReturnStrategy::Return), - use_excess_if_low: Some(true), - }), - }, - None, - ) - .await; - assert!( - matches!(result, Err(iota_sdk::wallet::WalletError::InsufficientFunds{available, required}) if available == balance.base_coin().available() && required == 85199) - ); - - let output = wallet_0 - .prepare_output( - OutputParams { - recipient_address: wallet_1.address().await, - amount: 100, // leave more behind than min. deposit - assets: None, - features: None, - unlocks: None, - storage_deposit: Some(StorageDeposit { - return_strategy: Some(ReturnStrategy::Gift), - use_excess_if_low: Some(true), - }), - }, - None, - ) - .await?; - - // Check if the output has enough amount to cover the storage deposit - output.verify_storage_deposit(storage_score_params)?; - // We use excess if leftover is too small, so amount == all available balance - assert_eq!(output.amount(), 63900); - // storage deposit gifted, only address unlock condition - assert_eq!(output.unlock_conditions().unwrap().len(), 1); - - let output = wallet_0 - .prepare_output( - OutputParams { - recipient_address: wallet_1.address().await, - amount: 100, // leave more behind than min. deposit - assets: None, - features: None, - unlocks: None, - storage_deposit: Some(StorageDeposit { - return_strategy: Some(ReturnStrategy::Return), - use_excess_if_low: Some(true), - }), - }, - None, - ) - .await?; - - // Check if the output has enough amount to cover the storage deposit - output.verify_storage_deposit(storage_score_params)?; - // We use excess if leftover is too small, so amount == all available balance - assert_eq!(output.amount(), 63900); - // storage deposit returned, address and SDR unlock condition - assert_eq!(output.unlock_conditions().unwrap().len(), 2); - // We have ReturnStrategy::Return, so leftover amount gets returned - let sdr = output.unlock_conditions().unwrap().storage_deposit_return().unwrap(); - assert_eq!(sdr.amount(), 63900 - 100); - - tear_down(storage_path_0)?; - tear_down(storage_path_1)?; - - Ok(()) -} +// TODO: adjust amounts +// #[ignore] +// #[tokio::test] +// async fn prepare_output_remainder_dust() -> Result<(), Box> { +// let storage_path_0 = "test-storage/prepare_output_remainder_dust_0"; +// let storage_path_1 = "test-storage/prepare_output_remainder_dust_1"; +// setup(storage_path_0)?; +// setup(storage_path_1)?; + +// let wallet_0 = make_wallet(storage_path_0, None, None).await?; +// let wallet_1 = make_wallet(storage_path_1, None, None).await?; +// request_funds(&wallet_0).await?; +// request_funds(&wallet_1).await?; + +// let storage_score_params = wallet_0.client().get_storage_score_parameters().await?; + +// let balance = wallet_0.sync(None).await?; +// let minimum_amount = BasicOutput::minimum_amount(&*wallet_1.address().await, storage_score_params); + +// // Send away most balance so we can test with leaving dust +// let output = wallet_0 +// .prepare_output( +// OutputParams { +// recipient_address: wallet_1.address().await, +// amount: balance.base_coin().available() - 63900, +// assets: None, +// features: None, +// unlocks: None, +// storage_deposit: None, +// }, +// None, +// ) +// .await?; +// let transaction = wallet_0.send_outputs(vec![output], None).await?; +// wallet_0 +// .wait_for_transaction_acceptance(&transaction.transaction_id, None, None) +// .await?; +// let balance = wallet_0.sync(None).await?; + +// // 63900 left +// let output = wallet_0 +// .prepare_output( +// OutputParams { +// recipient_address: wallet_1.address().await, +// amount: minimum_amount - 1, // Leave less than min. deposit +// assets: None, +// features: None, +// unlocks: None, +// storage_deposit: Some(StorageDeposit { +// return_strategy: Some(ReturnStrategy::Gift), +// use_excess_if_low: Some(true), +// }), +// }, +// None, +// ) +// .await?; + +// // Check if the output has enough amount to cover the storage deposit +// output.verify_storage_deposit(storage_score_params)?; +// // The left over 21299 is too small to keep, so we donate it +// assert_eq!(output.amount(), balance.base_coin().available()); +// // storage deposit gifted, only address unlock condition +// assert_eq!(output.unlock_conditions().unwrap().len(), 1); + +// let result = wallet_0 +// .prepare_output( +// OutputParams { +// recipient_address: wallet_1.address().await, +// amount: minimum_amount - 1, // Leave less than min. deposit +// assets: None, +// features: None, +// unlocks: None, +// storage_deposit: Some(StorageDeposit { +// return_strategy: Some(ReturnStrategy::Return), +// use_excess_if_low: Some(true), +// }), +// }, +// None, +// ) +// .await; +// assert!( +// matches!(result, Err(iota_sdk::wallet::WalletError::InsufficientFunds{available, required}) if available == +// balance.base_coin().available() && required == 42599) ); + +// let output = wallet_0 +// .prepare_output( +// OutputParams { +// recipient_address: wallet_1.address().await, +// amount: 100, // leave more behind than min. deposit +// assets: None, +// features: None, +// unlocks: None, +// storage_deposit: Some(StorageDeposit { +// return_strategy: Some(ReturnStrategy::Gift), +// use_excess_if_low: Some(true), +// }), +// }, +// None, +// ) +// .await?; + +// // Check if the output has enough amount to cover the storage deposit +// output.verify_storage_deposit(storage_score_params)?; +// // We use excess if leftover is too small, so amount == all available balance +// assert_eq!(output.amount(), 63900); +// // storage deposit gifted, only address unlock condition +// assert_eq!(output.unlock_conditions().unwrap().len(), 1); + +// let output = wallet_0 +// .prepare_output( +// OutputParams { +// recipient_address: wallet_1.address().await, +// amount: 100, // leave more behind than min. deposit +// assets: None, +// features: None, +// unlocks: None, +// storage_deposit: Some(StorageDeposit { +// return_strategy: Some(ReturnStrategy::Return), +// use_excess_if_low: Some(true), +// }), +// }, +// None, +// ) +// .await?; + +// // Check if the output has enough amount to cover the storage deposit +// output.verify_storage_deposit(storage_score_params)?; +// // We use excess if leftover is too small, so amount == all available balance +// assert_eq!(output.amount(), 63900); +// // storage deposit returned, address and SDR unlock condition +// assert_eq!(output.unlock_conditions().unwrap().len(), 2); +// // We have ReturnStrategy::Return, so leftover amount gets returned +// let sdr = output.unlock_conditions().unwrap().storage_deposit_return().unwrap(); +// assert_eq!(sdr.amount(), 63900 - 100); + +// tear_down(storage_path_0)?; +// tear_down(storage_path_1)?; + +// Ok(()) +// } #[ignore] #[tokio::test] @@ -764,8 +764,9 @@ async fn prepare_output_only_single_nft() -> Result<(), Box Result<(), Box Result<(), Box Result<(), WalletError> { -// let storage_path_0 = "test-storage/send_amount_0"; -// setup(storage_path_0)?; -// let storage_path_1 = "test-storage/send_amount_1"; -// setup(storage_path_1)?; +#[tokio::test] +async fn send_amount() -> Result<(), Box> { + let storage_path_0 = "test-storage/send_amount_0"; + setup(storage_path_0)?; + let storage_path_1 = "test-storage/send_amount_1"; + setup(storage_path_1)?; -// let wallet_0 = make_wallet(storage_path_0, None, None).await?; -// request_funds(&wallet_0, 1).await?; + let wallet_0 = make_wallet(storage_path_0, Some(generate_mnemonic()?), None).await?; + request_funds(&wallet_0).await?; -// let wallet_1 = make_wallet(storage_path_1, None, None).await?; + let wallet_1 = make_wallet(storage_path_1, None, None).await?; -// let amount = 1_000_000; -// let tx = wallet_0 -// .send_with_params([SendParams::new(amount, wallet_1.address().clone())?], None) -// .await?; + let amount = 1_000_000; + let tx = wallet_0 + .send_with_params([SendParams::new(amount, wallet_1.address().await)?], None) + .await?; -// wallet_0 -// .wait_for_transaction_acceptance(&tx.transaction_id, None, None) -// .await?; + wallet_0 + .wait_for_transaction_acceptance(&tx.transaction_id, None, None) + .await?; -// let balance = wallet_1.sync(None).await.unwrap(); -// assert_eq!(balance.base_coin().available(), amount); + let balance = wallet_1.sync(None).await.unwrap(); + assert_eq!(balance.base_coin().available(), amount); -// tear_down(storage_path) -// } + tear_down(storage_path_0)?; + tear_down(storage_path_1) +} // #[ignore] // #[tokio::test] -// async fn send_amount_127_outputs() -> Result<(), WalletError> { +// async fn send_amount_127_outputs() -> Result<(), Box> { // let storage_path_0 = "test-storage/send_amount_127_outputs_0"; // setup(storage_path_0)?; // let storage_path_1 = "test-storage/send_amount_127_outputs_1"; @@ -74,7 +74,7 @@ // #[ignore] // #[tokio::test] -// async fn send_amount_custom_input() -> Result<(), WalletError> { +// async fn send_amount_custom_input() -> Result<(), Box> { // let storage_path_0 = "test-storage/send_amount_custom_input_0"; // setup(storage_path_0)?; // let storage_path_1 = "test-storage/send_amount_custom_input_1"; @@ -121,7 +121,7 @@ // #[ignore] // #[tokio::test] -// async fn send_nft() -> Result<(), WalletError> { +// async fn send_nft() -> Result<(), Box> { // let storage_path_0 = "test-storage/send_nft_0"; // setup(storage_path_0)?; // let storage_path_1 = "test-storage/send_nft_1"; @@ -164,7 +164,7 @@ // #[ignore] // #[tokio::test] -// async fn send_with_note() -> Result<(), WalletError> { +// async fn send_with_note() -> Result<(), Box> { // let storage_path_0 = "test-storage/send_with_note_0"; // setup(storage_path_0)?; // let storage_path_1 = "test-storage/send_with_note_1"; @@ -193,7 +193,7 @@ // #[ignore] // #[tokio::test] -// async fn conflicting_transaction() -> Result<(), WalletError> { +// async fn conflicting_transaction() -> Result<(), Box> { // let storage_path_0 = "test-storage/conflicting_transaction_0"; // let storage_path_1 = "test-storage/conflicting_transaction_1"; // setup(storage_path_0)?; @@ -265,7 +265,7 @@ // #[tokio::test] // #[cfg(all(feature = "ledger_nano", feature = "events"))] // #[ignore = "requires ledger nano instance"] -// async fn prepare_transaction_ledger() -> Result<(), WalletError> { +// async fn prepare_transaction_ledger() -> Result<(), Box> { // use iota_sdk::wallet::events::{types::TransactionProgressEvent, WalletEvent, WalletEventType}; // let storage_path_0 = "test-storage/wallet_address_generation_ledger_0";