diff --git a/key-wallet-manager/tests/integration_test.rs b/key-wallet-manager/tests/integration_test.rs index af4881af..a92bce69 100644 --- a/key-wallet-manager/tests/integration_test.rs +++ b/key-wallet-manager/tests/integration_test.rs @@ -62,10 +62,10 @@ fn test_account_management() { ); assert!(result.is_ok()); - // Get accounts from wallet - Default creates 7 accounts, plus the one we added + // Get accounts from wallet - Default creates 8 accounts, plus the one we added let accounts = manager.get_accounts(&wallet_id); assert!(accounts.is_ok()); - assert_eq!(accounts.unwrap().len(), 8); // 7 from Default + 1 we added + assert_eq!(accounts.unwrap().len(), 9); // 8 from Default + 1 we added } #[test] diff --git a/key-wallet/src/gap_limit.rs b/key-wallet/src/gap_limit.rs index 649160b8..688d8af4 100644 --- a/key-wallet/src/gap_limit.rs +++ b/key-wallet/src/gap_limit.rs @@ -11,14 +11,16 @@ use serde::{Deserialize, Serialize}; use std::collections::HashSet; /// Standard gap limit for external addresses (BIP44 recommendation) -pub const DEFAULT_EXTERNAL_GAP_LIMIT: u32 = 20; +pub const DEFAULT_EXTERNAL_GAP_LIMIT: u32 = 30; /// Standard gap limit for internal (change) addresses -pub const DEFAULT_INTERNAL_GAP_LIMIT: u32 = 10; +pub const DEFAULT_INTERNAL_GAP_LIMIT: u32 = 30; /// Standard gap limit for CoinJoin addresses -pub const DEFAULT_COINJOIN_GAP_LIMIT: u32 = 10; +pub const DEFAULT_COINJOIN_GAP_LIMIT: u32 = 30; +/// Standard gap limit for special purpose keys (identity, provider keys) +pub const DEFAULT_SPECIAL_GAP_LIMIT: u32 = 5; /// Maximum gap limit to prevent excessive address generation pub const MAX_GAP_LIMIT: u32 = 1000; diff --git a/key-wallet/src/managed_account/address_pool.rs b/key-wallet/src/managed_account/address_pool.rs index 5af4f25e..cfef783f 100644 --- a/key-wallet/src/managed_account/address_pool.rs +++ b/key-wallet/src/managed_account/address_pool.rs @@ -15,6 +15,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use crate::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey}; use crate::error::{Error, Result}; +use crate::gap_limit::DEFAULT_EXTERNAL_GAP_LIMIT; use crate::Network; use dashcore::{Address, AddressType, ScriptBuf}; @@ -1059,7 +1060,7 @@ impl AddressPoolBuilder { Self { base_path: None, pool_type: AddressPoolType::External, - gap_limit: 20, + gap_limit: DEFAULT_EXTERNAL_GAP_LIMIT, network: Network::Dash, lookahead_size: 40, address_type: AddressType::P2pkh, diff --git a/key-wallet/src/managed_account/managed_account_collection.rs b/key-wallet/src/managed_account/managed_account_collection.rs index ad89ea50..d4a22391 100644 --- a/key-wallet/src/managed_account/managed_account_collection.rs +++ b/key-wallet/src/managed_account/managed_account_collection.rs @@ -4,6 +4,10 @@ //! across different networks in a hierarchical manner. use crate::account::account_type::AccountType; +use crate::gap_limit::{ + DEFAULT_COINJOIN_GAP_LIMIT, DEFAULT_EXTERNAL_GAP_LIMIT, DEFAULT_INTERNAL_GAP_LIMIT, + DEFAULT_SPECIAL_GAP_LIMIT, +}; use crate::managed_account::address_pool::{AddressPool, AddressPoolType}; use crate::managed_account::managed_account_type::ManagedAccountType; use crate::managed_account::ManagedAccount; @@ -329,7 +333,7 @@ impl ManagedAccountCollection { let external_pool = AddressPool::new( external_path, AddressPoolType::External, - 20, + DEFAULT_EXTERNAL_GAP_LIMIT, network, key_source, )?; @@ -339,7 +343,7 @@ impl ManagedAccountCollection { let internal_pool = AddressPool::new( internal_path, AddressPoolType::Internal, - 20, + DEFAULT_INTERNAL_GAP_LIMIT, network, key_source, )?; @@ -356,16 +360,26 @@ impl ManagedAccountCollection { AccountType::CoinJoin { index, } => { - let addresses = - AddressPool::new(base_path, AddressPoolType::Absent, 20, network, key_source)?; + let addresses = AddressPool::new( + base_path, + AddressPoolType::Absent, + DEFAULT_COINJOIN_GAP_LIMIT, + network, + key_source, + )?; ManagedAccountType::CoinJoin { index, addresses, } } AccountType::IdentityRegistration => { - let addresses = - AddressPool::new(base_path, AddressPoolType::Absent, 20, network, key_source)?; + let addresses = AddressPool::new( + base_path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; ManagedAccountType::IdentityRegistration { addresses, } @@ -373,44 +387,74 @@ impl ManagedAccountCollection { AccountType::IdentityTopUp { registration_index, } => { - let addresses = - AddressPool::new(base_path, AddressPoolType::Absent, 20, network, key_source)?; + let addresses = AddressPool::new( + base_path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; ManagedAccountType::IdentityTopUp { registration_index, addresses, } } AccountType::IdentityTopUpNotBoundToIdentity => { - let addresses = - AddressPool::new(base_path, AddressPoolType::Absent, 20, network, key_source)?; + let addresses = AddressPool::new( + base_path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; ManagedAccountType::IdentityTopUpNotBoundToIdentity { addresses, } } AccountType::IdentityInvitation => { - let addresses = - AddressPool::new(base_path, AddressPoolType::Absent, 20, network, key_source)?; + let addresses = AddressPool::new( + base_path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; ManagedAccountType::IdentityInvitation { addresses, } } AccountType::ProviderVotingKeys => { - let addresses = - AddressPool::new(base_path, AddressPoolType::Absent, 20, network, key_source)?; + let addresses = AddressPool::new( + base_path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; ManagedAccountType::ProviderVotingKeys { addresses, } } AccountType::ProviderOwnerKeys => { - let addresses = - AddressPool::new(base_path, AddressPoolType::Absent, 20, network, key_source)?; + let addresses = AddressPool::new( + base_path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; ManagedAccountType::ProviderOwnerKeys { addresses, } } AccountType::ProviderOperatorKeys => { - let addresses = - AddressPool::new(base_path, AddressPoolType::Absent, 20, network, key_source)?; + let addresses = AddressPool::new( + base_path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; ManagedAccountType::ProviderOperatorKeys { addresses, } @@ -419,7 +463,7 @@ impl ManagedAccountCollection { let addresses = AddressPool::new( base_path, AddressPoolType::AbsentHardened, - 20, + DEFAULT_SPECIAL_GAP_LIMIT, network, key_source, )?; diff --git a/key-wallet/src/managed_account/managed_account_type.rs b/key-wallet/src/managed_account/managed_account_type.rs index 61c1eb7e..f6b132f1 100644 --- a/key-wallet/src/managed_account/managed_account_type.rs +++ b/key-wallet/src/managed_account/managed_account_type.rs @@ -1,4 +1,9 @@ use crate::account::StandardAccountType; +use crate::gap_limit::{ + DEFAULT_COINJOIN_GAP_LIMIT, DEFAULT_EXTERNAL_GAP_LIMIT, DEFAULT_INTERNAL_GAP_LIMIT, + DEFAULT_SPECIAL_GAP_LIMIT, +}; + use crate::{AccountType, AddressPool, DerivationPath}; #[cfg(feature = "bincode")] use bincode_derive::{Decode, Encode}; @@ -356,7 +361,7 @@ impl ManagedAccountType { let external_pool = AddressPool::new( external_path, AddressPoolType::External, - 20, + DEFAULT_EXTERNAL_GAP_LIMIT, network, key_source, )?; @@ -366,7 +371,7 @@ impl ManagedAccountType { let internal_pool = AddressPool::new( internal_path, AddressPoolType::Internal, - 20, + DEFAULT_INTERNAL_GAP_LIMIT, network, key_source, )?; @@ -384,8 +389,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_COINJOIN_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::CoinJoin { index, @@ -396,8 +406,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::IdentityRegistration { addresses: pool, @@ -409,8 +424,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::IdentityTopUp { registration_index, @@ -421,8 +441,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::IdentityTopUpNotBoundToIdentity { addresses: pool, @@ -432,8 +457,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::IdentityInvitation { addresses: pool, @@ -443,8 +473,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::ProviderVotingKeys { addresses: pool, @@ -454,8 +489,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::ProviderOwnerKeys { addresses: pool, @@ -465,8 +505,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::ProviderOperatorKeys { addresses: pool, @@ -479,7 +524,7 @@ impl ManagedAccountType { let pool = AddressPool::new( path, AddressPoolType::AbsentHardened, - 20, + DEFAULT_SPECIAL_GAP_LIMIT, network, key_source, )?; diff --git a/key-wallet/src/transaction_checking/transaction_router/tests/routing.rs b/key-wallet/src/transaction_checking/transaction_router/tests/routing.rs index 929b70c5..d9d769a2 100644 --- a/key-wallet/src/transaction_checking/transaction_router/tests/routing.rs +++ b/key-wallet/src/transaction_checking/transaction_router/tests/routing.rs @@ -306,9 +306,9 @@ fn test_transaction_affects_multiple_accounts() { }; wallet.add_account(account_type, network, None).expect("Failed to add account to wallet"); - // Add a BIP32 account + // Add another BIP32 account let account_type = AccountType::Standard { - index: 0, + index: 1, standard_account_type: StandardAccountType::BIP32Account, }; wallet.add_account(account_type, network, None).expect("Failed to add account to wallet"); diff --git a/key-wallet/src/wallet/helper.rs b/key-wallet/src/wallet/helper.rs index 27b6ad93..6b3da1c8 100644 --- a/key-wallet/src/wallet/helper.rs +++ b/key-wallet/src/wallet/helper.rs @@ -171,6 +171,16 @@ impl Wallet { } match options { WalletAccountCreationOptions::Default => { + // Create default BIP32 account 0 + self.add_account( + AccountType::Standard { + index: 0, + standard_account_type: StandardAccountType::BIP32Account, + }, + network, + None, + )?; + // Create default BIP44 account 0 self.add_account( AccountType::Standard { @@ -347,6 +357,16 @@ impl Wallet { } match options { WalletAccountCreationOptions::Default => { + // Create default BIP32 account 0 + self.add_account_with_passphrase( + AccountType::Standard { + index: 0, + standard_account_type: StandardAccountType::BIP32Account, + }, + network, + passphrase, + )?; + // Create default BIP44 account 0 self.add_account_with_passphrase( AccountType::Standard { diff --git a/key-wallet/src/wallet/initialization.rs b/key-wallet/src/wallet/initialization.rs index db7f3b27..2d215c17 100644 --- a/key-wallet/src/wallet/initialization.rs +++ b/key-wallet/src/wallet/initialization.rs @@ -30,7 +30,7 @@ pub type WalletAccountCreationTopUpAccounts = BTreeSet; /// Options for specifying which accounts to create when initializing a wallet #[derive(Debug, Clone, Default)] pub enum WalletAccountCreationOptions { - /// Default account creation: Creates account 0 for BIP44, account 0 for CoinJoin, + /// Default account creation: Creates account 0 for BIP32, BIP44, account 0 for CoinJoin, /// and all special purpose accounts (Identity Registration, Identity Invitation, /// Provider keys, etc.) #[default]