Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions key-wallet-ffi/include/key_wallet_ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ typedef enum {
PROVIDER_PLATFORM_KEYS = 10,
DASHPAY_RECEIVING_FUNDS = 11,
DASHPAY_EXTERNAL_ACCOUNT = 12,
/*
Platform Payment address (DIP-17) - Path: m/9'/5'/17'/account'/key_class'/index
*/
PLATFORM_PAYMENT = 13,
} FFIAccountType;

/*
Expand Down
12 changes: 12 additions & 0 deletions key-wallet-ffi/src/address_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ fn get_managed_account_by_type<'a>(
// DashPay managed accounts are not currently persisted in ManagedAccountCollection
None
}
AccountType::PlatformPayment {
..
} => {
// Platform Payment accounts are not currently persisted in ManagedAccountCollection
None
}
}
}

Expand Down Expand Up @@ -102,6 +108,12 @@ fn get_managed_account_by_type_mut<'a>(
// DashPay managed accounts are not currently persisted in ManagedAccountCollection
None
}
AccountType::PlatformPayment {
..
} => {
// Platform Payment accounts are not currently persisted in ManagedAccountCollection
None
}
}
}

Expand Down
10 changes: 10 additions & 0 deletions key-wallet-ffi/src/managed_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ pub unsafe extern "C" fn managed_wallet_get_account(
AccountType::DashpayExternalAccount {
..
} => None,
AccountType::PlatformPayment {
..
} => None,
};

match managed_account {
Expand Down Expand Up @@ -527,6 +530,9 @@ pub unsafe extern "C" fn managed_account_get_account_type(
AccountType::DashpayExternalAccount {
..
} => FFIAccountType::DashpayExternalAccount,
AccountType::PlatformPayment {
..
} => FFIAccountType::PlatformPayment,
}
}

Expand Down Expand Up @@ -1010,6 +1016,10 @@ pub unsafe extern "C" fn managed_account_get_address_pool(
addresses,
..
} => addresses,
ManagedAccountType::PlatformPayment {
addresses,
..
} => addresses,
};

let ffi_pool = FFIAddressPool {
Expand Down
21 changes: 21 additions & 0 deletions key-wallet-ffi/src/transaction_checking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,27 @@ pub unsafe extern "C" fn managed_wallet_check_transaction(
ffi_accounts.push(ffi_match);
continue;
}
AccountTypeMatch::PlatformPayment {
account_index,
involved_addresses,
..
} => {
// Note: Platform Payment addresses are NOT used in Core chain transactions
// per DIP-17. This branch should never be reached in practice.
let ffi_match = FFIAccountMatch {
account_type: 13, // PlatformPayment
account_index: *account_index,
registration_index: 0,
received: account_match.received,
sent: account_match.sent,
external_addresses_count: involved_addresses.len() as c_uint,
internal_addresses_count: 0,
has_external_addresses: !involved_addresses.is_empty(),
has_internal_addresses: false,
};
ffi_accounts.push(ffi_match);
continue;
}
}
}

Expand Down
21 changes: 21 additions & 0 deletions key-wallet-ffi/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ pub enum FFIAccountType {
ProviderPlatformKeys = 10,
DashpayReceivingFunds = 11,
DashpayExternalAccount = 12,
/// Platform Payment address (DIP-17) - Path: m/9'/5'/17'/account'/key_class'/index
PlatformPayment = 13,
}

impl FFIAccountType {
Expand Down Expand Up @@ -327,6 +329,14 @@ impl FFIAccountType {
DashPay account creation must use a different API path."
);
}
FFIAccountType::PlatformPayment => {
panic!(
"FFIAccountType::PlatformPayment cannot be converted to AccountType \
without account and key_class indices. The FFI API does not yet \
support passing these values. This is a programming error - \
Platform Payment account creation must use a different API path."
);
}
}
}

Expand Down Expand Up @@ -411,6 +421,10 @@ impl FFIAccountType {
&friend_identity_id[..8]
);
}
key_wallet::AccountType::PlatformPayment {
account,
key_class,
} => (FFIAccountType::PlatformPayment, *account, Some(*key_class)),
}
}
}
Expand All @@ -433,6 +447,13 @@ mod tests {
let _ = FFIAccountType::DashpayExternalAccount.to_account_type(0);
}

#[test]
#[should_panic(expected = "PlatformPayment cannot be converted to AccountType")]
fn test_platform_payment_to_account_type_panics() {
// This should panic because we cannot construct a Platform Payment account without indices
let _ = FFIAccountType::PlatformPayment.to_account_type(0);
}

#[test]
#[should_panic(expected = "Cannot convert AccountType::DashpayReceivingFunds")]
fn test_dashpay_receiving_funds_from_account_type_panics() {
Expand Down
62 changes: 62 additions & 0 deletions key-wallet/src/account/account_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ pub struct DashpayAccountKey {
pub friend_identity_id: DashpayContactIdentityId,
}

/// Key for Platform Payment accounts (DIP-17)
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "bincode", derive(Encode, Decode))]
pub struct PlatformPaymentAccountKey {
/// Account index (hardened)
pub account: u32,
/// Key class (hardened)
pub key_class: u32,
}

/// Collection of accounts organized by type
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
Expand Down Expand Up @@ -61,6 +72,8 @@ pub struct AccountCollection {
pub dashpay_receival_accounts: BTreeMap<DashpayAccountKey, Account>,
/// DashPay external (watch-only) accounts
pub dashpay_external_accounts: BTreeMap<DashpayAccountKey, Account>,
/// Platform Payment accounts (DIP-17)
pub platform_payment_accounts: BTreeMap<PlatformPaymentAccountKey, Account>,
}

impl AccountCollection {
Expand All @@ -82,6 +95,7 @@ impl AccountCollection {
provider_platform_keys: None,
dashpay_receival_accounts: BTreeMap::new(),
dashpay_external_accounts: BTreeMap::new(),
platform_payment_accounts: BTreeMap::new(),
}
}

Expand Down Expand Up @@ -157,6 +171,16 @@ impl AccountCollection {
};
self.dashpay_external_accounts.insert(key, account);
}
AccountType::PlatformPayment {
account: acc_index,
key_class,
} => {
let key = PlatformPaymentAccountKey {
account: *acc_index,
key_class: *key_class,
};
self.platform_payment_accounts.insert(key, account);
}
}
Ok(())
}
Expand Down Expand Up @@ -240,6 +264,16 @@ impl AccountCollection {
};
self.dashpay_external_accounts.contains_key(&key)
}
AccountType::PlatformPayment {
account,
key_class,
} => {
let key = PlatformPaymentAccountKey {
account: *account,
key_class: *key_class,
};
self.platform_payment_accounts.contains_key(&key)
}
}
}

Expand Down Expand Up @@ -293,6 +327,16 @@ impl AccountCollection {
};
self.dashpay_external_accounts.get(&key)
}
AccountType::PlatformPayment {
account,
key_class,
} => {
let key = PlatformPaymentAccountKey {
account,
key_class,
};
self.platform_payment_accounts.get(&key)
}
}
}

Expand Down Expand Up @@ -346,6 +390,16 @@ impl AccountCollection {
};
self.dashpay_external_accounts.get_mut(&key)
}
AccountType::PlatformPayment {
account,
key_class,
} => {
let key = PlatformPaymentAccountKey {
account,
key_class,
};
self.platform_payment_accounts.get_mut(&key)
}
}
}

Expand Down Expand Up @@ -382,6 +436,10 @@ impl AccountCollection {
// Note: provider_operator_keys (BLS) and provider_platform_keys (EdDSA) are excluded
// Use specific methods to access them

accounts.extend(self.dashpay_receival_accounts.values());
accounts.extend(self.dashpay_external_accounts.values());
accounts.extend(self.platform_payment_accounts.values());

accounts
}

Expand Down Expand Up @@ -418,6 +476,10 @@ impl AccountCollection {
// Note: provider_operator_keys (BLS) and provider_platform_keys (EdDSA) are excluded
// Use specific methods to access them

accounts.extend(self.dashpay_receival_accounts.values_mut());
accounts.extend(self.dashpay_external_accounts.values_mut());
accounts.extend(self.platform_payment_accounts.values_mut());

accounts
}

Expand Down
43 changes: 43 additions & 0 deletions key-wallet/src/account/account_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ pub enum AccountType {
/// Our contact's identity id (32 bytes)
friend_identity_id: [u8; 32],
},
/// Platform Payment account (DIP-17)
/// Path: m/9'/coin_type'/17'/account'/key_class'/index
/// Address encoding (DIP-18 bech32m) is handled by the Platform repo.
PlatformPayment {
/// Account index (hardened) - default 0'
account: u32,
/// Key class (hardened) - default 0', 1' reserved for change-like segregation
key_class: u32,
},
}

impl From<AccountType> for AccountTypeToCheck {
Expand Down Expand Up @@ -116,6 +125,9 @@ impl From<AccountType> for AccountTypeToCheck {
AccountType::DashpayExternalAccount {
..
} => AccountTypeToCheck::DashpayExternalAccount,
AccountType::PlatformPayment {
..
} => AccountTypeToCheck::PlatformPayment,
}
}
}
Expand All @@ -140,6 +152,10 @@ impl AccountType {
index,
..
} => Some(*index),
Self::PlatformPayment {
account,
..
} => Some(*account),
// Identity and provider types don't have account indices
Self::IdentityRegistration
| Self::IdentityTopUp {
Expand Down Expand Up @@ -208,6 +224,9 @@ impl AccountType {
Self::DashpayExternalAccount {
..
} => DerivationPathReference::ContactBasedFundsExternal,
Self::PlatformPayment {
..
} => DerivationPathReference::PlatformPayment,
}
}

Expand Down Expand Up @@ -392,6 +411,30 @@ impl AccountType {
});
Ok(path)
}
Self::PlatformPayment {
account,
key_class,
} => {
// DIP-17: m/9'/coin_type'/17'/account'/key_class'
// The leaf index is non-hardened and appended during address generation
let mut path = match network {
Network::Dash => {
DerivationPath::from(crate::dip9::PLATFORM_PAYMENT_ROOT_PATH_MAINNET)
}
Network::Testnet => {
DerivationPath::from(crate::dip9::PLATFORM_PAYMENT_ROOT_PATH_TESTNET)
}
_ => return Err(crate::error::Error::InvalidNetwork),
};
path.push(
ChildNumber::from_hardened_idx(*account).map_err(crate::error::Error::Bip32)?,
);
path.push(
ChildNumber::from_hardened_idx(*key_class)
.map_err(crate::error::Error::Bip32)?,
);
Ok(path)
}
}
}
}
Loading