Problem
Dash Evo Tool (DET) derives BlockchainIdentities addresses at m/9'/coinType'/5'/subfeature'/index (non-hardened leaf) for identity authentication keys. These addresses are currently bootstrapped by DET directly — not through the SDK's WalletManager — so they are invisible to SPV's bloom filter and never receive UTXO/transaction notifications.
WalletAccountCreationOptions::Default creates Identity Registration, Invitation, TopUp, Provider, BIP44, BIP32, CoinJoin, AssetLock, and PlatformPayment accounts — but not BlockchainIdentities.
Expected Behavior
When a wallet is created with WalletAccountCreationOptions::Default, it should also create BlockchainIdentities accounts for subfeatures 0–3 (ECDSA, ECDSA_HASH160, BLS, BLS_HASH160). Their addresses should appear in monitored_addresses() so SPV bloom filters cover them automatically.
Required Changes
1. Add BlockchainIdentities variant to AccountType
File: key-wallet/src/account/account_type.rs
Add a new variant:
/// BlockchainIdentities authentication keys (m/9'/coinType'/5'/subfeature'/index)
/// Used for identity authentication proofs on Platform.
/// Subfeatures: 0=ECDSA, 1=ECDSA_HASH160, 2=BLS, 3=BLS_HASH160
/// Leaf index is non-hardened (unlike Provider keys which use hardened leaves).
BlockchainIdentities {
/// Subfeature index (0–3 for different key types)
subfeature: u32,
},
Implement derivation_path():
Self::BlockchainIdentities { subfeature } => {
// m/9'/coinType'/5'/subfeature'
Ok(DerivationPath::from(vec![
ChildNumber::from_hardened_idx(9).map_err(crate::error::Error::Bip32)?,
ChildNumber::from_hardened_idx(coin_type).map_err(crate::error::Error::Bip32)?,
ChildNumber::from_hardened_idx(5).map_err(crate::error::Error::Bip32)?,
ChildNumber::from_hardened_idx(*subfeature).map_err(crate::error::Error::Bip32)?,
]))
}
Implement derivation_path_reference():
Self::BlockchainIdentities { .. } => DerivationPathReference::BlockchainIdentities,
2. Add ManagedAccountType::BlockchainIdentities variant
File: key-wallet/src/wallet/managed_wallet_info/managed_account_type.rs (or equivalent)
Follow the ProviderVotingKeys pattern — single AddressPool with AddressPoolType::Absent (non-hardened leaf indices). Bootstrap ~20 addresses per subfeature.
3. Include in WalletAccountCreationOptions::Default
File: key-wallet/src/wallet/helper.rs (in create_special_purpose_accounts())
When processing Default, also create BlockchainIdentities accounts for subfeatures 0–3.
4. Add AccountTypeToCheck::BlockchainIdentities
File: key-wallet/src/transaction_checking/transaction_router/mod.rs
Add a BlockchainIdentities variant and implement TryFrom<AccountType> / TryFrom<ManagedAccountType> conversions.
5. Verify monitored_addresses() includes them
After the above changes, monitored_addresses() should automatically aggregate BlockchainIdentities addresses since it iterates all_accounts(). Verify this works.
Context
Testing
- Load a wallet with
WalletAccountCreationOptions::Default → verify BlockchainIdentities accounts are created for subfeatures 0–3
- Verify their addresses appear in
monitored_addresses()
- Send funds to a BlockchainIdentities address → verify SPV detects the UTXO via bloom filter
- Verify existing account types still work correctly (no regressions)
AI Implementation Prompt
You are implementing a new BlockchainIdentities account type in the key-wallet and key-wallet-manager crates. Use ProviderVotingKeys as the reference pattern throughout — it's the closest analog.
Step-by-step:
-
key-wallet/src/account/account_type.rs — Add BlockchainIdentities { subfeature: u32 } variant to AccountType. Implement derivation_path() returning m/9'/coinType'/5'/subfeature' (all hardened segments). Implement derivation_path_reference() returning DerivationPathReference::BlockchainIdentities. Add to any Display, Debug, serialization, or match-exhaustiveness blocks.
-
key-wallet/src/wallet/managed_wallet_info/managed_account_type.rs (or equivalent managed account file) — Add BlockchainIdentities { subfeature: u32, addresses: AddressPool } variant to ManagedAccountType. Use AddressPoolType::Absent (non-hardened leaf) following the ProviderVotingKeys pattern. Implement all trait methods (all_addresses(), account_type(), etc.) by following existing Provider variants.
-
key-wallet/src/wallet/helper.rs — In create_special_purpose_accounts(), add creation of BlockchainIdentities accounts for subfeatures 0, 1, 2, 3. Bootstrap with DEFAULT_SPECIAL_GAP_LIMIT addresses per subfeature.
-
key-wallet/src/transaction_checking/transaction_router/mod.rs — Add BlockchainIdentities to AccountTypeToCheck. Add mapping in TryFrom<AccountType> and TryFrom<ManagedAccountType> (should succeed, not error like PlatformPayment).
-
Verify exhaustiveness — cargo check to find any remaining match arms that need updating. Fix all.
-
Test — Add unit tests verifying: derivation path is correct for each subfeature, derivation_path_reference() returns BlockchainIdentities, accounts are created by Default options, addresses appear in monitored list.
Critical detail: BlockchainIdentities use non-hardened leaf indices for key derivation (unlike Provider keys which use hardened leaves). The account-level path segments (m/9'/coinType'/5'/subfeature') are all hardened, but the address pool must derive child keys with ChildNumber::Normal { index }. Using AddressPoolType::Absent (not AbsentHardened) achieves this.
🤖 Co-authored by Claudius the Magnificent AI Agent
Problem
Dash Evo Tool (DET) derives BlockchainIdentities addresses at
m/9'/coinType'/5'/subfeature'/index(non-hardened leaf) for identity authentication keys. These addresses are currently bootstrapped by DET directly — not through the SDK'sWalletManager— so they are invisible to SPV's bloom filter and never receive UTXO/transaction notifications.WalletAccountCreationOptions::Defaultcreates Identity Registration, Invitation, TopUp, Provider, BIP44, BIP32, CoinJoin, AssetLock, and PlatformPayment accounts — but not BlockchainIdentities.Expected Behavior
When a wallet is created with
WalletAccountCreationOptions::Default, it should also createBlockchainIdentitiesaccounts for subfeatures 0–3 (ECDSA, ECDSA_HASH160, BLS, BLS_HASH160). Their addresses should appear inmonitored_addresses()so SPV bloom filters cover them automatically.Required Changes
1. Add
BlockchainIdentitiesvariant toAccountTypeFile:
key-wallet/src/account/account_type.rsAdd a new variant:
Implement
derivation_path():Implement
derivation_path_reference():2. Add
ManagedAccountType::BlockchainIdentitiesvariantFile:
key-wallet/src/wallet/managed_wallet_info/managed_account_type.rs(or equivalent)Follow the
ProviderVotingKeyspattern — singleAddressPoolwithAddressPoolType::Absent(non-hardened leaf indices). Bootstrap ~20 addresses per subfeature.3. Include in
WalletAccountCreationOptions::DefaultFile:
key-wallet/src/wallet/helper.rs(increate_special_purpose_accounts())When processing
Default, also createBlockchainIdentitiesaccounts for subfeatures 0–3.4. Add
AccountTypeToCheck::BlockchainIdentitiesFile:
key-wallet/src/transaction_checking/transaction_router/mod.rsAdd a
BlockchainIdentitiesvariant and implementTryFrom<AccountType>/TryFrom<ManagedAccountType>conversions.5. Verify
monitored_addresses()includes themAfter the above changes,
monitored_addresses()should automatically aggregate BlockchainIdentities addresses since it iteratesall_accounts(). Verify this works.Context
DerivationPathReference::BlockchainIdentities(value 3) already exists inkey-wallet/src/dip9.rsIDENTITY_AUTHENTICATION_PATH_MAINNET=m/9'/5'/5'/0',IDENTITY_AUTHENTICATION_PATH_TESTNET=m/9'/1'/5'/0'ProviderVotingKeys— singleAddressPool,AddressPoolType::Absent,DEFAULT_SPECIAL_GAP_LIMITspv_account_metadata()inwallet_lifecycle.rsneeds a corresponding match arm (DET-side follow-up)Testing
WalletAccountCreationOptions::Default→ verifyBlockchainIdentitiesaccounts are created for subfeatures 0–3monitored_addresses()AI Implementation Prompt
You are implementing a new
BlockchainIdentitiesaccount type in thekey-walletandkey-wallet-managercrates. UseProviderVotingKeysas the reference pattern throughout — it's the closest analog.Step-by-step:
key-wallet/src/account/account_type.rs— AddBlockchainIdentities { subfeature: u32 }variant toAccountType. Implementderivation_path()returningm/9'/coinType'/5'/subfeature'(all hardened segments). Implementderivation_path_reference()returningDerivationPathReference::BlockchainIdentities. Add to anyDisplay,Debug, serialization, or match-exhaustiveness blocks.key-wallet/src/wallet/managed_wallet_info/managed_account_type.rs(or equivalent managed account file) — AddBlockchainIdentities { subfeature: u32, addresses: AddressPool }variant toManagedAccountType. UseAddressPoolType::Absent(non-hardened leaf) following theProviderVotingKeyspattern. Implement all trait methods (all_addresses(),account_type(), etc.) by following existing Provider variants.key-wallet/src/wallet/helper.rs— Increate_special_purpose_accounts(), add creation ofBlockchainIdentitiesaccounts for subfeatures 0, 1, 2, 3. Bootstrap withDEFAULT_SPECIAL_GAP_LIMITaddresses per subfeature.key-wallet/src/transaction_checking/transaction_router/mod.rs— AddBlockchainIdentitiestoAccountTypeToCheck. Add mapping inTryFrom<AccountType>andTryFrom<ManagedAccountType>(should succeed, not error like PlatformPayment).Verify exhaustiveness —
cargo checkto find any remaining match arms that need updating. Fix all.Test — Add unit tests verifying: derivation path is correct for each subfeature,
derivation_path_reference()returnsBlockchainIdentities, accounts are created by Default options, addresses appear in monitored list.Critical detail: BlockchainIdentities use non-hardened leaf indices for key derivation (unlike Provider keys which use hardened leaves). The account-level path segments (
m/9'/coinType'/5'/subfeature') are all hardened, but the address pool must derive child keys withChildNumber::Normal { index }. UsingAddressPoolType::Absent(notAbsentHardened) achieves this.🤖 Co-authored by Claudius the Magnificent AI Agent