From 556bfea813d83e39835833dcad54ca5300742c5b Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 6 Dec 2023 16:32:54 -0500 Subject: [PATCH] split online and offline wallet --- bindings/core/src/lib.rs | 6 +- .../core/src/method_handler/call_method.rs | 6 +- bindings/core/src/method_handler/wallet.rs | 5 +- bindings/nodejs/src/wallet.rs | 4 +- bindings/wasm/src/wallet.rs | 3 +- cli/src/cli.rs | 8 +- cli/src/main.rs | 4 +- sdk/examples/how_tos/account/create.rs | 8 +- sdk/examples/how_tos/account/destroy.rs | 8 +- .../how_tos/account_wallet/request_funds.rs | 8 +- .../how_tos/account_wallet/transaction.rs | 7 +- .../accounts_and_addresses/check_balance.rs | 9 +- .../consolidate_outputs.rs | 6 +- .../accounts_and_addresses/list_outputs.rs | 9 +- .../list_transactions.rs | 6 +- .../advanced_transaction.rs | 6 +- .../claim_transaction.rs | 6 +- .../send_micro_transaction.rs | 6 +- sdk/examples/how_tos/native_tokens/burn.rs | 6 +- sdk/examples/how_tos/native_tokens/create.rs | 6 +- .../how_tos/native_tokens/destroy_foundry.rs | 10 +- sdk/examples/how_tos/native_tokens/melt.rs | 10 +- sdk/examples/how_tos/native_tokens/mint.rs | 10 +- sdk/examples/how_tos/native_tokens/send.rs | 6 +- .../nft_collection/00_mint_issuer_nft.rs | 6 +- .../nft_collection/01_mint_collection_nft.rs | 6 +- sdk/examples/how_tos/nfts/burn_nft.rs | 9 +- sdk/examples/how_tos/nfts/mint_nft.rs | 6 +- sdk/examples/how_tos/nfts/send_nft.rs | 6 +- .../simple_transaction/request_funds.rs | 9 +- .../simple_transaction/simple_transaction.rs | 9 +- .../wallet/17_check_unlock_conditions.rs | 6 +- .../offline_signing/0_generate_address.rs | 4 +- .../offline_signing/3_send_transaction.rs | 5 +- sdk/examples/wallet/participation.rs | 7 +- sdk/examples/wallet/spammer.rs | 6 +- sdk/examples/wallet/storage.rs | 4 +- sdk/examples/wallet/wallet.rs | 8 +- sdk/src/lib.rs | 4 +- sdk/src/wallet/core/builder.rs | 368 +++++++++++++----- sdk/src/wallet/core/mod.rs | 337 +++++++++++----- .../core/operations/address_generation.rs | 2 +- .../core/operations/background_syncing.rs | 4 +- sdk/src/wallet/core/operations/client.rs | 17 +- sdk/src/wallet/core/operations/storage.rs | 33 +- sdk/src/wallet/core/operations/stronghold.rs | 6 +- .../core/operations/stronghold_backup/mod.rs | 9 +- .../stronghold_backup/stronghold_snapshot.rs | 12 +- sdk/src/wallet/operations/balance.rs | 8 +- sdk/src/wallet/operations/block.rs | 4 +- sdk/src/wallet/operations/output_claiming.rs | 6 +- .../wallet/operations/output_consolidation.rs | 3 +- .../wallet/operations/participation/event.rs | 14 +- .../wallet/operations/participation/mod.rs | 21 +- .../wallet/operations/participation/voting.rs | 6 +- .../operations/participation/voting_power.rs | 7 +- sdk/src/wallet/operations/reissue.rs | 4 +- .../addresses/output_ids/account_foundry.rs | 4 +- .../syncing/addresses/output_ids/basic.rs | 4 +- .../syncing/addresses/output_ids/mod.rs | 4 +- .../syncing/addresses/output_ids/nft.rs | 4 +- .../operations/syncing/addresses/outputs.rs | 3 +- .../wallet/operations/syncing/foundries.rs | 4 +- sdk/src/wallet/operations/syncing/mod.rs | 5 +- sdk/src/wallet/operations/syncing/outputs.rs | 6 +- .../wallet/operations/syncing/transactions.rs | 6 +- .../wallet/operations/transaction/account.rs | 3 +- .../transaction/build_transaction.rs | 4 +- .../burning_melting/melt_native_token.rs | 3 +- .../high_level/burning_melting/mod.rs | 4 +- .../transaction/high_level/create_account.rs | 3 +- .../high_level/minting/create_native_token.rs | 3 +- .../high_level/minting/mint_native_token.rs | 6 +- .../high_level/minting/mint_nfts.rs | 3 +- .../operations/transaction/high_level/send.rs | 3 +- .../high_level/send_native_tokens.rs | 3 +- .../transaction/high_level/send_nft.rs | 3 +- .../operations/transaction/input_selection.rs | 8 +- sdk/src/wallet/operations/transaction/mod.rs | 3 +- .../operations/transaction/prepare_output.rs | 3 +- .../transaction/prepare_transaction.rs | 3 +- .../transaction/sign_transaction.rs | 4 +- .../transaction/submit_transaction.rs | 4 +- sdk/src/wallet/storage/manager.rs | 42 +- sdk/src/wallet/types/mod.rs | 4 +- sdk/src/wallet/update.rs | 16 +- sdk/tests/wallet/burn_outputs.rs | 6 +- sdk/tests/wallet/common/mod.rs | 8 +- 88 files changed, 890 insertions(+), 408 deletions(-) diff --git a/bindings/core/src/lib.rs b/bindings/core/src/lib.rs index d589a5fead..d3e771f2a6 100644 --- a/bindings/core/src/lib.rs +++ b/bindings/core/src/lib.rs @@ -17,7 +17,7 @@ pub use iota_sdk; use iota_sdk::{ client::secret::{SecretManager, SecretManagerDto}, types::block::address::Bech32Address, - wallet::{ClientOptions, Wallet}, + wallet::{core::Online, ClientOptions, Wallet, WalletBuilder}, }; use serde::Deserialize; @@ -91,9 +91,9 @@ impl WalletOptions { self } - pub async fn build(self) -> iota_sdk::wallet::Result> { + pub async fn build(self) -> iota_sdk::wallet::Result>> { log::debug!("wallet options: {self:?}"); - let mut builder = Wallet::builder() + let mut builder = WalletBuilder::new() .with_address(self.address) .with_alias(self.alias) .with_public_key_options(self.public_key_options) diff --git a/bindings/core/src/method_handler/call_method.rs b/bindings/core/src/method_handler/call_method.rs index 0b20b5789b..22a77f0a65 100644 --- a/bindings/core/src/method_handler/call_method.rs +++ b/bindings/core/src/method_handler/call_method.rs @@ -6,7 +6,7 @@ use std::pin::Pin; use futures::Future; use iota_sdk::{ client::{secret::SecretManager, Client}, - wallet::Wallet, + wallet::{core::Online, Wallet}, }; use crate::{ @@ -35,7 +35,7 @@ impl CallMethod for Client { } } -impl CallMethod for Wallet { +impl CallMethod for Wallet> { type Method = WalletMethod; fn call_method<'a>(&'a self, method: Self::Method) -> Pin + 'a>> { @@ -55,7 +55,7 @@ pub async fn call_client_method(client: &Client, method: ClientMethod) -> Respon } /// Call a wallet method. -pub async fn call_wallet_method(wallet: &Wallet, method: WalletMethod) -> Response { +pub async fn call_wallet_method(wallet: &Wallet>, method: WalletMethod) -> Response { log::debug!("Wallet method: {method:?}"); let result = convert_async_panics(|| async { call_wallet_method_internal(wallet, method).await }).await; diff --git a/bindings/core/src/method_handler/wallet.rs b/bindings/core/src/method_handler/wallet.rs index a9b9617ea2..ada8c76e6e 100644 --- a/bindings/core/src/method_handler/wallet.rs +++ b/bindings/core/src/method_handler/wallet.rs @@ -11,7 +11,8 @@ use iota_sdk::{ }, types::TryFromDto, wallet::{ - types::TransactionWithMetadataDto, BlockIssuerKeySource, PreparedCreateNativeTokenTransactionDto, Wallet, + core::Online, types::TransactionWithMetadataDto, BlockIssuerKeySource, PreparedCreateNativeTokenTransactionDto, + Wallet, }, }; @@ -19,7 +20,7 @@ use crate::{method::WalletMethod, response::Response}; /// Call a wallet method. pub(crate) async fn call_wallet_method_internal( - wallet: &Wallet, + wallet: &Wallet>, method: WalletMethod, ) -> crate::Result { let response = match method { diff --git a/bindings/nodejs/src/wallet.rs b/bindings/nodejs/src/wallet.rs index 182854e900..eb25950c66 100644 --- a/bindings/nodejs/src/wallet.rs +++ b/bindings/nodejs/src/wallet.rs @@ -7,7 +7,7 @@ use iota_sdk_bindings_core::{ call_wallet_method as rust_call_wallet_method, iota_sdk::{ client::secret::SecretManager, - wallet::{events::WalletEventType, Wallet}, + wallet::{core::Online, events::WalletEventType, Wallet}, }, Response, WalletMethod, WalletOptions, }; @@ -17,7 +17,7 @@ use tokio::sync::RwLock; use crate::{client::ClientMethodHandler, secret_manager::SecretManagerMethodHandler, NodejsError}; -pub type WalletMethodHandler = Arc>>>; +pub type WalletMethodHandler = Arc>>>>; #[napi(js_name = "createWallet")] pub async fn create_wallet(options: String) -> Result> { diff --git a/bindings/wasm/src/wallet.rs b/bindings/wasm/src/wallet.rs index e5b163cb53..71ddfa1de9 100644 --- a/bindings/wasm/src/wallet.rs +++ b/bindings/wasm/src/wallet.rs @@ -8,6 +8,7 @@ use iota_sdk_bindings_core::{ iota_sdk::{ client::secret::SecretManager, wallet::{ + core::Online, events::types::{WalletEvent, WalletEventType}, Wallet, }, @@ -25,7 +26,7 @@ use crate::{client::ClientMethodHandler, secret_manager::SecretManagerMethodHand /// The Wallet method handler. #[wasm_bindgen(js_name = WalletMethodHandler)] pub struct WalletMethodHandler { - wallet: Arc>>>, + wallet: Arc>>>>, } /// Creates a method handler with the given options. diff --git a/cli/src/cli.rs b/cli/src/cli.rs index c9d6b3ca99..a29678fa34 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -13,7 +13,7 @@ use iota_sdk::{ }, crypto::keys::bip44::Bip44, types::block::address::Bech32Address, - wallet::ClientOptions, + wallet::{ClientOptions, WalletBuilder}, }; use log::LevelFilter; @@ -291,7 +291,7 @@ pub async fn init_command( .with_address_index(bip.address_index) }); - Ok(Wallet::builder() + Ok(WalletBuilder::new() .with_secret_manager(secret_manager) .with_client_options(ClientOptions::new().with_node(init_params.node_url.as_str())?) .with_storage_path(storage_path.to_str().expect("invalid unicode")) @@ -332,7 +332,7 @@ pub async fn node_info_command(storage_path: &Path) -> Result { pub async fn restore_command(storage_path: &Path, snapshot_path: &Path, backup_path: &Path) -> Result { check_file_exists(backup_path).await?; - let mut builder = Wallet::builder(); + let mut builder = WalletBuilder::new().into_online(); if check_file_exists(snapshot_path).await.is_ok() { println!( "Detected a stronghold file at {}. Enter password to unlock:", @@ -400,7 +400,7 @@ pub async fn unlock_wallet( None }; - let maybe_wallet = Wallet::builder() + let maybe_wallet = WalletBuilder::new() .with_secret_manager(secret_manager) .with_storage_path(storage_path.to_str().expect("invalid unicode")) .finish() diff --git a/cli/src/main.rs b/cli/src/main.rs index d8e4d83401..dec3b8579d 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -8,7 +8,7 @@ mod wallet_cli; use clap::Parser; use fern_logger::{LoggerConfigBuilder, LoggerOutputConfigBuilder}; -use iota_sdk::client::secret::stronghold::StrongholdSecretManager; +use iota_sdk::{client::secret::stronghold::StrongholdSecretManager, wallet::core::Online}; use log::LevelFilter; use self::{ @@ -16,7 +16,7 @@ use self::{ error::Error, }; -pub type Wallet = iota_sdk::wallet::Wallet; +pub type Wallet = iota_sdk::wallet::Wallet>; #[macro_export] macro_rules! println_log_info { diff --git a/sdk/examples/how_tos/account/create.rs b/sdk/examples/how_tos/account/create.rs index a9d44a25ca..f19638c184 100644 --- a/sdk/examples/how_tos/account/create.rs +++ b/sdk/examples/how_tos/account/create.rs @@ -12,7 +12,10 @@ //! cargo run --release --all-features --example create_account_output //! ``` -use iota_sdk::{wallet::Result, Wallet}; +use iota_sdk::{ + client::secret::SecretManager, + wallet::{Result, WalletBuilder}, +}; #[tokio::main] async fn main() -> Result<()> { @@ -23,7 +26,8 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".env variable '{var}' is undefined, see .env.example")); } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/account/destroy.rs b/sdk/examples/how_tos/account/destroy.rs index 20930776f6..7ddd2a8953 100644 --- a/sdk/examples/how_tos/account/destroy.rs +++ b/sdk/examples/how_tos/account/destroy.rs @@ -11,14 +11,18 @@ //! cargo run --release --all-features --example destroy_account_output //! ``` -use iota_sdk::{wallet::Result, Wallet}; +use iota_sdk::{ + client::secret::SecretManager, + wallet::{Result, WalletBuilder}, +}; #[tokio::main] async fn main() -> Result<()> { // This example uses secrets in environment variables for simplicity which should not be done in production. dotenvy::dotenv().ok(); - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/account_wallet/request_funds.rs b/sdk/examples/how_tos/account_wallet/request_funds.rs index 2604143aea..45d4a5f5f2 100644 --- a/sdk/examples/how_tos/account_wallet/request_funds.rs +++ b/sdk/examples/how_tos/account_wallet/request_funds.rs @@ -7,10 +7,9 @@ //! `cargo run --release --all-features --example account_wallet_request_funds` use iota_sdk::{ - client::request_funds_from_faucet, + client::{request_funds_from_faucet, secret::mnemonic::MnemonicSecretManager}, types::block::address::{AccountAddress, ToBech32Ext}, - wallet::{AccountSyncOptions, Result, SyncOptions}, - Wallet, + wallet::{AccountSyncOptions, Result, SyncOptions, WalletBuilder}, }; #[tokio::main] @@ -25,7 +24,8 @@ async fn main() -> Result<()> { let faucet_url = std::env::var("FAUCET_URL").unwrap(); // Create the wallet - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/account_wallet/transaction.rs b/sdk/examples/how_tos/account_wallet/transaction.rs index a6183ef651..c99d35246e 100644 --- a/sdk/examples/how_tos/account_wallet/transaction.rs +++ b/sdk/examples/how_tos/account_wallet/transaction.rs @@ -7,9 +7,9 @@ //! `cargo run --release --all-features --example account_wallet_transaction` use iota_sdk::{ - client::node_api::indexer::query_parameters::BasicOutputQueryParameters, + client::{node_api::indexer::query_parameters::BasicOutputQueryParameters, secret::SecretManager}, types::block::address::{AccountAddress, ToBech32Ext}, - wallet::{AccountSyncOptions, Result, SyncOptions, TransactionOptions}, + wallet::{AccountSyncOptions, Result, SyncOptions, TransactionOptions, WalletBuilder}, Wallet, }; @@ -31,7 +31,8 @@ async fn main() -> Result<()> { }; // Create the wallet - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/accounts_and_addresses/check_balance.rs b/sdk/examples/how_tos/accounts_and_addresses/check_balance.rs index 6cfda4f7a1..d47e4f35a0 100644 --- a/sdk/examples/how_tos/accounts_and_addresses/check_balance.rs +++ b/sdk/examples/how_tos/accounts_and_addresses/check_balance.rs @@ -11,7 +11,11 @@ //! cargo run --release --all-features --example check_balance //! ``` -use iota_sdk::{wallet::Result, Wallet}; +use iota_sdk::{ + client::secret::SecretManager, + wallet::{Result, WalletBuilder}, + Wallet, +}; #[tokio::main] async fn main() -> Result<()> { @@ -22,7 +26,8 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".env variable '{var}' is undefined, see .env.example")); } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/accounts_and_addresses/consolidate_outputs.rs b/sdk/examples/how_tos/accounts_and_addresses/consolidate_outputs.rs index 6280965836..b2edc46204 100644 --- a/sdk/examples/how_tos/accounts_and_addresses/consolidate_outputs.rs +++ b/sdk/examples/how_tos/accounts_and_addresses/consolidate_outputs.rs @@ -13,8 +13,9 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::address::ToBech32Ext, - wallet::{ConsolidationParams, Result}, + wallet::{ConsolidationParams, Result, WalletBuilder}, Wallet, }; @@ -29,7 +30,8 @@ async fn main() -> Result<()> { } } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/accounts_and_addresses/list_outputs.rs b/sdk/examples/how_tos/accounts_and_addresses/list_outputs.rs index 08b416c09f..091aafdf39 100644 --- a/sdk/examples/how_tos/accounts_and_addresses/list_outputs.rs +++ b/sdk/examples/how_tos/accounts_and_addresses/list_outputs.rs @@ -8,7 +8,11 @@ //! cargo run --release --all-features --example list_outputs //! ``` -use iota_sdk::{wallet::Result, Wallet}; +use iota_sdk::{ + client::secret::SecretManager, + wallet::{Result, WalletBuilder}, + Wallet, +}; #[tokio::main] async fn main() -> Result<()> { @@ -20,7 +24,8 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".env variable '{var}' is undefined, see .env.example")); } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/accounts_and_addresses/list_transactions.rs b/sdk/examples/how_tos/accounts_and_addresses/list_transactions.rs index 3b416eabad..fcef20ed45 100644 --- a/sdk/examples/how_tos/accounts_and_addresses/list_transactions.rs +++ b/sdk/examples/how_tos/accounts_and_addresses/list_transactions.rs @@ -9,7 +9,8 @@ //! ``` use iota_sdk::{ - wallet::{Result, SyncOptions}, + client::secret::SecretManager, + wallet::{Result, SyncOptions, WalletBuilder}, Wallet, }; @@ -23,7 +24,8 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".env variable '{var}' is undefined, see .env.example")); } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/advanced_transactions/advanced_transaction.rs b/sdk/examples/how_tos/advanced_transactions/advanced_transaction.rs index 6b07de8487..1e8adc9246 100644 --- a/sdk/examples/how_tos/advanced_transactions/advanced_transaction.rs +++ b/sdk/examples/how_tos/advanced_transactions/advanced_transaction.rs @@ -8,6 +8,7 @@ //! `cargo run --release --all-features --example advanced_transaction` use iota_sdk::{ + client::secret::SecretManager, types::block::{ address::Bech32Address, output::{ @@ -16,7 +17,7 @@ use iota_sdk::{ }, slot::SlotIndex, }, - wallet::Result, + wallet::{Result, WalletBuilder}, Wallet, }; @@ -30,7 +31,8 @@ async fn main() -> Result<()> { } // Get the wallet we generated with `create_wallet`. - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/advanced_transactions/claim_transaction.rs b/sdk/examples/how_tos/advanced_transactions/claim_transaction.rs index 6e8a8a60f3..30e1ee2330 100644 --- a/sdk/examples/how_tos/advanced_transactions/claim_transaction.rs +++ b/sdk/examples/how_tos/advanced_transactions/claim_transaction.rs @@ -7,7 +7,8 @@ //! `cargo run --release --all-features --example claim_transaction` use iota_sdk::{ - wallet::{OutputsToClaim, Result}, + client::secret::SecretManager, + wallet::{OutputsToClaim, Result, WalletBuilder}, Wallet, }; @@ -21,7 +22,8 @@ async fn main() -> Result<()> { } // Get the wallet we generated with `create_wallet`. - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/advanced_transactions/send_micro_transaction.rs b/sdk/examples/how_tos/advanced_transactions/send_micro_transaction.rs index 80b50eae56..58c9e92c74 100644 --- a/sdk/examples/how_tos/advanced_transactions/send_micro_transaction.rs +++ b/sdk/examples/how_tos/advanced_transactions/send_micro_transaction.rs @@ -12,7 +12,8 @@ //! ``` use iota_sdk::{ - wallet::{Result, TransactionOptions}, + client::secret::SecretManager, + wallet::{Result, TransactionOptions, WalletBuilder}, Wallet, }; @@ -31,7 +32,8 @@ async fn main() -> Result<()> { } // Get the wallet we generated with `create_wallet`. - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/native_tokens/burn.rs b/sdk/examples/how_tos/native_tokens/burn.rs index 42e2a3773e..344509db77 100644 --- a/sdk/examples/how_tos/native_tokens/burn.rs +++ b/sdk/examples/how_tos/native_tokens/burn.rs @@ -17,8 +17,9 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::output::{NativeToken, TokenId}, - wallet::Result, + wallet::{Result, WalletBuilder}, Wallet, U256, }; @@ -36,7 +37,8 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".env variable '{var}' is undefined, see .env.example")); } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/native_tokens/create.rs b/sdk/examples/how_tos/native_tokens/create.rs index 467162c741..f6f96dea0c 100644 --- a/sdk/examples/how_tos/native_tokens/create.rs +++ b/sdk/examples/how_tos/native_tokens/create.rs @@ -12,8 +12,9 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::output::feature::Irc30Metadata, - wallet::{CreateNativeTokenParams, Result}, + wallet::{CreateNativeTokenParams, Result, WalletBuilder}, Wallet, U256, }; @@ -31,7 +32,8 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".env variable '{var}' is undefined, see .env.example")); } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/native_tokens/destroy_foundry.rs b/sdk/examples/how_tos/native_tokens/destroy_foundry.rs index 3304548b9d..c9afc1ec09 100644 --- a/sdk/examples/how_tos/native_tokens/destroy_foundry.rs +++ b/sdk/examples/how_tos/native_tokens/destroy_foundry.rs @@ -12,7 +12,12 @@ //! cargo run --release --all-features --example destroy_foundry //! ``` -use iota_sdk::{types::block::output::TokenId, wallet::Result, Wallet}; +use iota_sdk::{ + client::secret::SecretManager, + types::block::output::TokenId, + wallet::{Result, WalletBuilder}, + Wallet, +}; #[tokio::main] async fn main() -> Result<()> { @@ -23,7 +28,8 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".env variable '{var}' is undefined, see .env.example")); } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/native_tokens/melt.rs b/sdk/examples/how_tos/native_tokens/melt.rs index 779beda4fe..8e1e4fd080 100644 --- a/sdk/examples/how_tos/native_tokens/melt.rs +++ b/sdk/examples/how_tos/native_tokens/melt.rs @@ -16,7 +16,12 @@ //! cargo run --release --all-features --example melt_native_token [TOKEN_ID] //! ``` -use iota_sdk::{types::block::output::TokenId, wallet::Result, Wallet}; +use iota_sdk::{ + client::secret::SecretManager, + types::block::output::TokenId, + wallet::{Result, WalletBuilder}, + Wallet, +}; // The amount of native tokens to melt const MELT_AMOUNT: u64 = 10; @@ -30,7 +35,8 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".env variable '{var}' is undefined, see .env.example")); } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/native_tokens/mint.rs b/sdk/examples/how_tos/native_tokens/mint.rs index 44ed6db3ab..67ac71961a 100644 --- a/sdk/examples/how_tos/native_tokens/mint.rs +++ b/sdk/examples/how_tos/native_tokens/mint.rs @@ -16,7 +16,12 @@ //! cargo run --release --all-features --example mint_native_token [TOKEN_ID] //! ``` -use iota_sdk::{types::block::output::TokenId, wallet::Result, Wallet}; +use iota_sdk::{ + client::secret::SecretManager, + types::block::output::TokenId, + wallet::{Result, WalletBuilder}, + Wallet, +}; // The amount of native tokens to mint const MINT_AMOUNT: u64 = 10; @@ -30,7 +35,8 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".env variable '{var}' is undefined, see .env.example")); } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/native_tokens/send.rs b/sdk/examples/how_tos/native_tokens/send.rs index 5e765bd153..18fdbc6652 100644 --- a/sdk/examples/how_tos/native_tokens/send.rs +++ b/sdk/examples/how_tos/native_tokens/send.rs @@ -12,8 +12,9 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::address::Bech32Address, - wallet::{Result, SendNativeTokenParams}, + wallet::{Result, SendNativeTokenParams, WalletBuilder}, Wallet, }; use primitive_types::U256; @@ -32,7 +33,8 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".env variable '{var}' is undefined, see .env.example")); } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/nft_collection/00_mint_issuer_nft.rs b/sdk/examples/how_tos/nft_collection/00_mint_issuer_nft.rs index 2a0e5bca56..f8abaadc93 100644 --- a/sdk/examples/how_tos/nft_collection/00_mint_issuer_nft.rs +++ b/sdk/examples/how_tos/nft_collection/00_mint_issuer_nft.rs @@ -15,11 +15,12 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::{ output::{NftId, Output, OutputId}, payload::signed_transaction::TransactionId, }, - wallet::{MintNftParams, Result}, + wallet::{MintNftParams, Result, WalletBuilder}, Wallet, }; @@ -32,7 +33,8 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".env variable '{var}' is undefined, see .env.example")); } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/nft_collection/01_mint_collection_nft.rs b/sdk/examples/how_tos/nft_collection/01_mint_collection_nft.rs index 914897800e..867143eeef 100644 --- a/sdk/examples/how_tos/nft_collection/01_mint_collection_nft.rs +++ b/sdk/examples/how_tos/nft_collection/01_mint_collection_nft.rs @@ -15,12 +15,13 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::{ address::{Bech32Address, NftAddress}, output::{feature::Irc27Metadata, NftId}, payload::signed_transaction::TransactionId, }, - wallet::{MintNftParams, Result}, + wallet::{MintNftParams, Result, WalletBuilder}, Wallet, }; @@ -43,7 +44,8 @@ async fn main() -> Result<()> { .expect("missing example argument: ISSUER_NFT_ID") .parse::()?; - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/nfts/burn_nft.rs b/sdk/examples/how_tos/nfts/burn_nft.rs index 227a777063..8e4519a24c 100644 --- a/sdk/examples/how_tos/nfts/burn_nft.rs +++ b/sdk/examples/how_tos/nfts/burn_nft.rs @@ -11,7 +11,11 @@ //! cargo run --release --all-features --example burn_nft //! ``` -use iota_sdk::{wallet::Result, Wallet}; +use iota_sdk::{ + client::secret::SecretManager, + wallet::{Result, WalletBuilder}, + Wallet, +}; #[tokio::main] async fn main() -> Result<()> { @@ -23,7 +27,8 @@ async fn main() -> Result<()> { } // Create the wallet - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/nfts/mint_nft.rs b/sdk/examples/how_tos/nfts/mint_nft.rs index 10264f07c9..7f06ea011a 100644 --- a/sdk/examples/how_tos/nfts/mint_nft.rs +++ b/sdk/examples/how_tos/nfts/mint_nft.rs @@ -12,12 +12,13 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::output::{ feature::{Irc27Metadata, IssuerFeature, SenderFeature}, unlock_condition::AddressUnlockCondition, NftId, NftOutputBuilder, }, - wallet::{MintNftParams, Result}, + wallet::{MintNftParams, Result, WalletBuilder}, Wallet, }; @@ -40,7 +41,8 @@ async fn main() -> Result<()> { } // Get the wallet we generated with `create_wallet`. - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/nfts/send_nft.rs b/sdk/examples/how_tos/nfts/send_nft.rs index ba4b29d288..3fa38ad7f8 100644 --- a/sdk/examples/how_tos/nfts/send_nft.rs +++ b/sdk/examples/how_tos/nfts/send_nft.rs @@ -12,7 +12,8 @@ //! ``` use iota_sdk::{ - wallet::{Result, SendNftParams}, + client::secret::SecretManager, + wallet::{Result, SendNftParams, WalletBuilder}, Wallet, }; @@ -29,7 +30,8 @@ async fn main() -> Result<()> { } // Create the wallet - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/simple_transaction/request_funds.rs b/sdk/examples/how_tos/simple_transaction/request_funds.rs index 13a0de5254..8cfe700e5a 100644 --- a/sdk/examples/how_tos/simple_transaction/request_funds.rs +++ b/sdk/examples/how_tos/simple_transaction/request_funds.rs @@ -11,7 +11,11 @@ //! cargo run --release --all-features --example request_funds //! ``` -use iota_sdk::{client::request_funds_from_faucet, wallet::Result, Wallet}; +use iota_sdk::{ + client::{request_funds_from_faucet, secret::SecretManager}, + wallet::{Result, WalletBuilder}, + Wallet, +}; #[tokio::main] async fn main() -> Result<()> { @@ -22,7 +26,8 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".env variable '{var}' is undefined, see .env.example")); } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/simple_transaction/simple_transaction.rs b/sdk/examples/how_tos/simple_transaction/simple_transaction.rs index 9990e6843e..f41896233c 100644 --- a/sdk/examples/how_tos/simple_transaction/simple_transaction.rs +++ b/sdk/examples/how_tos/simple_transaction/simple_transaction.rs @@ -11,7 +11,11 @@ //! cargo run --release --all-features --example simple_transaction //! ``` -use iota_sdk::{wallet::Result, Wallet}; +use iota_sdk::{ + client::secret::SecretManager, + wallet::{Result, WalletBuilder}, + Wallet, +}; // The base coin amount to send const SEND_AMOUNT: u64 = 1_000_000; @@ -27,7 +31,8 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".env variable '{var}' is undefined, see .env.example")); } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/wallet/17_check_unlock_conditions.rs b/sdk/examples/wallet/17_check_unlock_conditions.rs index dda853bc04..756462c51d 100644 --- a/sdk/examples/wallet/17_check_unlock_conditions.rs +++ b/sdk/examples/wallet/17_check_unlock_conditions.rs @@ -11,8 +11,9 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::output::{unlock_condition::AddressUnlockCondition, BasicOutputBuilder, UnlockCondition}, - wallet::Result, + wallet::{Result, WalletBuilder}, Wallet, }; @@ -29,7 +30,8 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".env variable '{var}' is undefined, see .env.example")); } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/wallet/offline_signing/0_generate_address.rs b/sdk/examples/wallet/offline_signing/0_generate_address.rs index a1d574c747..3abb6d085d 100644 --- a/sdk/examples/wallet/offline_signing/0_generate_address.rs +++ b/sdk/examples/wallet/offline_signing/0_generate_address.rs @@ -14,7 +14,7 @@ use iota_sdk::{ secret::{stronghold::StrongholdSecretManager, PublicKeyOptions, SecretManage}, }, crypto::keys::{bip39::Mnemonic, bip44::Bip44}, - wallet::{ClientOptions, Result, Wallet}, + wallet::{core::Online, ClientOptions, Result, Wallet}, }; const OFFLINE_WALLET_DB_PATH: &str = "./examples/wallet/offline_signing/example-offline-walletdb"; @@ -57,7 +57,7 @@ async fn main() -> Result<()> { write_wallet_address_to_file(&wallet).await } -async fn write_wallet_address_to_file(wallet: &Wallet) -> Result<()> { +async fn write_wallet_address_to_file(wallet: &Wallet>) -> Result<()> { use tokio::io::AsyncWriteExt; let wallet_address = wallet.address().await; diff --git a/sdk/examples/wallet/offline_signing/3_send_transaction.rs b/sdk/examples/wallet/offline_signing/3_send_transaction.rs index 3e3675e0bf..80f65b60a4 100644 --- a/sdk/examples/wallet/offline_signing/3_send_transaction.rs +++ b/sdk/examples/wallet/offline_signing/3_send_transaction.rs @@ -15,7 +15,7 @@ use iota_sdk::{ Client, }, types::{block::payload::signed_transaction::TransactionId, TryFromDto}, - wallet::Result, + wallet::{Result, WalletBuilder}, Wallet, }; use serde::de::DeserializeOwned; @@ -34,7 +34,8 @@ async fn main() -> Result<()> { } // Create the wallet with the secret_manager and client options - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(ONLINE_WALLET_DB_PATH) .with_secret_manager(SecretManager::Placeholder) .finish() diff --git a/sdk/examples/wallet/participation.rs b/sdk/examples/wallet/participation.rs index 190ff79462..d49177d7ce 100644 --- a/sdk/examples/wallet/participation.rs +++ b/sdk/examples/wallet/participation.rs @@ -17,8 +17,8 @@ //! ``` use iota_sdk::{ - client::node_manager::node::Node, - wallet::{types::participation::ParticipationEventRegistrationOptions, Result}, + client::{node_manager::node::Node, secret::SecretManager}, + wallet::{types::participation::ParticipationEventRegistrationOptions, Result, WalletBuilder}, Wallet, }; use url::Url; @@ -46,7 +46,8 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".env variable '{var}' is undefined, see .env.example")); } - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() + .into_online::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/wallet/spammer.rs b/sdk/examples/wallet/spammer.rs index e497f3af21..1a0a60cc33 100644 --- a/sdk/examples/wallet/spammer.rs +++ b/sdk/examples/wallet/spammer.rs @@ -20,7 +20,7 @@ use iota_sdk::{ output::BasicOutput, payload::signed_transaction::TransactionId, }, - wallet::{ClientOptions, FilterOptions, Result, SendParams, Wallet}, + wallet::{core::Online, ClientOptions, FilterOptions, Result, SendParams, Wallet}, }; // The number of spamming rounds. @@ -157,7 +157,7 @@ async fn main() -> Result<()> { } async fn ensure_enough_funds( - wallet: &Wallet, + wallet: &Wallet>, bech32_address: &Bech32Address, ) -> Result<()> { let balance = wallet.sync(None).await?; @@ -201,7 +201,7 @@ async fn ensure_enough_funds( } async fn wait_for_inclusion( - wallet: &Wallet, + wallet: &Wallet>, transaction_id: &TransactionId, ) -> Result<()> { println!( diff --git a/sdk/examples/wallet/storage.rs b/sdk/examples/wallet/storage.rs index 9cdf963007..3bf3215b1c 100644 --- a/sdk/examples/wallet/storage.rs +++ b/sdk/examples/wallet/storage.rs @@ -14,7 +14,7 @@ use iota_sdk::{ secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManage}, }, crypto::keys::bip44::Bip44, - wallet::{ClientOptions, Result, Wallet}, + wallet::{core::Online, ClientOptions, Result, Wallet}, }; #[tokio::main] @@ -49,7 +49,7 @@ async fn main() -> Result<()> { Ok(()) } -async fn sync_print_balance(wallet: &Wallet) -> Result<()> { +async fn sync_print_balance(wallet: &Wallet>) -> Result<()> { let alias = wallet.alias().await; let now = tokio::time::Instant::now(); let balance = wallet.sync(None).await?; diff --git a/sdk/examples/wallet/wallet.rs b/sdk/examples/wallet/wallet.rs index a5c2973091..ff45a2ad3e 100644 --- a/sdk/examples/wallet/wallet.rs +++ b/sdk/examples/wallet/wallet.rs @@ -21,7 +21,7 @@ use iota_sdk::{ secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManage}, }, types::block::payload::signed_transaction::TransactionId, - wallet::{ClientOptions, Result, Wallet}, + wallet::{core::Online, ClientOptions, Result, Wallet}, }; // The amount of coins to send @@ -53,7 +53,7 @@ async fn main() -> Result<()> { Ok(()) } -async fn create_wallet() -> Result> { +async fn create_wallet() -> Result>> { let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; Wallet::builder() @@ -66,7 +66,7 @@ async fn create_wallet() -> Result> { .await } -async fn sync_print_balance(wallet: &Wallet, full_report: bool) -> Result<()> { +async fn sync_print_balance(wallet: &Wallet>, full_report: bool) -> Result<()> { let now = tokio::time::Instant::now(); let balance = wallet.sync(None).await?; println!("Wallet synced in: {:.2?}", now.elapsed()); @@ -79,7 +79,7 @@ async fn sync_print_balance(wallet: &Wallet, full_ } async fn wait_for_inclusion( - wallet: &Wallet, + wallet: &Wallet>, transaction_id: &TransactionId, ) -> Result<()> { println!( diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index ce004f33d2..1fa61f90db 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -28,5 +28,7 @@ pub use crypto; pub use packable; pub use primitive_types::U256; +use crate::wallet::core::Online; + #[cfg(feature = "wallet")] -pub type Wallet = self::wallet::Wallet; +pub type Wallet = self::wallet::Wallet>; diff --git a/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index c9b3ef6d48..76dcc01842 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -5,6 +5,7 @@ use std::collections::HashSet; use std::sync::{atomic::AtomicUsize, Arc}; +use async_trait::async_trait; use serde::Serialize; use tokio::sync::{Mutex, RwLock}; @@ -18,61 +19,71 @@ use crate::{ client::secret::{SecretManage, SecretManager, SecretManagerConfig}, types::block::address::{Bech32Address, Ed25519Address, ToBech32Ext}, wallet::{ - core::{WalletData, WalletInner}, + core::{Offline, OfflineWalletData, Online, OnlineWalletData, WalletCommon, WalletStorageOptions}, operations::syncing::SyncOptions, ClientOptions, Wallet, }, }; /// Builder for the wallet. -#[derive(Debug, Serialize)] +#[derive(Debug, Default, Serialize)] #[serde(rename_all = "camelCase")] -pub struct WalletBuilder { - pub(crate) public_key_options: Option, - pub(crate) signing_options: Option, +pub struct WalletBuilder { + #[serde(flatten)] + pub(crate) inner: T, pub(crate) address: Option, pub(crate) alias: Option, - pub(crate) client_options: Option, #[cfg(feature = "storage")] pub(crate) storage_options: Option, +} + +impl core::ops::Deref for WalletBuilder { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct OnlineBuilder { + pub(crate) public_key_options: Option, + pub(crate) signing_options: Option, + pub(crate) client_options: Option, #[serde(skip)] pub(crate) secret_manager: Option>>, } -impl Default for WalletBuilder { +#[derive(Debug, Default, Serialize)] +pub struct OfflineBuilder; + +impl Default for OnlineBuilder { fn default() -> Self { Self { public_key_options: Default::default(), signing_options: Default::default(), - address: Default::default(), - alias: Default::default(), client_options: Default::default(), - #[cfg(feature = "storage")] - storage_options: Default::default(), secret_manager: Default::default(), } } } -impl WalletBuilder { - /// Initialises a new instance of the wallet builder with the default storage adapter. +impl WalletBuilder { + /// Initialises a new instance of the wallet builder. pub fn new() -> Self { - Self { - secret_manager: None, - ..Default::default() - } - } - - /// Set the public key options. - pub fn with_public_key_options(mut self, public_key_options: impl Into>) -> Self { - self.public_key_options = public_key_options.into(); - self + Self::default() } +} - /// Set the signing options. - pub fn with_signing_options(mut self, signing_options: impl Into>) -> Self { - self.signing_options = signing_options.into(); - self +impl WalletBuilder { + pub fn into_online(self) -> WalletBuilder> { + WalletBuilder { + inner: Default::default(), + address: self.address, + alias: self.alias, + storage_options: self.storage_options, + } } /// Set the wallet address. @@ -87,12 +98,6 @@ impl WalletBuilder { self } - /// Set the client options for the core nodes. - pub fn with_client_options(mut self, client_options: impl Into>) -> Self { - self.client_options = client_options.into(); - self - } - /// Set the storage options to be used. #[cfg(feature = "storage")] #[cfg_attr(docsrs, doc(cfg(feature = "storage")))] @@ -101,16 +106,77 @@ impl WalletBuilder { self } - /// Set the secret_manager to be used. - pub fn with_secret_manager(mut self, secret_manager: impl Into>) -> Self { - self.secret_manager = secret_manager.into().map(|sm| Arc::new(RwLock::new(sm))); + /// Set the storage path to be used. + #[cfg(feature = "storage")] + #[cfg_attr(docsrs, doc(cfg(feature = "storage")))] + pub fn with_storage_path(mut self, path: &str) -> Self { + self.storage_options = Some(StorageOptions { + path: path.into(), + ..Default::default() + }); self } + /// Set the public key options. + pub fn with_public_key_options( + mut self, + public_key_options: impl Into>, + ) -> WalletBuilder> { + self.into_online::().with_public_key_options(public_key_options) + } + + /// Set the signing options. + pub fn with_signing_options( + mut self, + signing_options: impl Into>, + ) -> WalletBuilder> { + self.into_online::().with_signing_options(signing_options) + } + + /// Set the client options for the core nodes. + pub fn with_client_options( + mut self, + client_options: impl Into>, + ) -> WalletBuilder> { + self.into_online::().with_client_options(client_options) + } + + /// Set the secret_manager to be used. + pub fn with_secret_manager( + mut self, + secret_manager: impl Into>, + ) -> WalletBuilder> { + self.into_online::().with_secret_manager(secret_manager) + } + /// Set the secret_manager to be used wrapped in an Arc> so it can be cloned and mutated also outside of /// the Wallet. - pub fn with_secret_manager_arc(mut self, secret_manager: impl Into>>>) -> Self { - self.secret_manager = secret_manager.into(); + pub fn with_secret_manager_arc( + mut self, + secret_manager: impl Into>>>, + ) -> WalletBuilder> { + self.into_online::().with_secret_manager_arc(secret_manager) + } +} + +impl WalletBuilder> { + /// Set the wallet address. + pub fn with_address(mut self, address: impl Into>) -> Self { + self.address = address.into(); + self + } + + /// Set the alias of the wallet. + pub fn with_alias(mut self, alias: impl Into>) -> Self { + self.alias = alias.into(); + self + } + + /// Set the storage options to be used. + #[cfg(feature = "storage")] + #[cfg_attr(docsrs, doc(cfg(feature = "storage")))] + pub fn with_storage_options(mut self, storage_options: impl Into>) -> Self { + self.storage_options = storage_options.into(); self } @@ -124,14 +190,45 @@ impl WalletBuilder { }); self } + + /// Set the public key options. + pub fn with_public_key_options(mut self, public_key_options: impl Into>) -> Self { + self.inner.public_key_options = public_key_options.into(); + self + } + + /// Set the signing options. + pub fn with_signing_options(mut self, signing_options: impl Into>) -> Self { + self.inner.signing_options = signing_options.into(); + self + } + + /// Set the client options for the core nodes. + pub fn with_client_options(mut self, client_options: impl Into>) -> Self { + self.inner.client_options = client_options.into(); + self + } + + /// Set the secret_manager to be used. + pub fn with_secret_manager(mut self, secret_manager: impl Into>) -> Self { + self.inner.secret_manager = secret_manager.into().map(|sm| Arc::new(RwLock::new(sm))); + self + } + + /// Set the secret_manager to be used wrapped in an Arc> so it can be cloned and mutated also outside of + /// the Wallet. + pub fn with_secret_manager_arc(mut self, secret_manager: impl Into>>>) -> Self { + self.inner.secret_manager = secret_manager.into(); + self + } } -impl WalletBuilder +impl WalletBuilder> where for<'a> &'a S::GenerationOptions: PartialEq, { /// Builds the wallet. - pub async fn finish(mut self) -> crate::wallet::Result> { + pub async fn finish(mut self) -> crate::wallet::Result>> { log::debug!("[WalletBuilder]"); #[cfg(feature = "storage")] @@ -165,7 +262,7 @@ where .ok_or(crate::wallet::Error::MissingParameter("client_options"))?; // Update self so it gets used and stored again - self.client_options = Some(loaded_client_options); + self.inner.client_options = Some(loaded_client_options); false } else { true @@ -177,12 +274,12 @@ where .as_ref() .and_then(|builder| builder.secret_manager.clone()); - self.secret_manager = secret_manager; + self.inner.secret_manager = secret_manager; } // May use previously stored options if they weren't provided if self.public_key_options.is_none() { - self.public_key_options = loaded_wallet_builder + self.inner.public_key_options = loaded_wallet_builder .as_ref() .and_then(|builder| builder.public_key_options.clone()); } @@ -212,21 +309,17 @@ where let address = self.address.as_ref().unwrap().clone(); #[cfg(feature = "storage")] - let mut wallet_data = storage_manager.load_wallet_data::().await?; + let mut wallet_data = storage_manager.load_wallet_data::, _>().await?; // The public key options must not change. #[cfg(feature = "storage")] if let Some(wallet_data) = &wallet_data { let old = &wallet_data.public_key_options; - if let Some(new) = self.public_key_options.as_ref() { - if new != old { - return Err(crate::wallet::Error::PublicKeyOptionsMismatch { - new: serde_json::to_value(new)?, - old: serde_json::to_value(old)?, - }); - } - } else { - self.public_key_options = Some(old.clone()); + if self.public_key_options.as_ref() != Some(old) { + return Err(crate::wallet::Error::PublicKeyOptionsMismatch { + new: serde_json::to_value(self.public_key_options.as_ref())?, + old: serde_json::to_value(old)?, + }); } } @@ -235,7 +328,7 @@ where self.save(&storage_manager).await?; #[cfg(feature = "events")] - let event_emitter = tokio::sync::RwLock::new(EventEmitter::new()); + let event_emitter = Arc::new(tokio::sync::RwLock::new(EventEmitter::new())); // It happened that inputs got locked, the transaction failed, but they weren't unlocked again, so we do this // here @@ -252,27 +345,17 @@ where .finish() .await?; - // Build the wallet. - let wallet_inner = WalletInner { - default_sync_options: Mutex::new(SyncOptions::default()), - last_synced: Mutex::new(0), - background_syncing_status: AtomicUsize::new(0), - client, - secret_manager: self.secret_manager.expect("make WalletInner::secret_manager optional?"), - #[cfg(feature = "events")] - event_emitter, - #[cfg(feature = "storage")] - storage_options, - #[cfg(feature = "storage")] - storage_manager: tokio::sync::RwLock::new(storage_manager), - }; #[cfg(feature = "storage")] let wallet_data = match wallet_data { Some(d) => d, - None => WalletData::new( - self.public_key_options + None => OnlineWalletData::new( + self.inner + .public_key_options + .take() .ok_or(crate::wallet::Error::MissingParameter("public_key_options"))?, - self.signing_options + self.inner + .signing_options + .take() .ok_or(crate::wallet::Error::MissingParameter("signing_options"))?, address, self.alias.clone(), @@ -280,9 +363,27 @@ where }; #[cfg(not(feature = "storage"))] let wallet_data = WalletData::new(self.bip_path, address, self.alias.clone()); + + // Build the wallet. let wallet = Wallet { - inner: Arc::new(wallet_inner), - data: Arc::new(RwLock::new(wallet_data)), + inner: Online { + #[cfg(feature = "storage")] + storage: Arc::new(WalletStorageOptions { + options: storage_options, + manager: tokio::sync::RwLock::new(storage_manager), + }), + default_sync_options: Arc::new(Mutex::new(SyncOptions::default())), + last_synced: Arc::new(Mutex::new(0)), + background_syncing_status: Arc::new(AtomicUsize::new(0)), + client, + secret_manager: self + .inner + .secret_manager + .expect("make WalletInner::secret_manager optional?"), + #[cfg(feature = "events")] + event_emitter, + data: Arc::new(tokio::sync::RwLock::new(wallet_data)), + }, }; // If the wallet builder is not set, it means the user provided it and we need to update the addresses. @@ -317,29 +418,58 @@ where ) .to_bech32(bech32_hrp)) } +} +impl WalletBuilder { #[cfg(feature = "storage")] - pub(crate) async fn from_wallet(wallet: &Wallet) -> Self + pub(crate) async fn from_wallet(wallet: &Wallet) -> Self where - S::GenerationOptions: Clone, - S::SigningOptions: Clone, + Self: FromRefAsync>, { + FromRefAsync::>::from(wallet).await + } +} + +#[async_trait] +pub trait FromRefAsync { + async fn from(value: &T) -> Self; +} + +#[async_trait] +impl + Send> FromRefAsync> for WalletBuilder { + async fn from(wallet: &Wallet) -> Self { Self { - public_key_options: Some(wallet.data().await.public_key_options.clone()), - signing_options: Some(wallet.data().await.signing_options.clone()), + inner: T2::from(&wallet.inner).await, address: Some(wallet.address().await), alias: wallet.alias().await, - client_options: Some(wallet.client_options().await), - storage_options: Some(wallet.storage_options.clone()), - secret_manager: Some(wallet.secret_manager.clone()), + storage_options: Some(wallet.storage_options().clone()), + } + } +} + +#[async_trait] +impl FromRefAsync> for OnlineBuilder { + async fn from(value: &Online) -> Self { + Self { + public_key_options: Some(value.data().await.public_key_options.clone()), + signing_options: Some(value.data().await.signing_options.clone()), + client_options: Some(value.client_options().await), + secret_manager: Some(value.secret_manager.clone()), } } } +#[async_trait] +impl FromRefAsync for OfflineBuilder { + async fn from(_: &Offline) -> Self { + Self + } +} + // Check if any of the locked inputs is not used in a transaction and unlock them, so they get available for new // transactions #[cfg(feature = "storage")] -fn unlock_unused_inputs(wallet_data: &mut WalletData) -> crate::wallet::Result<()> { +fn unlock_unused_inputs(wallet_data: &mut OnlineWalletData) -> crate::wallet::Result<()> { log::debug!("[unlock_unused_inputs]"); let mut used_inputs = HashSet::new(); for transaction_id in &wallet_data.pending_transactions { @@ -367,40 +497,65 @@ pub(crate) mod dto { #[cfg(feature = "storage")] use crate::{client::secret::SecretManage, wallet::storage::StorageOptions}; + #[derive(Debug, Deserialize)] + pub struct WalletBuilderDto { + #[serde(flatten)] + pub(crate) inner: T, + } + + impl core::ops::Deref for WalletBuilderDto { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.inner + } + } + #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] - pub struct WalletBuilderDto { + pub struct OnlineDto { + #[serde(flatten)] + pub(crate) inner: OfflineDto, #[serde(default = "Option::default", skip_serializing_if = "Option::is_none")] pub(crate) public_key_options: Option, #[serde(default = "Option::default", skip_serializing_if = "Option::is_none")] pub(crate) signing_options: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub(crate) client_options: Option, + } + + #[derive(Debug, Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct OfflineDto { #[serde(default, skip_serializing_if = "Option::is_none")] pub(crate) address: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub(crate) alias: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub(crate) client_options: Option, #[cfg(feature = "storage")] #[serde(default, skip_serializing_if = "Option::is_none")] pub(crate) storage_options: Option, } - impl From> for WalletBuilder { - fn from(value: WalletBuilderDto) -> Self { + impl From>> + for WalletBuilder> + { + fn from(value: WalletBuilderDto>) -> Self { Self { - public_key_options: value.public_key_options, - signing_options: value.signing_options, - address: value.address, - alias: value.alias, - client_options: value.client_options, + inner: OnlineBuilder { + public_key_options: value.inner.public_key_options, + signing_options: value.inner.signing_options, + client_options: value.inner.client_options, + secret_manager: None, + }, + address: value.inner.inner.address, + alias: value.inner.inner.alias, #[cfg(feature = "storage")] - storage_options: value.storage_options, - secret_manager: None, + storage_options: value.inner.inner.storage_options, } } } - impl<'de, S: SecretManage> Deserialize<'de> for WalletBuilder + impl<'de, S: SecretManage> Deserialize<'de> for WalletBuilder> where S::GenerationOptions: Deserialize<'de>, S::SigningOptions: Deserialize<'de>, @@ -409,7 +564,28 @@ pub(crate) mod dto { where D: serde::Deserializer<'de>, { - WalletBuilderDto::::deserialize(d).map(Into::into) + WalletBuilderDto::>::deserialize(d).map(Into::into) + } + } + + impl From> for WalletBuilder { + fn from(value: WalletBuilderDto) -> Self { + Self { + inner: OfflineBuilder, + address: value.inner.address, + alias: value.inner.alias, + #[cfg(feature = "storage")] + storage_options: value.inner.storage_options, + } + } + } + + impl<'de> Deserialize<'de> for WalletBuilder { + fn deserialize(d: D) -> Result + where + D: serde::Deserializer<'de>, + { + WalletBuilderDto::::deserialize(d).map(Into::into) } } } diff --git a/sdk/src/wallet/core/mod.rs b/sdk/src/wallet/core/mod.rs index 90b015acd2..93b754d112 100644 --- a/sdk/src/wallet/core/mod.rs +++ b/sdk/src/wallet/core/mod.rs @@ -9,9 +9,10 @@ use std::{ sync::{atomic::AtomicUsize, Arc}, }; +use async_trait::async_trait; use crypto::keys::bip39::{Mnemonic, MnemonicRef}; use serde::{Deserialize, Serialize}; -use tokio::sync::{Mutex, RwLock}; +use tokio::sync::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; pub use self::builder::WalletBuilder; use super::types::{TransactionWithMetadata, TransactionWithMetadataDto}; @@ -23,10 +24,7 @@ use crate::wallet::events::{ #[cfg(feature = "storage")] use crate::wallet::storage::{StorageManager, StorageOptions}; use crate::{ - client::{ - secret::{SecretManage, SecretManager}, - verify_mnemonic, Client, - }, + client::{secret::SecretManage, verify_mnemonic, Client}, types::{ block::{ address::{Address, Bech32Address, Hrp, ImplicitAccountCreationAddress}, @@ -36,70 +34,147 @@ use crate::{ }, TryFromDto, }, - wallet::{operations::syncing::SyncOptions, types::OutputData, Error, FilterOptions, Result}, + wallet::{ + core::builder::OnlineBuilder, operations::syncing::SyncOptions, types::OutputData, Error, FilterOptions, Result, + }, }; /// The stateful wallet used to interact with an IOTA network. -#[derive(Debug)] -pub struct Wallet { - pub(crate) inner: Arc>, - pub(crate) data: Arc>>, +#[derive(Debug, Clone)] +pub struct Wallet { + inner: T, } -impl Clone for Wallet { - fn clone(&self) -> Self { - Self { - inner: self.inner.clone(), - data: self.data.clone(), - } +impl core::ops::Deref for Wallet { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.inner } } -impl core::ops::Deref for Wallet { - type Target = WalletInner; +#[async_trait] +pub trait WalletCommon { + async fn alias(&self) -> Option; - fn deref(&self) -> &Self::Target { - &self.inner + async fn address(&self) -> Bech32Address; + + fn storage_options(&self) -> &StorageOptions; +} + +#[async_trait] +impl WalletCommon for Online { + async fn alias(&self) -> Option { + self.data().await.alias.clone() + } + + async fn address(&self) -> Bech32Address { + self.data().await.address.clone() + } + + fn storage_options(&self) -> &StorageOptions { + &self.storage.options } } -impl Wallet { - /// Initialises the wallet builder. - pub fn builder() -> WalletBuilder { - WalletBuilder::::new() +#[async_trait] +impl WalletCommon for Offline { + async fn alias(&self) -> Option { + self.data().await.alias.clone() + } + + async fn address(&self) -> Bech32Address { + self.data().await.address.clone() + } + + fn storage_options(&self) -> &StorageOptions { + &self.storage.options } } -/// Wallet inner. #[derive(Debug)] -pub struct WalletInner { +pub struct Online { + #[cfg(feature = "storage")] + pub(crate) storage: Arc, + pub(crate) data: Arc>>, + #[cfg(feature = "events")] + pub(crate) event_emitter: Arc>>, + pub(crate) client: Client, + pub(crate) secret_manager: Arc>, // mutex to prevent multiple sync calls at the same or almost the same time, the u128 is a timestamp // if the last synced time was < `MIN_SYNC_INTERVAL` second ago, we don't sync, but only calculate the balance // again, because sending transactions can change that - pub(crate) last_synced: Mutex, - pub(crate) default_sync_options: Mutex, + pub(crate) last_synced: Arc>, + pub(crate) default_sync_options: Arc>, // 0 = not running, 1 = running, 2 = stopping - pub(crate) background_syncing_status: AtomicUsize, - pub(crate) client: Client, - pub(crate) secret_manager: Arc>, - #[cfg(feature = "events")] - pub(crate) event_emitter: tokio::sync::RwLock>, + pub(crate) background_syncing_status: Arc, +} + +impl Online { + pub async fn data(&self) -> RwLockReadGuard<'_, OnlineWalletData> { + self.data.read().await + } + + pub async fn data_mut(&self) -> RwLockWriteGuard<'_, OnlineWalletData> { + self.data.write().await + } +} + +#[derive(Clone, Debug)] +pub struct Offline { #[cfg(feature = "storage")] - pub(crate) storage_options: StorageOptions, + pub(crate) storage: Arc, + pub(crate) data: Arc>, +} + +impl Offline { + pub async fn data(&self) -> RwLockReadGuard<'_, OfflineWalletData> { + self.data.read().await + } + + pub async fn data_mut(&self) -> RwLockWriteGuard<'_, OfflineWalletData> { + self.data.write().await + } +} + +impl Clone for Online { + fn clone(&self) -> Self { + Self { + storage: self.storage.clone(), + data: self.data.clone(), + event_emitter: self.event_emitter.clone(), + client: self.client.clone(), + secret_manager: self.secret_manager.clone(), + last_synced: self.last_synced.clone(), + default_sync_options: self.default_sync_options.clone(), + background_syncing_status: self.background_syncing_status.clone(), + } + } +} + +impl Wallet { + /// Initialises the wallet builder. + pub fn builder() -> WalletBuilder { + WalletBuilder::new() + } +} + +/// Wallet inner. +#[derive(Debug)] +pub struct WalletStorageOptions { #[cfg(feature = "storage")] - pub(crate) storage_manager: tokio::sync::RwLock, + pub(crate) options: StorageOptions, + #[cfg(feature = "storage")] + pub(crate) manager: tokio::sync::RwLock, } /// Wallet data. -pub struct WalletData { +pub struct OnlineWalletData { + pub(crate) inner: OfflineWalletData, /// The public key generation options. pub(crate) public_key_options: S::GenerationOptions, /// The signing options for transactions and blocks. pub(crate) signing_options: S::SigningOptions, - /// The wallet address. - pub(crate) address: Bech32Address, - /// The wallet alias. - pub(crate) alias: Option, /// Outputs // stored separated from the wallet for performance? pub(crate) outputs: HashMap>, @@ -128,7 +203,23 @@ pub struct WalletData { pub(crate) native_token_foundries: HashMap, } -impl WalletData { +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct OfflineWalletData { + /// The wallet alias. + pub(crate) alias: Option, + /// The wallet address. + pub(crate) address: Bech32Address, +} + +impl core::ops::Deref for OnlineWalletData { + type Target = OfflineWalletData; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl OnlineWalletData { pub(crate) fn new( public_key_options: S::GenerationOptions, signing_options: S::SigningOptions, @@ -136,10 +227,9 @@ impl WalletData { alias: Option, ) -> Self { Self { + inner: OfflineWalletData { alias, address }, public_key_options, signing_options, - address, - alias, outputs: HashMap::new(), locked_outputs: HashSet::new(), unspent_outputs: HashMap::new(), @@ -357,7 +447,7 @@ impl WalletData { } } -impl PartialEq for WalletData { +impl PartialEq for OnlineWalletData { fn eq(&self, other: &Self) -> bool { self.public_key_options == other.public_key_options && self.signing_options == other.signing_options @@ -373,8 +463,8 @@ impl PartialEq for WalletData { && self.native_token_foundries == other.native_token_foundries } } -impl Eq for WalletData {} -impl core::fmt::Debug for WalletData { +impl Eq for OnlineWalletData {} +impl core::fmt::Debug for OnlineWalletData { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("WalletData") .field("public_key_options", &self.public_key_options) @@ -395,13 +485,12 @@ impl core::fmt::Debug for WalletData { .finish() } } -impl Clone for WalletData { +impl Clone for OnlineWalletData { fn clone(&self) -> Self { Self { public_key_options: self.public_key_options.clone(), signing_options: self.signing_options.clone(), - address: self.address.clone(), - alias: self.alias.clone(), + inner: self.inner.clone(), outputs: self.outputs.clone(), locked_outputs: self.locked_outputs.clone(), unspent_outputs: self.unspent_outputs.clone(), @@ -414,12 +503,42 @@ impl Clone for WalletData { } } -impl Wallet { - /// Create a new wallet. - pub(crate) async fn new(inner: Arc>, data: WalletData) -> Result { +impl Wallet { + /// Create a new offline wallet. + pub(crate) async fn new(inner: Offline) -> Result { + Ok(Self { inner }) + } + + /// Save the wallet to the database, accepts the updated wallet data as option so we don't need to drop it before + /// saving + #[cfg(feature = "storage")] + pub(crate) async fn save(&self, updated_wallet: Option<&OfflineWalletData>) -> Result<()> { + log::debug!("[save] wallet data"); + match updated_wallet { + Some(wallet) => { + let mut storage_manager = self.storage.manager.write().await; + storage_manager.save_wallet_data(wallet).await?; + drop(storage_manager); + } + None => { + let wallet_data = self.data().await; + let mut storage_manager = self.storage.manager.write().await; + storage_manager.save_wallet_data(&*wallet_data).await?; + drop(storage_manager); + drop(wallet_data); + } + } + Ok(()) + } +} + +impl Wallet> { + /// Create a new online wallet. + pub(crate) async fn new(inner: Online) -> Result { #[cfg(feature = "storage")] let default_sync_options = inner - .storage_manager + .storage + .manager .read() .await .get_default_sync_options() @@ -436,10 +555,7 @@ impl Wallet { *sync_options = default_sync_options; } - Ok(Self { - inner, - data: Arc::new(RwLock::new(data)), - }) + Ok(Self { inner }) } /// Get the [`Output`] that minted a native token by the token ID. First try to get it @@ -465,18 +581,18 @@ impl Wallet { /// Save the wallet to the database, accepts the updated wallet data as option so we don't need to drop it before /// saving #[cfg(feature = "storage")] - pub(crate) async fn save(&self, updated_wallet: Option<&WalletData>) -> Result<()> { + pub(crate) async fn save(&self, updated_wallet: Option<&OnlineWalletData>) -> Result<()> { log::debug!("[save] wallet data"); match updated_wallet { Some(wallet) => { - let mut storage_manager = self.storage_manager.write().await; + let mut storage_manager = self.storage.manager.write().await; storage_manager.save_wallet_data(wallet).await?; drop(storage_manager); } None => { - let wallet_data = self.data.read().await; - let mut storage_manager = self.storage_manager.write().await; - storage_manager.save_wallet_data(&wallet_data).await?; + let wallet_data = self.data().await; + let mut storage_manager = self.storage.manager.write().await; + storage_manager.save_wallet_data(&*wallet_data).await?; drop(storage_manager); drop(wallet_data); } @@ -489,14 +605,6 @@ impl Wallet { self.inner.emit(wallet_event).await } - pub async fn data(&self) -> tokio::sync::RwLockReadGuard<'_, WalletData> { - self.data.read().await - } - - pub(crate) async fn data_mut(&self) -> tokio::sync::RwLockWriteGuard<'_, WalletData> { - self.data.write().await - } - /// Get the alias of the wallet if one was set. pub async fn alias(&self) -> Option { self.data().await.alias.clone() @@ -527,7 +635,7 @@ impl Wallet { } } -impl WalletInner { +impl Online { /// Get the [SecretManager] pub fn get_secret_manager(&self) -> &Arc> { &self.secret_manager @@ -580,16 +688,10 @@ impl WalletInner { } } -impl Drop for Wallet { - fn drop(&mut self) { - log::debug!("drop Wallet"); - } -} - /// Dto for the wallet data. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct WalletDataDto { +pub struct OnlineWalletDataDto { pub public_key_options: G, pub signing_options: S, pub address: Bech32Address, @@ -604,18 +706,20 @@ pub struct WalletDataDto { pub native_token_foundries: HashMap, } -impl TryFromDto> for WalletData { +impl TryFromDto> for OnlineWalletData { type Error = crate::wallet::Error; fn try_from_dto_with_params_inner( - dto: WalletDataDto, + dto: OnlineWalletDataDto, params: Option<&ProtocolParameters>, ) -> core::result::Result { Ok(Self { + inner: OfflineWalletData { + alias: dto.alias, + address: dto.address, + }, public_key_options: dto.public_key_options, signing_options: dto.signing_options, - address: dto.address, - alias: dto.alias, outputs: dto.outputs, locked_outputs: dto.locked_outputs, unspent_outputs: dto.unspent_outputs, @@ -636,12 +740,12 @@ impl TryFromDto From<&WalletData> for WalletDataDto +impl From<&OnlineWalletData> for OnlineWalletDataDto where S::GenerationOptions: Clone, S::SigningOptions: Clone, { - fn from(value: &WalletData) -> Self { + fn from(value: &OnlineWalletData) -> Self { Self { public_key_options: value.public_key_options.clone(), signing_options: value.signing_options.clone(), @@ -666,6 +770,37 @@ where } } +/// Dto for the wallet data. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct OfflineWalletDataDto { + pub address: Bech32Address, + pub alias: Option, +} + +impl TryFromDto for OfflineWalletData { + type Error = crate::wallet::Error; + + fn try_from_dto_with_params_inner( + dto: OfflineWalletDataDto, + params: Option<&ProtocolParameters>, + ) -> core::result::Result { + Ok(Self { + alias: dto.alias, + address: dto.address, + }) + } +} + +impl From<&OfflineWalletData> for OfflineWalletDataDto { + fn from(value: &OfflineWalletData) -> Self { + Self { + address: value.address.clone(), + alias: value.alias.clone(), + } + } +} + #[cfg(test)] mod test { use core::str::FromStr; @@ -758,14 +893,16 @@ mod test { incoming_transaction, ); - let wallet_data = WalletData { + let wallet_data = OnlineWalletData { + inner: OfflineWalletData { + address: crate::types::block::address::Bech32Address::from_str( + "rms1qpllaj0pyveqfkwxmnngz2c488hfdtmfrj3wfkgxtk4gtyrax0jaxzt70zy", + ) + .unwrap(), + alias: Some("Alice".to_string()), + }, public_key_options: PublicKeyOptions::new(4218), signing_options: Bip44::new(4218), - address: crate::types::block::address::Bech32Address::from_str( - "rms1qpllaj0pyveqfkwxmnngz2c488hfdtmfrj3wfkgxtk4gtyrax0jaxzt70zy", - ) - .unwrap(), - alias: Some("Alice".to_string()), outputs: HashMap::new(), locked_outputs: HashSet::new(), unspent_outputs: HashMap::new(), @@ -776,9 +913,9 @@ mod test { native_token_foundries: HashMap::new(), }; - let deser_wallet_data = WalletData::::try_from_dto( - serde_json::from_str::>( - &serde_json::to_string(&WalletDataDto::from(&wallet_data)).unwrap(), + let deser_wallet_data = OnlineWalletData::::try_from_dto( + serde_json::from_str::>( + &serde_json::to_string(&OnlineWalletDataDto::from(&wallet_data)).unwrap(), ) .unwrap(), ) @@ -787,7 +924,7 @@ mod test { assert_eq!(wallet_data, deser_wallet_data); } - impl> WalletData { + impl> OnlineWalletData { /// Returns a mock of this type with the following values: /// index: 0, coin_type: 4218, alias: "Alice", address: /// rms1qpllaj0pyveqfkwxmnngz2c488hfdtmfrj3wfkgxtk4gtyrax0jaxzt70zy, all other fields are set to their Rust @@ -795,13 +932,15 @@ mod test { #[cfg(feature = "storage")] pub(crate) fn mock() -> Self { Self { + inner: OfflineWalletData { + address: crate::types::block::address::Bech32Address::from_str( + "rms1qpllaj0pyveqfkwxmnngz2c488hfdtmfrj3wfkgxtk4gtyrax0jaxzt70zy", + ) + .unwrap(), + alias: Some("Alice".to_string()), + }, public_key_options: PublicKeyOptions::new(4218), signing_options: Bip44::new(4218), - address: crate::types::block::address::Bech32Address::from_str( - "rms1qpllaj0pyveqfkwxmnngz2c488hfdtmfrj3wfkgxtk4gtyrax0jaxzt70zy", - ) - .unwrap(), - alias: Some("Alice".to_string()), outputs: HashMap::new(), locked_outputs: HashSet::new(), unspent_outputs: HashMap::new(), diff --git a/sdk/src/wallet/core/operations/address_generation.rs b/sdk/src/wallet/core/operations/address_generation.rs index 1e237f318f..be9889dd04 100644 --- a/sdk/src/wallet/core/operations/address_generation.rs +++ b/sdk/src/wallet/core/operations/address_generation.rs @@ -12,7 +12,7 @@ // wallet::events::types::{AddressData, WalletEvent}, // }; -// impl Wallet { +// impl Wallet> { // /// Generate an address without storing it // /// ```ignore // /// let public_addresses = wallet diff --git a/sdk/src/wallet/core/operations/background_syncing.rs b/sdk/src/wallet/core/operations/background_syncing.rs index fb1dcc7c66..e9adcb5c9d 100644 --- a/sdk/src/wallet/core/operations/background_syncing.rs +++ b/sdk/src/wallet/core/operations/background_syncing.rs @@ -7,13 +7,13 @@ use tokio::time::sleep; use crate::{ client::secret::SecretManage, - wallet::{operations::syncing::SyncOptions, Wallet}, + wallet::{core::Online, operations::syncing::SyncOptions, Wallet}, }; /// The default interval for background syncing pub(crate) const DEFAULT_BACKGROUNDSYNCING_INTERVAL: Duration = Duration::from_secs(7); -impl Wallet { +impl Wallet> { /// Start the background syncing process for the wallet, default interval is 7 seconds pub async fn start_background_syncing( &self, diff --git a/sdk/src/wallet/core/operations/client.rs b/sdk/src/wallet/core/operations/client.rs index e193b774fa..6a19a4c870 100644 --- a/sdk/src/wallet/core/operations/client.rs +++ b/sdk/src/wallet/core/operations/client.rs @@ -14,10 +14,13 @@ use crate::{ secret::{SecretManage, SecretManagerConfig}, Client, ClientBuilder, }, - wallet::{Wallet, WalletBuilder}, + wallet::{ + core::{builder::OnlineBuilder, Online}, + Wallet, WalletBuilder, + }, }; -impl Wallet { +impl Online { pub fn client(&self) -> &Client { &self.client } @@ -27,7 +30,7 @@ impl Wallet { } } -impl Wallet { +impl Wallet> { pub async fn set_client_options(&self, client_options: ClientBuilder) -> crate::wallet::Result<()> { let ClientBuilder { node_manager_builder, @@ -66,9 +69,9 @@ impl Wallet { #[cfg(feature = "storage")] { - WalletBuilder::from_wallet(self) + WalletBuilder::>::from_wallet(self) .await - .save(&*self.storage_manager.read().await) + .save(&*self.storage.manager.read().await) .await?; } Ok(()) @@ -136,9 +139,9 @@ impl Wallet { #[cfg(feature = "storage")] { - WalletBuilder::from_wallet(self) + WalletBuilder::>::from_wallet(self) .await - .save(&*self.storage_manager.read().await) + .save(&*self.storage.manager.read().await) .await?; } diff --git a/sdk/src/wallet/core/operations/storage.rs b/sdk/src/wallet/core/operations/storage.rs index dad5e85b7f..6ab0826ef9 100644 --- a/sdk/src/wallet/core/operations/storage.rs +++ b/sdk/src/wallet/core/operations/storage.rs @@ -4,13 +4,16 @@ use crate::{ client::{secret::SecretManagerConfig, storage::StorageAdapter}, wallet::{ - core::builder::dto::WalletBuilderDto, + core::builder::{ + dto::{OfflineDto, OnlineDto, WalletBuilderDto}, + OfflineBuilder, OnlineBuilder, + }, storage::constants::{SECRET_MANAGER_KEY, WALLET_BUILDER_KEY}, WalletBuilder, }, }; -impl WalletBuilder { +impl WalletBuilder> { pub(crate) async fn save( &self, storage: &impl StorageAdapter, @@ -33,7 +36,7 @@ impl WalletBuilder { ) -> crate::wallet::Result> { log::debug!("[load] wallet builder"); if let Some(wallet_builder_dto) = storage - .get::>(WALLET_BUILDER_KEY) + .get::>>(WALLET_BUILDER_KEY) .await? { log::debug!("[load] wallet builder dto: {wallet_builder_dto:?}"); @@ -49,3 +52,27 @@ impl WalletBuilder { } } } + +impl WalletBuilder { + pub(crate) async fn save( + &self, + storage: &impl StorageAdapter, + ) -> crate::wallet::Result<()> { + log::debug!("[save] wallet builder"); + storage.set(WALLET_BUILDER_KEY, self).await?; + Ok(()) + } + + pub(crate) async fn load( + storage: &impl StorageAdapter, + ) -> crate::wallet::Result> { + log::debug!("[load] wallet builder"); + if let Some(wallet_builder_dto) = storage.get::>(WALLET_BUILDER_KEY).await? { + log::debug!("[load] wallet builder dto: {wallet_builder_dto:?}"); + + Ok(Some(Self::from(wallet_builder_dto))) + } else { + Ok(None) + } + } +} diff --git a/sdk/src/wallet/core/operations/stronghold.rs b/sdk/src/wallet/core/operations/stronghold.rs index 79dd195669..3d1b153b1b 100644 --- a/sdk/src/wallet/core/operations/stronghold.rs +++ b/sdk/src/wallet/core/operations/stronghold.rs @@ -7,11 +7,11 @@ use crypto::keys::bip39::Mnemonic; use crate::{ client::{secret::SecretManager, stronghold::StrongholdAdapter, utils::Password}, - wallet::Wallet, + wallet::{core::Online, Wallet}, }; // TODO: Remove these and just use the secret manager directly -impl Wallet { +impl Wallet> { /// Sets the Stronghold password pub async fn set_stronghold_password(&self, password: impl Into + Send) -> crate::wallet::Result<()> { let password = password.into(); @@ -84,7 +84,7 @@ impl Wallet { } } -impl Wallet { +impl Wallet> { /// Sets the Stronghold password pub async fn set_stronghold_password(&self, password: impl Into + Send) -> crate::wallet::Result<()> { Ok(self.secret_manager.write().await.set_password(password).await?) diff --git a/sdk/src/wallet/core/operations/stronghold_backup/mod.rs b/sdk/src/wallet/core/operations/stronghold_backup/mod.rs index 523935e45c..80874b9e81 100644 --- a/sdk/src/wallet/core/operations/stronghold_backup/mod.rs +++ b/sdk/src/wallet/core/operations/stronghold_backup/mod.rs @@ -14,10 +14,10 @@ use crate::{ utils::Password, }, types::block::address::Hrp, - wallet::Wallet, + wallet::{core::Online, Wallet}, }; -impl Wallet { +impl Wallet> { /// Backup the wallet data in a Stronghold file /// stronghold_password must be the current one when Stronghold is used as SecretManager. pub async fn backup( @@ -166,7 +166,8 @@ impl Wallet { .with_secret_manager_arc(self.secret_manager.clone()) .with_storage_path( &self - .storage_options + .storage + .options .path .clone() .into_os_string() @@ -177,7 +178,7 @@ impl Wallet { .with_public_key_options(self.data().await.public_key_options.clone()) .with_signing_options(self.data().await.signing_options.clone()); - wallet_builder.save(&*self.storage_manager.read().await).await?; + wallet_builder.save(&*self.storage.manager.read().await).await?; // also save wallet data to db self.save(Some(&wallet_data)).await?; diff --git a/sdk/src/wallet/core/operations/stronghold_backup/stronghold_snapshot.rs b/sdk/src/wallet/core/operations/stronghold_backup/stronghold_snapshot.rs index ad9cd80d48..58bcd06aad 100644 --- a/sdk/src/wallet/core/operations/stronghold_backup/stronghold_snapshot.rs +++ b/sdk/src/wallet/core/operations/stronghold_backup/stronghold_snapshot.rs @@ -5,7 +5,7 @@ use crate::{ client::{secret::SecretManagerConfig, storage::StorageAdapter, stronghold::StrongholdAdapter}, types::TryFromDto, wallet::{ - core::{WalletData, WalletDataDto}, + core::{Online, OnlineWalletData, OnlineWalletDataDto}, migration::{latest_backup_migration_version, migrate, MIGRATION_VERSION_KEY}, ClientOptions, Wallet, }, @@ -15,7 +15,7 @@ pub(crate) const CLIENT_OPTIONS_KEY: &str = "client_options"; pub(crate) const SECRET_MANAGER_KEY: &str = "secret_manager"; pub(crate) const WALLET_DATA_KEY: &str = "wallet_data"; -impl Wallet { +impl Wallet> { pub(crate) async fn store_data_to_stronghold(&self, stronghold: &StrongholdAdapter) -> crate::wallet::Result<()> { // Set migration version stronghold @@ -29,7 +29,7 @@ impl Wallet { stronghold.set(SECRET_MANAGER_KEY, &secret_manager_dto).await?; } - let serialized_wallet_data = serde_json::to_value(&WalletDataDto::from(&*self.data.read().await))?; + let serialized_wallet_data = serde_json::to_value(&OnlineWalletDataDto::from(&*self.data.read().await))?; stronghold.set(WALLET_DATA_KEY, &serialized_wallet_data).await?; Ok(()) @@ -38,7 +38,7 @@ impl Wallet { pub(crate) async fn read_wallet_data_from_stronghold_snapshot( stronghold: &StrongholdAdapter, -) -> crate::wallet::Result<(Option, Option, Option>)> { +) -> crate::wallet::Result<(Option, Option, Option>)> { migrate(stronghold).await?; // Get client_options @@ -64,9 +64,9 @@ pub(crate) async fn read_wallet_data_from_stronghold_snapshot>(WALLET_DATA_KEY) + .get::>(WALLET_DATA_KEY) .await? - .map(WalletData::try_from_dto) + .map(OnlineWalletData::try_from_dto) .transpose()?; Ok((client_options, restored_secret_manager, restored_wallet_data)) diff --git a/sdk/src/wallet/operations/balance.rs b/sdk/src/wallet/operations/balance.rs index b269acce17..76156ac707 100644 --- a/sdk/src/wallet/operations/balance.rs +++ b/sdk/src/wallet/operations/balance.rs @@ -9,14 +9,14 @@ use crate::{ unlock_condition::UnlockCondition, FoundryId, MinimumOutputAmount, NativeTokensBuilder, Output, }, wallet::{ - core::WalletData, + core::{Online, OnlineWalletData}, operations::{helpers::time::can_output_be_unlocked_forever_from_now_on, output_claiming::OutputsToClaim}, types::{Balance, NativeTokensBalance}, Result, Wallet, }, }; -impl Wallet { +impl Wallet> { /// Get the balance of the wallet. pub async fn balance(&self) -> Result { log::debug!("[BALANCE] balance"); @@ -29,7 +29,7 @@ impl Wallet { async fn balance_inner( &self, // addresses_with_unspent_outputs: impl Iterator + Send, - wallet_data: &WalletData, + wallet_data: &OnlineWalletData, ) -> Result { let network_id = self.client().get_network_id().await?; let storage_score_params = self.client().get_storage_score_parameters().await?; @@ -248,7 +248,7 @@ impl Wallet { fn finish( &self, mut balance: Balance, - wallet_data: &WalletData, + wallet_data: &OnlineWalletData, network_id: u64, total_storage_cost: u64, total_native_tokens: NativeTokensBuilder, diff --git a/sdk/src/wallet/operations/block.rs b/sdk/src/wallet/operations/block.rs index d0962b9e50..f510013fab 100644 --- a/sdk/src/wallet/operations/block.rs +++ b/sdk/src/wallet/operations/block.rs @@ -4,10 +4,10 @@ use crate::{ client::secret::{BlockSignExt, SecretManage}, types::block::{output::AccountId, payload::Payload, BlockId}, - wallet::{Result, Wallet}, + wallet::{core::Online, Result, Wallet}, }; -impl Wallet { +impl Wallet> { pub(crate) async fn submit_basic_block( &self, payload: Option, diff --git a/sdk/src/wallet/operations/output_claiming.rs b/sdk/src/wallet/operations/output_claiming.rs index 819f4ee999..f23a3ebbbd 100644 --- a/sdk/src/wallet/operations/output_claiming.rs +++ b/sdk/src/wallet/operations/output_claiming.rs @@ -19,7 +19,7 @@ use crate::{ slot::SlotIndex, }, wallet::{ - core::WalletData, + core::{Online, OnlineWalletData}, operations::{helpers::time::can_output_be_unlocked_now, transaction::TransactionOptions}, types::{OutputData, TransactionWithMetadata}, Wallet, @@ -37,7 +37,7 @@ pub enum OutputsToClaim { All, } -impl WalletData { +impl OnlineWalletData { /// Get basic and nft outputs that have /// [`ExpirationUnlockCondition`](crate::types::block::output::unlock_condition::ExpirationUnlockCondition), /// [`StorageDepositReturnUnlockCondition`] or @@ -125,7 +125,7 @@ impl WalletData { } } -impl Wallet { +impl Wallet> { /// Get basic and nft outputs that have /// [`ExpirationUnlockCondition`](crate::types::block::output::unlock_condition::ExpirationUnlockCondition), /// [`StorageDepositReturnUnlockCondition`] or diff --git a/sdk/src/wallet/operations/output_consolidation.rs b/sdk/src/wallet/operations/output_consolidation.rs index a671ddcde9..d9ec0c9ff4 100644 --- a/sdk/src/wallet/operations/output_consolidation.rs +++ b/sdk/src/wallet/operations/output_consolidation.rs @@ -15,6 +15,7 @@ use crate::{ }, wallet::{ constants::DEFAULT_OUTPUT_CONSOLIDATION_THRESHOLD, + core::Online, operations::{helpers::time::can_output_be_unlocked_now, transaction::TransactionOptions}, types::{OutputData, TransactionWithMetadata}, Result, Wallet, @@ -65,7 +66,7 @@ impl ConsolidationParams { } } -impl Wallet { +impl Wallet> { fn should_consolidate_output( &self, output_data: &OutputData, diff --git a/sdk/src/wallet/operations/participation/event.rs b/sdk/src/wallet/operations/participation/event.rs index 6bea5f81cf..781e94babc 100644 --- a/sdk/src/wallet/operations/participation/event.rs +++ b/sdk/src/wallet/operations/participation/event.rs @@ -9,12 +9,12 @@ use crate::{ ParticipationEventId, ParticipationEventStatus, ParticipationEventType, }, wallet::{ - operations::participation::ParticipationEventWithNodes, + core::Online, operations::participation::ParticipationEventWithNodes, types::participation::ParticipationEventRegistrationOptions, Wallet, }, }; -impl Wallet { +impl Wallet> { /// Stores participation information for the given events locally and returns them all. /// /// This will NOT store the node url and auth inside the client options. @@ -57,7 +57,8 @@ impl Wallet { data: event_data, nodes: vec![options.node.clone()], }; - self.storage_manager + self.storage + .manager .read() .await .insert_participation_event(event_with_node.clone()) @@ -70,7 +71,7 @@ impl Wallet { /// Removes a previously registered participation event from local storage. pub async fn deregister_participation_event(&self, id: &ParticipationEventId) -> crate::wallet::Result<()> { - self.storage_manager.read().await.remove_participation_event(id).await?; + self.storage.manager.read().await.remove_participation_event(id).await?; Ok(()) } @@ -80,7 +81,8 @@ impl Wallet { id: ParticipationEventId, ) -> crate::wallet::Result> { Ok(self - .storage_manager + .storage + .manager .read() .await .get_participation_events() @@ -93,7 +95,7 @@ impl Wallet { pub async fn get_participation_events( &self, ) -> crate::wallet::Result> { - self.storage_manager.read().await.get_participation_events().await + self.storage.manager.read().await.get_participation_events().await } /// Retrieves IDs of all events tracked by the client options node. diff --git a/sdk/src/wallet/operations/participation/mod.rs b/sdk/src/wallet/operations/participation/mod.rs index 8d31b45800..bfc06375d2 100644 --- a/sdk/src/wallet/operations/participation/mod.rs +++ b/sdk/src/wallet/operations/participation/mod.rs @@ -25,7 +25,12 @@ use crate::{ }, block::output::{unlock_condition::UnlockCondition, Output, OutputId}, }, - wallet::{core::WalletData, task, types::OutputData, Result, Wallet}, + wallet::{ + core::{Online, OnlineWalletData}, + task, + types::OutputData, + Result, Wallet, + }, }; /// An object containing an account's entire participation overview. @@ -46,7 +51,7 @@ pub struct ParticipationEventWithNodes { pub nodes: Vec, } -impl Wallet { +impl Wallet> { /// Calculates the voting overview of a wallet. If event_ids are provided, only return outputs and tracked /// participations for them. pub async fn get_participation_overview( @@ -57,7 +62,8 @@ impl Wallet { // TODO: Could use the address endpoint in the future when https://github.com/iotaledger/inx-participation/issues/50 is done. let mut spent_cached_outputs = self - .storage_manager + .storage + .manager .read() .await .get_cached_participation_output_status() @@ -206,7 +212,8 @@ impl Wallet { ); // Only store updated data if new outputs got added if spent_cached_outputs.len() > restored_spent_cached_outputs_len { - self.storage_manager + self.storage + .manager .read() .await .set_cached_participation_output_status(&spent_cached_outputs) @@ -227,7 +234,7 @@ impl Wallet { /// If event isn't found, the client from the account will be returned. pub(crate) async fn get_client_for_event(&self, id: &ParticipationEventId) -> crate::wallet::Result { log::debug!("[get_client_for_event]"); - let events = self.storage_manager.read().await.get_participation_events().await?; + let events = self.storage.manager.read().await.get_participation_events().await?; let event_with_nodes = match events.get(id) { Some(event_with_nodes) => event_with_nodes, @@ -252,7 +259,7 @@ impl Wallet { let latest_milestone_index = 0; // let latest_milestone_index = self.client().get_info().await?.node_info.status.latest_milestone.index; - let events = self.storage_manager.read().await.get_participation_events().await?; + let events = self.storage.manager.read().await.get_participation_events().await?; for participation in participations.participations.clone().iter() { if let Some(event_with_nodes) = events.get(&participation.event_id) { @@ -273,7 +280,7 @@ impl Wallet { } } -impl WalletData { +impl OnlineWalletData { /// Returns the voting output ("PARTICIPATION" tag). /// /// If multiple outputs with this tag exist, the one with the largest amount will be returned. diff --git a/sdk/src/wallet/operations/participation/voting.rs b/sdk/src/wallet/operations/participation/voting.rs index a4dc030be3..f34ab4501c 100644 --- a/sdk/src/wallet/operations/participation/voting.rs +++ b/sdk/src/wallet/operations/participation/voting.rs @@ -13,10 +13,12 @@ use crate::{ payload::TaggedDataPayload, }, }, - wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Result, Wallet}, + wallet::{ + core::Online, operations::transaction::TransactionOptions, types::TransactionWithMetadata, Result, Wallet, + }, }; -impl Wallet { +impl Wallet> { /// Casts a given number of votes for a given (voting) event. /// /// If voting for other events, continues voting for them. diff --git a/sdk/src/wallet/operations/participation/voting_power.rs b/sdk/src/wallet/operations/participation/voting_power.rs index 7a4f5fb424..d84f178c83 100644 --- a/sdk/src/wallet/operations/participation/voting_power.rs +++ b/sdk/src/wallet/operations/participation/voting_power.rs @@ -14,10 +14,13 @@ use crate::{ payload::TaggedDataPayload, }, }, - wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Error, Result, Wallet}, + wallet::{ + core::Online, operations::transaction::TransactionOptions, types::TransactionWithMetadata, Error, Result, + Wallet, + }, }; -impl Wallet { +impl Wallet> { /// Returns an account's total voting power (voting or NOT voting). pub async fn get_voting_power(&self) -> Result { Ok(self diff --git a/sdk/src/wallet/operations/reissue.rs b/sdk/src/wallet/operations/reissue.rs index 186186cd89..7d4951ee0f 100644 --- a/sdk/src/wallet/operations/reissue.rs +++ b/sdk/src/wallet/operations/reissue.rs @@ -13,13 +13,13 @@ use crate::{ BlockId, }, }, - wallet::{types::InclusionState, Error, Wallet}, + wallet::{core::Online, types::InclusionState, Error, Wallet}, }; const DEFAULT_REISSUE_UNTIL_INCLUDED_INTERVAL: u64 = 1; const DEFAULT_REISSUE_UNTIL_INCLUDED_MAX_AMOUNT: u64 = 40; -impl Wallet { +impl Wallet> { /// Reissues a transaction sent from the account for a provided transaction id until it's /// included (referenced by a milestone). Returns the included block id. pub async fn reissue_transaction_until_included( diff --git a/sdk/src/wallet/operations/syncing/addresses/output_ids/account_foundry.rs b/sdk/src/wallet/operations/syncing/addresses/output_ids/account_foundry.rs index 4ae451adf0..542275bfa8 100644 --- a/sdk/src/wallet/operations/syncing/addresses/output_ids/account_foundry.rs +++ b/sdk/src/wallet/operations/syncing/addresses/output_ids/account_foundry.rs @@ -16,10 +16,10 @@ use crate::{ }, }, utils::ConvertTo, - wallet::{operations::syncing::SyncOptions, task, Wallet}, + wallet::{core::Online, operations::syncing::SyncOptions, task, Wallet}, }; -impl Wallet { +impl Wallet> { /// Returns output ids of account outputs pub(crate) async fn get_account_and_foundry_output_ids( &self, diff --git a/sdk/src/wallet/operations/syncing/addresses/output_ids/basic.rs b/sdk/src/wallet/operations/syncing/addresses/output_ids/basic.rs index 1213cd2b4f..3f205e4d2a 100644 --- a/sdk/src/wallet/operations/syncing/addresses/output_ids/basic.rs +++ b/sdk/src/wallet/operations/syncing/addresses/output_ids/basic.rs @@ -5,10 +5,10 @@ use crate::{ client::{node_api::indexer::query_parameters::BasicOutputQueryParameters, secret::SecretManage}, types::block::{address::Bech32Address, output::OutputId}, utils::ConvertTo, - wallet::Wallet, + wallet::{core::Online, Wallet}, }; -impl Wallet { +impl Wallet> { /// Returns output ids of basic outputs that have only the address unlock condition pub(crate) async fn get_basic_output_ids_with_address_unlock_condition_only( &self, diff --git a/sdk/src/wallet/operations/syncing/addresses/output_ids/mod.rs b/sdk/src/wallet/operations/syncing/addresses/output_ids/mod.rs index 48860984af..b0f163955a 100644 --- a/sdk/src/wallet/operations/syncing/addresses/output_ids/mod.rs +++ b/sdk/src/wallet/operations/syncing/addresses/output_ids/mod.rs @@ -18,12 +18,12 @@ use crate::{ }, types::block::{address::Bech32Address, output::OutputId}, wallet::{ - constants::PARALLEL_REQUESTS_AMOUNT, operations::syncing::SyncOptions, + constants::PARALLEL_REQUESTS_AMOUNT, core::Online, operations::syncing::SyncOptions, types::address::AddressWithUnspentOutputs, Wallet, }, }; -impl Wallet { +impl Wallet> { /// Returns output ids for outputs that are directly (Ed25519 address in AddressUnlockCondition) or indirectly /// (account/nft address in AddressUnlockCondition and the account/nft output is controlled with the Ed25519 /// address) connected to diff --git a/sdk/src/wallet/operations/syncing/addresses/output_ids/nft.rs b/sdk/src/wallet/operations/syncing/addresses/output_ids/nft.rs index bbb566437c..c2f982de99 100644 --- a/sdk/src/wallet/operations/syncing/addresses/output_ids/nft.rs +++ b/sdk/src/wallet/operations/syncing/addresses/output_ids/nft.rs @@ -5,10 +5,10 @@ use crate::{ client::{node_api::indexer::query_parameters::NftOutputQueryParameters, secret::SecretManage}, types::block::{address::Bech32Address, output::OutputId}, utils::ConvertTo, - wallet::Wallet, + wallet::{core::Online, Wallet}, }; -impl Wallet { +impl Wallet> { /// Returns output ids of NFT outputs that have the address in the `AddressUnlockCondition` or /// `ExpirationUnlockCondition` pub(crate) async fn get_nft_output_ids_with_any_unlock_condition( diff --git a/sdk/src/wallet/operations/syncing/addresses/outputs.rs b/sdk/src/wallet/operations/syncing/addresses/outputs.rs index d6f374854e..489dd4a476 100644 --- a/sdk/src/wallet/operations/syncing/addresses/outputs.rs +++ b/sdk/src/wallet/operations/syncing/addresses/outputs.rs @@ -7,13 +7,14 @@ use crate::{ client::secret::SecretManage, wallet::{ constants::PARALLEL_REQUESTS_AMOUNT, + core::Online, task, types::{address::AddressWithUnspentOutputs, OutputData}, Wallet, }, }; -impl Wallet { +impl Wallet> { /// Get outputs from addresses pub(crate) async fn get_outputs_from_address_output_ids( &self, diff --git a/sdk/src/wallet/operations/syncing/foundries.rs b/sdk/src/wallet/operations/syncing/foundries.rs index 839a11ee1a..7291a715f9 100644 --- a/sdk/src/wallet/operations/syncing/foundries.rs +++ b/sdk/src/wallet/operations/syncing/foundries.rs @@ -6,10 +6,10 @@ use std::collections::HashSet; use crate::{ client::secret::SecretManage, types::block::output::{FoundryId, Output}, - wallet::{task, Wallet}, + wallet::{core::Online, task, Wallet}, }; -impl Wallet { +impl Wallet> { pub(crate) async fn request_and_store_foundry_outputs( &self, foundry_ids: HashSet, diff --git a/sdk/src/wallet/operations/syncing/mod.rs b/sdk/src/wallet/operations/syncing/mod.rs index d1cc51c6f0..51e04fe15e 100644 --- a/sdk/src/wallet/operations/syncing/mod.rs +++ b/sdk/src/wallet/operations/syncing/mod.rs @@ -18,18 +18,19 @@ use crate::{ }, wallet::{ constants::MIN_SYNC_INTERVAL, + core::Online, types::{AddressWithUnspentOutputs, Balance, OutputData}, Wallet, }, }; -impl Wallet { +impl Wallet> { /// Set the fallback SyncOptions for account syncing. /// If storage is enabled, will persist during restarts. pub async fn set_default_sync_options(&self, options: SyncOptions) -> crate::wallet::Result<()> { #[cfg(feature = "storage")] { - let storage_manager = self.storage_manager.read().await; + let storage_manager = self.storage.manager.read().await; storage_manager.set_default_sync_options(&options).await?; } diff --git a/sdk/src/wallet/operations/syncing/outputs.rs b/sdk/src/wallet/operations/syncing/outputs.rs index 0213d2662e..9265794b9a 100644 --- a/sdk/src/wallet/operations/syncing/outputs.rs +++ b/sdk/src/wallet/operations/syncing/outputs.rs @@ -15,13 +15,15 @@ use crate::{ }, }, wallet::{ - build_transaction_from_payload_and_inputs, task, + build_transaction_from_payload_and_inputs, + core::Online, + task, types::{AddressWithUnspentOutputs, OutputData}, Wallet, }, }; -impl Wallet { +impl Wallet> { /// Convert OutputWithMetadataResponse to OutputData with the network_id added pub(crate) async fn output_response_to_output_data( &self, diff --git a/sdk/src/wallet/operations/syncing/transactions.rs b/sdk/src/wallet/operations/syncing/transactions.rs index 0f7de427f9..e57ce747c0 100644 --- a/sdk/src/wallet/operations/syncing/transactions.rs +++ b/sdk/src/wallet/operations/syncing/transactions.rs @@ -8,7 +8,7 @@ use crate::{ block::{input::Input, output::OutputId, BlockId}, }, wallet::{ - core::WalletData, + core::{Online, OnlineWalletData}, types::{InclusionState, TransactionWithMetadata}, Wallet, }, @@ -19,7 +19,7 @@ use crate::{ // also revalidate that the locked outputs needs to be there, maybe there was a conflict or the transaction got // confirmed, then they should get removed -impl Wallet { +impl Wallet> { /// Sync transactions and reissue them if unconfirmed. Returns the transaction with updated metadata and spent /// output ids that don't need to be locked anymore /// Return true if a transaction got confirmed for which we don't have an output already, based on this outputs will @@ -234,7 +234,7 @@ fn updated_transaction_and_outputs( // When a transaction got pruned, the inputs and outputs are also not available, then this could mean that it was // confirmed and the created outputs got also already spent and pruned or the inputs got spent in another transaction fn process_transaction_with_unknown_state( - wallet_data: &WalletData, + wallet_data: &OnlineWalletData, mut transaction: TransactionWithMetadata, updated_transactions: &mut Vec, output_ids_to_unlock: &mut Vec, diff --git a/sdk/src/wallet/operations/transaction/account.rs b/sdk/src/wallet/operations/transaction/account.rs index 3b284b8580..b26b68a024 100644 --- a/sdk/src/wallet/operations/transaction/account.rs +++ b/sdk/src/wallet/operations/transaction/account.rs @@ -16,12 +16,13 @@ use crate::{ payload::signed_transaction::{TransactionCapabilities, TransactionCapabilityFlag}, }, wallet::{ + core::Online, operations::transaction::{TransactionOptions, TransactionWithMetadata}, Error, Result, Wallet, }, }; -impl Wallet { +impl Wallet> { /// Transitions an implicit account to an account. pub async fn implicit_account_transition( &self, diff --git a/sdk/src/wallet/operations/transaction/build_transaction.rs b/sdk/src/wallet/operations/transaction/build_transaction.rs index 362d910ce2..609adb40b1 100644 --- a/sdk/src/wallet/operations/transaction/build_transaction.rs +++ b/sdk/src/wallet/operations/transaction/build_transaction.rs @@ -12,10 +12,10 @@ use crate::{ input::{Input, UtxoInput}, payload::signed_transaction::Transaction, }, - wallet::{operations::transaction::TransactionOptions, Wallet}, + wallet::{core::Online, operations::transaction::TransactionOptions, Wallet}, }; -impl Wallet { +impl Wallet> { /// Builds the transaction from the selected in and outputs. pub(crate) async fn build_transaction( &self, diff --git a/sdk/src/wallet/operations/transaction/high_level/burning_melting/melt_native_token.rs b/sdk/src/wallet/operations/transaction/high_level/burning_melting/melt_native_token.rs index d42d2b6743..d4af0a04d9 100644 --- a/sdk/src/wallet/operations/transaction/high_level/burning_melting/melt_native_token.rs +++ b/sdk/src/wallet/operations/transaction/high_level/burning_melting/melt_native_token.rs @@ -10,13 +10,14 @@ use crate::{ TokenScheme, }, wallet::{ + core::{Online, WalletCommon}, operations::transaction::TransactionOptions, types::{OutputData, TransactionWithMetadata}, Error, Wallet, }, }; -impl Wallet { +impl Wallet> { /// Melts native tokens. /// /// This happens with the foundry output which minted them, by increasing it's diff --git a/sdk/src/wallet/operations/transaction/high_level/burning_melting/mod.rs b/sdk/src/wallet/operations/transaction/high_level/burning_melting/mod.rs index be341e5e86..a420b4813b 100644 --- a/sdk/src/wallet/operations/transaction/high_level/burning_melting/mod.rs +++ b/sdk/src/wallet/operations/transaction/high_level/burning_melting/mod.rs @@ -6,12 +6,12 @@ use crate::{ api::{input_selection::Burn, PreparedTransactionData}, secret::SecretManage, }, - wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Wallet}, + wallet::{core::Online, operations::transaction::TransactionOptions, types::TransactionWithMetadata, Wallet}, }; pub(crate) mod melt_native_token; -impl Wallet { +impl Wallet> { /// A generic function that can be used to burn native tokens, nfts, foundries and accounts. /// /// Note that burning **native tokens** doesn't require the foundry output which minted them, but will not increase diff --git a/sdk/src/wallet/operations/transaction/high_level/create_account.rs b/sdk/src/wallet/operations/transaction/high_level/create_account.rs index 1a26dd21d3..9876ef438e 100644 --- a/sdk/src/wallet/operations/transaction/high_level/create_account.rs +++ b/sdk/src/wallet/operations/transaction/high_level/create_account.rs @@ -13,6 +13,7 @@ use crate::{ }, utils::serde::option_prefix_hex_bytes, wallet::{ + core::Online, operations::transaction::TransactionOptions, types::{OutputData, TransactionWithMetadata}, Wallet, @@ -34,7 +35,7 @@ pub struct CreateAccountParams { pub metadata: Option>, } -impl Wallet { +impl Wallet> { /// Creates an account output. /// ```ignore /// let params = CreateAccountParams { diff --git a/sdk/src/wallet/operations/transaction/high_level/minting/create_native_token.rs b/sdk/src/wallet/operations/transaction/high_level/minting/create_native_token.rs index dc957dabf3..b0d7ef04e3 100644 --- a/sdk/src/wallet/operations/transaction/high_level/minting/create_native_token.rs +++ b/sdk/src/wallet/operations/transaction/high_level/minting/create_native_token.rs @@ -17,6 +17,7 @@ use crate::{ }, }, wallet::{ + core::Online, operations::transaction::TransactionOptions, types::{TransactionWithMetadata, TransactionWithMetadataDto}, Wallet, @@ -86,7 +87,7 @@ impl From<&PreparedCreateNativeTokenTransaction> for PreparedCreate } } -impl Wallet { +impl Wallet> { /// Creates a new foundry output with minted native tokens. /// /// Calls [Wallet::send_outputs()] internally, the options may define the remainder value strategy or custom inputs. diff --git a/sdk/src/wallet/operations/transaction/high_level/minting/mint_native_token.rs b/sdk/src/wallet/operations/transaction/high_level/minting/mint_native_token.rs index 3107c193c4..e2d9b3a709 100644 --- a/sdk/src/wallet/operations/transaction/high_level/minting/mint_native_token.rs +++ b/sdk/src/wallet/operations/transaction/high_level/minting/mint_native_token.rs @@ -8,10 +8,12 @@ use crate::{ types::block::output::{ AccountOutputBuilder, FoundryOutputBuilder, Output, SimpleTokenScheme, TokenId, TokenScheme, }, - wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Error, Wallet}, + wallet::{ + core::Online, operations::transaction::TransactionOptions, types::TransactionWithMetadata, Error, Wallet, + }, }; -impl Wallet { +impl Wallet> { /// Mints additional native tokens. /// /// The max supply must not be reached yet. The foundry needs to be diff --git a/sdk/src/wallet/operations/transaction/high_level/minting/mint_nfts.rs b/sdk/src/wallet/operations/transaction/high_level/minting/mint_nfts.rs index 5b59b1f627..659a7a4d5b 100644 --- a/sdk/src/wallet/operations/transaction/high_level/minting/mint_nfts.rs +++ b/sdk/src/wallet/operations/transaction/high_level/minting/mint_nfts.rs @@ -16,6 +16,7 @@ use crate::{ }, utils::ConvertTo, wallet::{ + core::Online, operations::transaction::{TransactionOptions, TransactionWithMetadata}, Wallet, }, @@ -109,7 +110,7 @@ impl MintNftParams { } } -impl Wallet { +impl Wallet> { /// Mints NFTs. /// /// Calls [Wallet::send_outputs()] internally. The options may define the remainder value strategy or custom inputs. diff --git a/sdk/src/wallet/operations/transaction/high_level/send.rs b/sdk/src/wallet/operations/transaction/high_level/send.rs index b9ba07be43..e7d4256057 100644 --- a/sdk/src/wallet/operations/transaction/high_level/send.rs +++ b/sdk/src/wallet/operations/transaction/high_level/send.rs @@ -17,6 +17,7 @@ use crate::{ utils::{serde::string, ConvertTo}, wallet::{ constants::DEFAULT_EXPIRATION_SLOTS, + core::Online, operations::transaction::{TransactionOptions, TransactionWithMetadata}, Error, Wallet, }, @@ -73,7 +74,7 @@ impl SendParams { } } -impl Wallet { +impl Wallet> { /// Sends a certain amount of base coins to a single address. /// /// Calls [Wallet::send_with_params()] internally. diff --git a/sdk/src/wallet/operations/transaction/high_level/send_native_tokens.rs b/sdk/src/wallet/operations/transaction/high_level/send_native_tokens.rs index 93e176706e..95a1edf40d 100644 --- a/sdk/src/wallet/operations/transaction/high_level/send_native_tokens.rs +++ b/sdk/src/wallet/operations/transaction/high_level/send_native_tokens.rs @@ -18,6 +18,7 @@ use crate::{ utils::ConvertTo, wallet::{ constants::DEFAULT_EXPIRATION_SLOTS, + core::Online, operations::transaction::{TransactionOptions, TransactionWithMetadata}, Error, Result, Wallet, }, @@ -73,7 +74,7 @@ impl SendNativeTokenParams { } } -impl Wallet { +impl Wallet> { /// Sends native tokens in basic outputs with a /// [`StorageDepositReturnUnlockCondition`](crate::types::block::output::unlock_condition::StorageDepositReturnUnlockCondition) /// and an [`ExpirationUnlockCondition`], so that the storage deposit is returned to the sender and the sender diff --git a/sdk/src/wallet/operations/transaction/high_level/send_nft.rs b/sdk/src/wallet/operations/transaction/high_level/send_nft.rs index f4cfa12b1e..56ecd32ade 100644 --- a/sdk/src/wallet/operations/transaction/high_level/send_nft.rs +++ b/sdk/src/wallet/operations/transaction/high_level/send_nft.rs @@ -12,6 +12,7 @@ use crate::{ }, utils::ConvertTo, wallet::{ + core::Online, operations::transaction::{TransactionOptions, TransactionWithMetadata}, Wallet, }, @@ -42,7 +43,7 @@ impl SendNftParams { } } -impl Wallet { +impl Wallet> { /// Sends native tokens in basic outputs with a /// [`StorageDepositReturnUnlockCondition`](crate::types::block::output::unlock_condition::StorageDepositReturnUnlockCondition) and an /// [`ExpirationUnlockCondition`](crate::types::block::output::unlock_condition::ExpirationUnlockCondition), so that diff --git a/sdk/src/wallet/operations/transaction/input_selection.rs b/sdk/src/wallet/operations/transaction/input_selection.rs index d7dec257ac..20a85eab7a 100644 --- a/sdk/src/wallet/operations/transaction/input_selection.rs +++ b/sdk/src/wallet/operations/transaction/input_selection.rs @@ -16,12 +16,14 @@ use crate::{ slot::SlotIndex, }, wallet::{ - core::WalletData, operations::helpers::time::can_output_be_unlocked_forever_from_now_on, types::OutputData, + core::{Online, OnlineWalletData}, + operations::helpers::time::can_output_be_unlocked_forever_from_now_on, + types::OutputData, Wallet, }, }; -impl Wallet { +impl Wallet> { /// Selects inputs for a transaction and locks them in the wallet, so they don't get used again pub(crate) async fn select_inputs( &self, @@ -212,7 +214,7 @@ impl Wallet { /// | [Address, StorageDepositReturn, expired Expiration] | yes | #[allow(clippy::too_many_arguments)] fn filter_inputs( - wallet_data: &WalletData, + wallet_data: &OnlineWalletData, available_outputs: Values<'_, OutputId, OutputData>, slot_index: SlotIndex, custom_inputs: Option<&HashSet>, diff --git a/sdk/src/wallet/operations/transaction/mod.rs b/sdk/src/wallet/operations/transaction/mod.rs index 55b599b5b2..aa9574f524 100644 --- a/sdk/src/wallet/operations/transaction/mod.rs +++ b/sdk/src/wallet/operations/transaction/mod.rs @@ -29,12 +29,13 @@ use crate::{ }, }, wallet::{ + core::Online, types::{InclusionState, TransactionWithMetadata}, Wallet, }, }; -impl Wallet { +impl Wallet> { /// Sends a transaction by specifying its outputs. /// /// Note that, if sending a block fails, the method will return `None` for the block id, but the wallet diff --git a/sdk/src/wallet/operations/transaction/prepare_output.rs b/sdk/src/wallet/operations/transaction/prepare_output.rs index 85b088c7c7..fda6b0d180 100644 --- a/sdk/src/wallet/operations/transaction/prepare_output.rs +++ b/sdk/src/wallet/operations/transaction/prepare_output.rs @@ -21,13 +21,14 @@ use crate::{ }, utils::serde::string, wallet::{ + core::Online, operations::transaction::{RemainderValueStrategy, TransactionOptions}, types::OutputData, Wallet, }, }; -impl Wallet { +impl Wallet> { /// Prepare a basic or NFT output for sending /// If the amount is below the minimum required storage deposit, by default the remaining amount will automatically /// be added with a StorageDepositReturn UnlockCondition, when setting the ReturnStrategy to `gift`, the full diff --git a/sdk/src/wallet/operations/transaction/prepare_transaction.rs b/sdk/src/wallet/operations/transaction/prepare_transaction.rs index 59f553cabf..1c3a46266e 100644 --- a/sdk/src/wallet/operations/transaction/prepare_transaction.rs +++ b/sdk/src/wallet/operations/transaction/prepare_transaction.rs @@ -13,12 +13,13 @@ use crate::{ output::{Output, OUTPUT_COUNT_RANGE}, }, wallet::{ + core::Online, operations::transaction::{RemainderValueStrategy, TransactionOptions}, Wallet, }, }; -impl Wallet { +impl Wallet> { /// Get inputs and build the transaction pub async fn prepare_transaction( &self, diff --git a/sdk/src/wallet/operations/transaction/sign_transaction.rs b/sdk/src/wallet/operations/transaction/sign_transaction.rs index dd32b00301..a20964bbf6 100644 --- a/sdk/src/wallet/operations/transaction/sign_transaction.rs +++ b/sdk/src/wallet/operations/transaction/sign_transaction.rs @@ -16,10 +16,10 @@ use crate::{ }, secret::SecretManage, }, - wallet::{operations::transaction::SignedTransactionPayload, Wallet}, + wallet::{core::Online, operations::transaction::SignedTransactionPayload, Wallet}, }; -impl Wallet { +impl Wallet> { /// Signs a transaction. pub async fn sign_transaction( &self, diff --git a/sdk/src/wallet/operations/transaction/submit_transaction.rs b/sdk/src/wallet/operations/transaction/submit_transaction.rs index fab7ac0ee7..cab520b556 100644 --- a/sdk/src/wallet/operations/transaction/submit_transaction.rs +++ b/sdk/src/wallet/operations/transaction/submit_transaction.rs @@ -6,10 +6,10 @@ use crate::wallet::events::types::{TransactionProgressEvent, WalletEvent}; use crate::{ client::secret::SecretManage, types::block::{output::AccountId, payload::Payload, BlockId}, - wallet::{operations::transaction::SignedTransactionPayload, Wallet}, + wallet::{core::Online, operations::transaction::SignedTransactionPayload, Wallet}, }; -impl Wallet { +impl Wallet> { /// Submits a signed transaction in a block. pub(crate) async fn submit_signed_transaction( &self, diff --git a/sdk/src/wallet/storage/manager.rs b/sdk/src/wallet/storage/manager.rs index 470f8ce964..53c904b670 100644 --- a/sdk/src/wallet/storage/manager.rs +++ b/sdk/src/wallet/storage/manager.rs @@ -1,13 +1,13 @@ // Copyright 2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use serde::{de::DeserializeOwned, Serialize}; use zeroize::Zeroizing; use crate::{ - client::{secret::SecretManage, storage::StorageAdapter}, + client::storage::StorageAdapter, types::TryFromDto, wallet::{ - core::{WalletData, WalletDataDto}, migration::migrate, operations::syncing::SyncOptions, storage::{constants::*, DynStorageAdapter, Storage}, @@ -49,22 +49,24 @@ impl StorageManager { Ok(storage_manager) } - pub(crate) async fn load_wallet_data(&mut self) -> crate::wallet::Result>> { - if let Some(dto) = self - .get::>(WALLET_DATA_KEY) - .await? - { - Ok(Some(WalletData::try_from_dto(dto)?)) + pub(crate) async fn load_wallet_data, D: DeserializeOwned>( + &mut self, + ) -> crate::wallet::Result> + where + crate::wallet::Error: From, + { + if let Some(dto) = self.get::(WALLET_DATA_KEY).await? { + Ok(Some(T::try_from_dto(dto)?)) } else { Ok(None) } } - pub(crate) async fn save_wallet_data( + pub(crate) async fn save_wallet_data, D: Serialize + Send + Sync + for<'a> From<&'a T>>( &mut self, - wallet_data: &WalletData, + wallet_data: &T, ) -> crate::wallet::Result<()> { - self.set(WALLET_DATA_KEY, &WalletDataDto::from(wallet_data)).await + self.set(WALLET_DATA_KEY, &D::from(wallet_data)).await } pub(crate) async fn set_default_sync_options(&self, sync_options: &SyncOptions) -> crate::wallet::Result<()> { @@ -103,7 +105,11 @@ mod tests { use super::*; use crate::{ client::secret::{mnemonic::MnemonicSecretManager, SecretManager}, - wallet::{storage::adapter::memory::Memory, WalletBuilder}, + wallet::{ + core::{builder::OnlineBuilder, OnlineWalletData}, + storage::adapter::memory::Memory, + WalletBuilder, + }, }; #[tokio::test] @@ -132,17 +138,17 @@ mod tests { let mut storage_manager = StorageManager::new(Memory::default(), None).await.unwrap(); assert!( storage_manager - .load_wallet_data::() + .load_wallet_data::, _>() .await .unwrap() .is_none() ); - let wallet_data = WalletData::::mock(); + let wallet_data = OnlineWalletData::::mock(); storage_manager.save_wallet_data(&wallet_data).await.unwrap(); let wallet = storage_manager - .load_wallet_data::() + .load_wallet_data::, _>() .await .unwrap(); assert!(matches!(wallet, Some(data) if data.alias == Some("Alice".to_string()))); @@ -152,17 +158,17 @@ mod tests { async fn save_load_wallet_builder() { let storage_manager = StorageManager::new(Memory::default(), None).await.unwrap(); assert!( - WalletBuilder::::load(&storage_manager) + WalletBuilder::>::load(&storage_manager) .await .unwrap() .is_none() ); - let wallet_builder = WalletBuilder::::new(); + let wallet_builder = WalletBuilder::new().into_online::(); wallet_builder.save(&storage_manager).await.unwrap(); assert!( - WalletBuilder::::load(&storage_manager) + WalletBuilder::>::load(&storage_manager) .await .unwrap() .is_some() diff --git a/sdk/src/wallet/types/mod.rs b/sdk/src/wallet/types/mod.rs index 98c7dc9102..8db1edebc0 100644 --- a/sdk/src/wallet/types/mod.rs +++ b/sdk/src/wallet/types/mod.rs @@ -29,7 +29,7 @@ use crate::{ }, TryFromDto, }, - wallet::core::WalletData, + wallet::core::OnlineWalletData, }; /// An output with metadata @@ -55,7 +55,7 @@ pub struct OutputData { impl OutputData { pub fn input_signing_data>( &self, - wallet_data: &WalletData, + wallet_data: &OnlineWalletData, slot_index: SlotIndex, ) -> crate::wallet::Result>> { let (unlock_address, _unlocked_account_or_nft_address) = diff --git a/sdk/src/wallet/update.rs b/sdk/src/wallet/update.rs index 24787a8f72..5ff19e5981 100644 --- a/sdk/src/wallet/update.rs +++ b/sdk/src/wallet/update.rs @@ -10,6 +10,7 @@ use crate::{ signature::Ed25519Signature, }, wallet::{ + core::{Offline, Online, WalletCommon}, types::{InclusionState, OutputData, TransactionWithMetadata}, Wallet, }, @@ -21,7 +22,7 @@ use crate::{ wallet::events::types::{NewOutputEvent, SpentOutputEvent, TransactionInclusionEvent, WalletEvent}, }; -impl Wallet { +impl Wallet { /// Set the alias for the wallet. pub async fn set_alias(&self, alias: &str) -> crate::wallet::Result<()> { let mut wallet_data = self.data_mut().await; @@ -30,6 +31,17 @@ impl Wallet { self.save(Some(&wallet_data)).await?; Ok(()) } +} + +impl Wallet> { + /// Set the alias for the wallet. + pub async fn set_alias(&self, alias: &str) -> crate::wallet::Result<()> { + let mut wallet_data = self.data_mut().await; + wallet_data.inner.alias = Some(alias.to_string()); + #[cfg(feature = "storage")] + self.save(Some(&wallet_data)).await?; + Ok(()) + } /// Update wallet with newly synced data and emit events for outputs. pub(crate) async fn update_after_sync( @@ -188,7 +200,7 @@ impl Wallet { let bech32_hrp = self.client().get_bech32_hrp().await?; log::debug!("updating wallet data with new bech32 hrp: {}", bech32_hrp); let mut wallet_data = self.data_mut().await; - wallet_data.address.hrp = bech32_hrp; + wallet_data.inner.address.hrp = bech32_hrp; wallet_data.inaccessible_incoming_transactions.clear(); diff --git a/sdk/tests/wallet/burn_outputs.rs b/sdk/tests/wallet/burn_outputs.rs index 8973700dae..5af986a7d9 100644 --- a/sdk/tests/wallet/burn_outputs.rs +++ b/sdk/tests/wallet/burn_outputs.rs @@ -7,7 +7,7 @@ use iota_sdk::{ unlock_condition::{AddressUnlockCondition, ExpirationUnlockCondition}, NativeToken, NftId, NftOutputBuilder, OutputId, UnlockCondition, }, - wallet::{CreateNativeTokenParams, MintNftParams, Result, Wallet}, + wallet::{core::Online, CreateNativeTokenParams, MintNftParams, Result, Wallet}, U256, }; use pretty_assertions::assert_eq; @@ -177,7 +177,7 @@ async fn create_and_melt_native_token() -> Result<()> { tear_down(storage_path) } -async fn destroy_foundry(wallet: &Wallet) -> Result<()> { +async fn destroy_foundry(wallet: &Wallet>) -> Result<()> { let balance = wallet.sync(None).await?; println!("wallet balance -> {}", serde_json::to_string(&balance).unwrap()); @@ -200,7 +200,7 @@ async fn destroy_foundry(wallet: &Wallet) -> Resul Ok(()) } -async fn destroy_account(wallet: &Wallet) -> Result<()> { +async fn destroy_account(wallet: &Wallet>) -> Result<()> { let balance = wallet.sync(None).await.unwrap(); println!("account balance -> {}", serde_json::to_string(&balance).unwrap()); diff --git a/sdk/tests/wallet/common/mod.rs b/sdk/tests/wallet/common/mod.rs index 2748476704..4b1cb44167 100644 --- a/sdk/tests/wallet/common/mod.rs +++ b/sdk/tests/wallet/common/mod.rs @@ -11,7 +11,7 @@ use iota_sdk::{ secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManage}, Client, }, - wallet::{ClientOptions, Result, Wallet}, + wallet::{core::Online, ClientOptions, Result, Wallet}, }; pub use self::constants::*; @@ -33,7 +33,7 @@ pub(crate) async fn make_wallet( storage_path: &str, mnemonic: Option, node: Option<&str>, -) -> Result> { +) -> Result>> { let client_options = ClientOptions::new().with_node(node.unwrap_or(NODE_LOCAL))?; let secret_manager = MnemonicSecretManager::try_from_mnemonic(mnemonic.unwrap_or_else(|| Client::generate_mnemonic().unwrap()))?; @@ -58,7 +58,7 @@ pub(crate) async fn make_wallet( pub(crate) async fn make_ledger_nano_wallet( storage_path: &str, node: Option<&str>, -) -> Result> { +) -> Result>> { use iota_sdk::client::secret::ledger_nano::{LedgerOptions, LedgerSecretManager}; let client_options = ClientOptions::new().with_node(node.unwrap_or(NODE_LOCAL))?; @@ -81,7 +81,7 @@ pub(crate) async fn make_ledger_nano_wallet( /// Request funds from the faucet and sync the wallet. #[allow(dead_code)] -pub(crate) async fn request_funds(wallet: &Wallet) -> Result<()> { +pub(crate) async fn request_funds(wallet: &Wallet>) -> Result<()> { request_funds_from_faucet(FAUCET_URL, &wallet.address().await).await?; // Continue only after funds are received