Skip to content

feat(key-wallet): Add BlockchainIdentities account type so SPV monitors identity authentication addresses #553

@lklimek

Description

@lklimek

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:

  1. 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.

  2. 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.

  3. 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.

  4. 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).

  5. Verify exhaustivenesscargo check to find any remaining match arms that need updating. Fix all.

  6. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions