From 9f845aa3aa58f891374e73f7d040ea5c6ce9a56d Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Fri, 3 Oct 2025 16:05:25 -0700 Subject: [PATCH 01/11] fix: add a BIP32 path to Default wallet creation options --- key-wallet/src/wallet/helper.rs | 10 ++++++++++ key-wallet/src/wallet/initialization.rs | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/key-wallet/src/wallet/helper.rs b/key-wallet/src/wallet/helper.rs index 27b6ad93f..2433a040f 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 { diff --git a/key-wallet/src/wallet/initialization.rs b/key-wallet/src/wallet/initialization.rs index db7f3b27e..2d215c175 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] From 0f0978eec193dd460f33aee0b8c22e9a05b9b181 Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Fri, 3 Oct 2025 16:06:03 -0700 Subject: [PATCH 02/11] fix: increase gap limits to match Android and iOS defaults --- key-wallet/src/gap_limit.rs | 8 ++++--- .../managed_account_collection.rs | 23 ++++++++++--------- .../managed_account/managed_account_type.rs | 23 ++++++++++--------- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/key-wallet/src/gap_limit.rs b/key-wallet/src/gap_limit.rs index 649160b8e..b119f80e5 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 = 100; /// Standard gap limit for internal (change) addresses -pub const DEFAULT_INTERNAL_GAP_LIMIT: u32 = 10; +pub const DEFAULT_INTERNAL_GAP_LIMIT: u32 = 100; /// Standard gap limit for CoinJoin addresses -pub const DEFAULT_COINJOIN_GAP_LIMIT: u32 = 10; +pub const DEFAULT_COINJOIN_GAP_LIMIT: u32 = 500; +/// Standard gap limit for CoinJoin addresses +pub const DEFAULT_SPECIAL_GAP_LIMIT: u32 = 20; /// Maximum gap limit to prevent excessive address generation pub const MAX_GAP_LIMIT: u32 = 1000; diff --git a/key-wallet/src/managed_account/managed_account_collection.rs b/key-wallet/src/managed_account/managed_account_collection.rs index ad89ea508..47c8da897 100644 --- a/key-wallet/src/managed_account/managed_account_collection.rs +++ b/key-wallet/src/managed_account/managed_account_collection.rs @@ -13,6 +13,7 @@ use alloc::collections::BTreeMap; use alloc::vec::Vec; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use crate::gap_limit::{DEFAULT_COINJOIN_GAP_LIMIT, DEFAULT_EXTERNAL_GAP_LIMIT, DEFAULT_INTERNAL_GAP_LIMIT, DEFAULT_SPECIAL_GAP_LIMIT}; /// Collection of managed accounts organized by type #[derive(Debug, Clone, Default)] @@ -329,7 +330,7 @@ impl ManagedAccountCollection { let external_pool = AddressPool::new( external_path, AddressPoolType::External, - 20, + DEFAULT_EXTERNAL_GAP_LIMIT, network, key_source, )?; @@ -339,7 +340,7 @@ impl ManagedAccountCollection { let internal_pool = AddressPool::new( internal_path, AddressPoolType::Internal, - 20, + DEFAULT_INTERNAL_GAP_LIMIT, network, key_source, )?; @@ -357,7 +358,7 @@ impl ManagedAccountCollection { index, } => { let addresses = - AddressPool::new(base_path, AddressPoolType::Absent, 20, network, key_source)?; + AddressPool::new(base_path, AddressPoolType::Absent, DEFAULT_COINJOIN_GAP_LIMIT, network, key_source)?; ManagedAccountType::CoinJoin { index, addresses, @@ -365,7 +366,7 @@ impl ManagedAccountCollection { } AccountType::IdentityRegistration => { let addresses = - AddressPool::new(base_path, AddressPoolType::Absent, 20, network, key_source)?; + AddressPool::new(base_path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; ManagedAccountType::IdentityRegistration { addresses, } @@ -374,7 +375,7 @@ impl ManagedAccountCollection { registration_index, } => { let addresses = - AddressPool::new(base_path, AddressPoolType::Absent, 20, network, key_source)?; + AddressPool::new(base_path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; ManagedAccountType::IdentityTopUp { registration_index, addresses, @@ -382,35 +383,35 @@ impl ManagedAccountCollection { } AccountType::IdentityTopUpNotBoundToIdentity => { let addresses = - AddressPool::new(base_path, AddressPoolType::Absent, 20, network, key_source)?; + 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)?; + 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)?; + 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)?; + 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)?; + AddressPool::new(base_path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; ManagedAccountType::ProviderOperatorKeys { addresses, } @@ -419,7 +420,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 61c1eb7e6..f9121f02f 100644 --- a/key-wallet/src/managed_account/managed_account_type.rs +++ b/key-wallet/src/managed_account/managed_account_type.rs @@ -5,6 +5,7 @@ use bincode_derive::{Decode, Encode}; use dashcore::ScriptBuf; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use crate::gap_limit::{DEFAULT_COINJOIN_GAP_LIMIT, DEFAULT_EXTERNAL_GAP_LIMIT, DEFAULT_INTERNAL_GAP_LIMIT, DEFAULT_SPECIAL_GAP_LIMIT}; /// Managed account type with embedded address pools #[derive(Debug, Clone)] @@ -356,7 +357,7 @@ impl ManagedAccountType { let external_pool = AddressPool::new( external_path, AddressPoolType::External, - 20, + DEFAULT_EXTERNAL_GAP_LIMIT, network, key_source, )?; @@ -366,7 +367,7 @@ impl ManagedAccountType { let internal_pool = AddressPool::new( internal_path, AddressPoolType::Internal, - 20, + DEFAULT_INTERNAL_GAP_LIMIT, network, key_source, )?; @@ -385,7 +386,7 @@ impl ManagedAccountType { .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + AddressPool::new(path, AddressPoolType::Absent, DEFAULT_COINJOIN_GAP_LIMIT, network, key_source)?; Ok(Self::CoinJoin { index, @@ -397,7 +398,7 @@ impl ManagedAccountType { .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + AddressPool::new(path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; Ok(Self::IdentityRegistration { addresses: pool, @@ -410,7 +411,7 @@ impl ManagedAccountType { .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + AddressPool::new(path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; Ok(Self::IdentityTopUp { registration_index, @@ -422,7 +423,7 @@ impl ManagedAccountType { .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + AddressPool::new(path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; Ok(Self::IdentityTopUpNotBoundToIdentity { addresses: pool, @@ -433,7 +434,7 @@ impl ManagedAccountType { .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + AddressPool::new(path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; Ok(Self::IdentityInvitation { addresses: pool, @@ -444,7 +445,7 @@ impl ManagedAccountType { .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + AddressPool::new(path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; Ok(Self::ProviderVotingKeys { addresses: pool, @@ -455,7 +456,7 @@ impl ManagedAccountType { .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + AddressPool::new(path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; Ok(Self::ProviderOwnerKeys { addresses: pool, @@ -466,7 +467,7 @@ impl ManagedAccountType { .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); let pool = - AddressPool::new(path, AddressPoolType::Absent, 20, network, key_source)?; + AddressPool::new(path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; Ok(Self::ProviderOperatorKeys { addresses: pool, @@ -479,7 +480,7 @@ impl ManagedAccountType { let pool = AddressPool::new( path, AddressPoolType::AbsentHardened, - 20, + DEFAULT_SPECIAL_GAP_LIMIT, network, key_source, )?; From cc8d49c087ea4b6f409cde6708cf19c93e3b112d Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Fri, 3 Oct 2025 18:57:44 -0700 Subject: [PATCH 03/11] chore: fix special gap limit comment --- key-wallet/src/gap_limit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key-wallet/src/gap_limit.rs b/key-wallet/src/gap_limit.rs index b119f80e5..432e481ee 100644 --- a/key-wallet/src/gap_limit.rs +++ b/key-wallet/src/gap_limit.rs @@ -19,7 +19,7 @@ pub const DEFAULT_INTERNAL_GAP_LIMIT: u32 = 100; /// Standard gap limit for CoinJoin addresses pub const DEFAULT_COINJOIN_GAP_LIMIT: u32 = 500; -/// Standard gap limit for CoinJoin addresses +/// Standard gap limit for special purpose keys (identity, provider keys) pub const DEFAULT_SPECIAL_GAP_LIMIT: u32 = 20; /// Maximum gap limit to prevent excessive address generation pub const MAX_GAP_LIMIT: u32 = 1000; From bbf43a9047865807995570620764910e9a027f5e Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Fri, 3 Oct 2025 18:58:15 -0700 Subject: [PATCH 04/11] fix: add BIP32 account 0 to create_accounts_with_passphrase_from_options --- key-wallet/src/wallet/helper.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/key-wallet/src/wallet/helper.rs b/key-wallet/src/wallet/helper.rs index 2433a040f..6b3da1c8e 100644 --- a/key-wallet/src/wallet/helper.rs +++ b/key-wallet/src/wallet/helper.rs @@ -357,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 { From 971be53b285b4930af34120a823efec9b053f0ea Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Fri, 3 Oct 2025 19:16:34 -0700 Subject: [PATCH 05/11] style: format to pass fmt --- .../src/managed_account/address_pool.rs | 1 + .../managed_account_collection.rs | 77 ++++++++++++++---- .../managed_account/managed_account_type.rs | 78 +++++++++++++++---- 3 files changed, 122 insertions(+), 34 deletions(-) diff --git a/key-wallet/src/managed_account/address_pool.rs b/key-wallet/src/managed_account/address_pool.rs index 5af4f25e9..345fa0f82 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, DEFAULT_SPECIAL_GAP_LIMIT}; use crate::Network; use dashcore::{Address, AddressType, ScriptBuf}; diff --git a/key-wallet/src/managed_account/managed_account_collection.rs b/key-wallet/src/managed_account/managed_account_collection.rs index 47c8da897..303a49611 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; @@ -13,7 +17,6 @@ use alloc::collections::BTreeMap; use alloc::vec::Vec; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::gap_limit::{DEFAULT_COINJOIN_GAP_LIMIT, DEFAULT_EXTERNAL_GAP_LIMIT, DEFAULT_INTERNAL_GAP_LIMIT, DEFAULT_SPECIAL_GAP_LIMIT}; /// Collection of managed accounts organized by type #[derive(Debug, Clone, Default)] @@ -357,16 +360,26 @@ impl ManagedAccountCollection { AccountType::CoinJoin { index, } => { - let addresses = - AddressPool::new(base_path, AddressPoolType::Absent, DEFAULT_COINJOIN_GAP_LIMIT, 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, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; + let addresses = AddressPool::new( + base_path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; ManagedAccountType::IdentityRegistration { addresses, } @@ -374,44 +387,74 @@ impl ManagedAccountCollection { AccountType::IdentityTopUp { registration_index, } => { - let addresses = - AddressPool::new(base_path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, 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, DEFAULT_SPECIAL_GAP_LIMIT, 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, DEFAULT_SPECIAL_GAP_LIMIT, 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, DEFAULT_SPECIAL_GAP_LIMIT, 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, DEFAULT_SPECIAL_GAP_LIMIT, 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, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; + let addresses = AddressPool::new( + base_path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; ManagedAccountType::ProviderOperatorKeys { addresses, } diff --git a/key-wallet/src/managed_account/managed_account_type.rs b/key-wallet/src/managed_account/managed_account_type.rs index f9121f02f..f6b132f15 100644 --- a/key-wallet/src/managed_account/managed_account_type.rs +++ b/key-wallet/src/managed_account/managed_account_type.rs @@ -1,11 +1,15 @@ 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}; use dashcore::ScriptBuf; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::gap_limit::{DEFAULT_COINJOIN_GAP_LIMIT, DEFAULT_EXTERNAL_GAP_LIMIT, DEFAULT_INTERNAL_GAP_LIMIT, DEFAULT_SPECIAL_GAP_LIMIT}; /// Managed account type with embedded address pools #[derive(Debug, Clone)] @@ -385,8 +389,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, DEFAULT_COINJOIN_GAP_LIMIT, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_COINJOIN_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::CoinJoin { index, @@ -397,8 +406,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::IdentityRegistration { addresses: pool, @@ -410,8 +424,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::IdentityTopUp { registration_index, @@ -422,8 +441,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::IdentityTopUpNotBoundToIdentity { addresses: pool, @@ -433,8 +457,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::IdentityInvitation { addresses: pool, @@ -444,8 +473,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::ProviderVotingKeys { addresses: pool, @@ -455,8 +489,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::ProviderOwnerKeys { addresses: pool, @@ -466,8 +505,13 @@ impl ManagedAccountType { let path = account_type .derivation_path(network) .unwrap_or_else(|_| DerivationPath::master()); - let pool = - AddressPool::new(path, AddressPoolType::Absent, DEFAULT_SPECIAL_GAP_LIMIT, network, key_source)?; + let pool = AddressPool::new( + path, + AddressPoolType::Absent, + DEFAULT_SPECIAL_GAP_LIMIT, + network, + key_source, + )?; Ok(Self::ProviderOperatorKeys { addresses: pool, From 7fc5df7b23e604ba0c54bb889c41443662f863a1 Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Fri, 3 Oct 2025 19:33:23 -0700 Subject: [PATCH 06/11] tests: update tests for adding BIP32 to Default wallet --- key-wallet-manager/tests/integration_test.rs | 2 +- .../transaction_checking/transaction_router/tests/routing.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/key-wallet-manager/tests/integration_test.rs b/key-wallet-manager/tests/integration_test.rs index af4881af5..c2ca599fb 100644 --- a/key-wallet-manager/tests/integration_test.rs +++ b/key-wallet-manager/tests/integration_test.rs @@ -65,7 +65,7 @@ fn test_account_management() { // Get accounts from wallet - Default creates 7 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/transaction_checking/transaction_router/tests/routing.rs b/key-wallet/src/transaction_checking/transaction_router/tests/routing.rs index 929b70c5e..d9d769a29 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"); From 430da5b746204f42e5e20877686860e63e0a2a78 Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Fri, 3 Oct 2025 19:38:37 -0700 Subject: [PATCH 07/11] style: add missing , --- key-wallet/src/managed_account/managed_account_collection.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key-wallet/src/managed_account/managed_account_collection.rs b/key-wallet/src/managed_account/managed_account_collection.rs index 303a49611..d4a22391b 100644 --- a/key-wallet/src/managed_account/managed_account_collection.rs +++ b/key-wallet/src/managed_account/managed_account_collection.rs @@ -6,7 +6,7 @@ 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 + DEFAULT_SPECIAL_GAP_LIMIT, }; use crate::managed_account::address_pool::{AddressPool, AddressPoolType}; use crate::managed_account::managed_account_type::ManagedAccountType; From 3cdd496ab9eeb154f2d9c907881115cc6b33eb31 Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Fri, 3 Oct 2025 19:41:19 -0700 Subject: [PATCH 08/11] chore: remove unused import --- key-wallet/src/managed_account/address_pool.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/key-wallet/src/managed_account/address_pool.rs b/key-wallet/src/managed_account/address_pool.rs index 345fa0f82..5af4f25e9 100644 --- a/key-wallet/src/managed_account/address_pool.rs +++ b/key-wallet/src/managed_account/address_pool.rs @@ -15,7 +15,6 @@ 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, DEFAULT_SPECIAL_GAP_LIMIT}; use crate::Network; use dashcore::{Address, AddressType, ScriptBuf}; From 7bec3058f23044308d3b95c64898d99a57cba84c Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Fri, 3 Oct 2025 20:33:28 -0700 Subject: [PATCH 09/11] chore: fix comment in test --- key-wallet-manager/tests/integration_test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key-wallet-manager/tests/integration_test.rs b/key-wallet-manager/tests/integration_test.rs index c2ca599fb..a92bce694 100644 --- a/key-wallet-manager/tests/integration_test.rs +++ b/key-wallet-manager/tests/integration_test.rs @@ -62,7 +62,7 @@ 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(), 9); // 8 from Default + 1 we added From a28239498afa4991a319ed5ed4b07184eff8a42d Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Tue, 7 Oct 2025 10:56:21 -0700 Subject: [PATCH 10/11] fix: lower gap limits based on testing with one old wallet from 2019 --- key-wallet/src/gap_limit.rs | 8 ++++---- key-wallet/src/managed_account/address_pool.rs | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/key-wallet/src/gap_limit.rs b/key-wallet/src/gap_limit.rs index 432e481ee..688d8af4a 100644 --- a/key-wallet/src/gap_limit.rs +++ b/key-wallet/src/gap_limit.rs @@ -11,16 +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 = 100; +pub const DEFAULT_EXTERNAL_GAP_LIMIT: u32 = 30; /// Standard gap limit for internal (change) addresses -pub const DEFAULT_INTERNAL_GAP_LIMIT: u32 = 100; +pub const DEFAULT_INTERNAL_GAP_LIMIT: u32 = 30; /// Standard gap limit for CoinJoin addresses -pub const DEFAULT_COINJOIN_GAP_LIMIT: u32 = 500; +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 = 20; +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 5af4f25e9..9be7d78b1 100644 --- a/key-wallet/src/managed_account/address_pool.rs +++ b/key-wallet/src/managed_account/address_pool.rs @@ -17,6 +17,7 @@ use crate::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey} use crate::error::{Error, Result}; use crate::Network; use dashcore::{Address, AddressType, ScriptBuf}; +use crate::gap_limit::DEFAULT_EXTERNAL_GAP_LIMIT; /// Types of public keys used in the address pool #[derive(Debug, Clone, PartialEq, Eq)] @@ -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, From c65c6e18b782d8a98f612ff905568851ded737ef Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Wed, 8 Oct 2025 14:11:36 -0700 Subject: [PATCH 11/11] style: fix format --- key-wallet/src/managed_account/address_pool.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key-wallet/src/managed_account/address_pool.rs b/key-wallet/src/managed_account/address_pool.rs index 9be7d78b1..cfef783f9 100644 --- a/key-wallet/src/managed_account/address_pool.rs +++ b/key-wallet/src/managed_account/address_pool.rs @@ -15,9 +15,9 @@ 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}; -use crate::gap_limit::DEFAULT_EXTERNAL_GAP_LIMIT; /// Types of public keys used in the address pool #[derive(Debug, Clone, PartialEq, Eq)]