Skip to content

Commit 8f97c4b

Browse files
authored
feat(key-wallet): Add DIP-17 Platform Payment account support (#229)
1 parent 3c9145a commit 8f97c4b

File tree

18 files changed

+613
-15
lines changed

18 files changed

+613
-15
lines changed

key-wallet-ffi/include/key_wallet_ffi.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ typedef enum {
9292
PROVIDER_PLATFORM_KEYS = 10,
9393
DASHPAY_RECEIVING_FUNDS = 11,
9494
DASHPAY_EXTERNAL_ACCOUNT = 12,
95+
/*
96+
Platform Payment address (DIP-17) - Path: m/9'/5'/17'/account'/key_class'/index
97+
*/
98+
PLATFORM_PAYMENT = 13,
9599
} FFIAccountType;
96100

97101
/*

key-wallet-ffi/src/address_pool.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ fn get_managed_account_by_type<'a>(
5959
// DashPay managed accounts are not currently persisted in ManagedAccountCollection
6060
None
6161
}
62+
AccountType::PlatformPayment {
63+
..
64+
} => {
65+
// Platform Payment accounts are not currently persisted in ManagedAccountCollection
66+
None
67+
}
6268
}
6369
}
6470

@@ -102,6 +108,12 @@ fn get_managed_account_by_type_mut<'a>(
102108
// DashPay managed accounts are not currently persisted in ManagedAccountCollection
103109
None
104110
}
111+
AccountType::PlatformPayment {
112+
..
113+
} => {
114+
// Platform Payment accounts are not currently persisted in ManagedAccountCollection
115+
None
116+
}
105117
}
106118
}
107119

key-wallet-ffi/src/managed_account.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ pub unsafe extern "C" fn managed_wallet_get_account(
178178
AccountType::DashpayExternalAccount {
179179
..
180180
} => None,
181+
AccountType::PlatformPayment {
182+
..
183+
} => None,
181184
};
182185

183186
match managed_account {
@@ -527,6 +530,9 @@ pub unsafe extern "C" fn managed_account_get_account_type(
527530
AccountType::DashpayExternalAccount {
528531
..
529532
} => FFIAccountType::DashpayExternalAccount,
533+
AccountType::PlatformPayment {
534+
..
535+
} => FFIAccountType::PlatformPayment,
530536
}
531537
}
532538

@@ -1010,6 +1016,10 @@ pub unsafe extern "C" fn managed_account_get_address_pool(
10101016
addresses,
10111017
..
10121018
} => addresses,
1019+
ManagedAccountType::PlatformPayment {
1020+
addresses,
1021+
..
1022+
} => addresses,
10131023
};
10141024

10151025
let ffi_pool = FFIAddressPool {

key-wallet-ffi/src/transaction_checking.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,27 @@ pub unsafe extern "C" fn managed_wallet_check_transaction(
455455
ffi_accounts.push(ffi_match);
456456
continue;
457457
}
458+
AccountTypeMatch::PlatformPayment {
459+
account_index,
460+
involved_addresses,
461+
..
462+
} => {
463+
// Note: Platform Payment addresses are NOT used in Core chain transactions
464+
// per DIP-17. This branch should never be reached in practice.
465+
let ffi_match = FFIAccountMatch {
466+
account_type: 13, // PlatformPayment
467+
account_index: *account_index,
468+
registration_index: 0,
469+
received: account_match.received,
470+
sent: account_match.sent,
471+
external_addresses_count: involved_addresses.len() as c_uint,
472+
internal_addresses_count: 0,
473+
has_external_addresses: !involved_addresses.is_empty(),
474+
has_internal_addresses: false,
475+
};
476+
ffi_accounts.push(ffi_match);
477+
continue;
478+
}
458479
}
459480
}
460481

key-wallet-ffi/src/types.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ pub enum FFIAccountType {
266266
ProviderPlatformKeys = 10,
267267
DashpayReceivingFunds = 11,
268268
DashpayExternalAccount = 12,
269+
/// Platform Payment address (DIP-17) - Path: m/9'/5'/17'/account'/key_class'/index
270+
PlatformPayment = 13,
269271
}
270272

271273
impl FFIAccountType {
@@ -327,6 +329,14 @@ impl FFIAccountType {
327329
DashPay account creation must use a different API path."
328330
);
329331
}
332+
FFIAccountType::PlatformPayment => {
333+
panic!(
334+
"FFIAccountType::PlatformPayment cannot be converted to AccountType \
335+
without account and key_class indices. The FFI API does not yet \
336+
support passing these values. This is a programming error - \
337+
Platform Payment account creation must use a different API path."
338+
);
339+
}
330340
}
331341
}
332342

@@ -411,6 +421,10 @@ impl FFIAccountType {
411421
&friend_identity_id[..8]
412422
);
413423
}
424+
key_wallet::AccountType::PlatformPayment {
425+
account,
426+
key_class,
427+
} => (FFIAccountType::PlatformPayment, *account, Some(*key_class)),
414428
}
415429
}
416430
}
@@ -433,6 +447,13 @@ mod tests {
433447
let _ = FFIAccountType::DashpayExternalAccount.to_account_type(0);
434448
}
435449

450+
#[test]
451+
#[should_panic(expected = "PlatformPayment cannot be converted to AccountType")]
452+
fn test_platform_payment_to_account_type_panics() {
453+
// This should panic because we cannot construct a Platform Payment account without indices
454+
let _ = FFIAccountType::PlatformPayment.to_account_type(0);
455+
}
456+
436457
#[test]
437458
#[should_panic(expected = "Cannot convert AccountType::DashpayReceivingFunds")]
438459
fn test_dashpay_receiving_funds_from_account_type_panics() {

key-wallet/src/account/account_collection.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ pub struct DashpayAccountKey {
2828
pub friend_identity_id: DashpayContactIdentityId,
2929
}
3030

31+
/// Key for Platform Payment accounts (DIP-17)
32+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
33+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
34+
#[cfg_attr(feature = "bincode", derive(Encode, Decode))]
35+
pub struct PlatformPaymentAccountKey {
36+
/// Account index (hardened)
37+
pub account: u32,
38+
/// Key class (hardened)
39+
pub key_class: u32,
40+
}
41+
3142
/// Collection of accounts organized by type
3243
#[derive(Debug, Clone, Default)]
3344
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -61,6 +72,8 @@ pub struct AccountCollection {
6172
pub dashpay_receival_accounts: BTreeMap<DashpayAccountKey, Account>,
6273
/// DashPay external (watch-only) accounts
6374
pub dashpay_external_accounts: BTreeMap<DashpayAccountKey, Account>,
75+
/// Platform Payment accounts (DIP-17)
76+
pub platform_payment_accounts: BTreeMap<PlatformPaymentAccountKey, Account>,
6477
}
6578

6679
impl AccountCollection {
@@ -82,6 +95,7 @@ impl AccountCollection {
8295
provider_platform_keys: None,
8396
dashpay_receival_accounts: BTreeMap::new(),
8497
dashpay_external_accounts: BTreeMap::new(),
98+
platform_payment_accounts: BTreeMap::new(),
8599
}
86100
}
87101

@@ -157,6 +171,16 @@ impl AccountCollection {
157171
};
158172
self.dashpay_external_accounts.insert(key, account);
159173
}
174+
AccountType::PlatformPayment {
175+
account: acc_index,
176+
key_class,
177+
} => {
178+
let key = PlatformPaymentAccountKey {
179+
account: *acc_index,
180+
key_class: *key_class,
181+
};
182+
self.platform_payment_accounts.insert(key, account);
183+
}
160184
}
161185
Ok(())
162186
}
@@ -240,6 +264,16 @@ impl AccountCollection {
240264
};
241265
self.dashpay_external_accounts.contains_key(&key)
242266
}
267+
AccountType::PlatformPayment {
268+
account,
269+
key_class,
270+
} => {
271+
let key = PlatformPaymentAccountKey {
272+
account: *account,
273+
key_class: *key_class,
274+
};
275+
self.platform_payment_accounts.contains_key(&key)
276+
}
243277
}
244278
}
245279

@@ -293,6 +327,16 @@ impl AccountCollection {
293327
};
294328
self.dashpay_external_accounts.get(&key)
295329
}
330+
AccountType::PlatformPayment {
331+
account,
332+
key_class,
333+
} => {
334+
let key = PlatformPaymentAccountKey {
335+
account,
336+
key_class,
337+
};
338+
self.platform_payment_accounts.get(&key)
339+
}
296340
}
297341
}
298342

@@ -346,6 +390,16 @@ impl AccountCollection {
346390
};
347391
self.dashpay_external_accounts.get_mut(&key)
348392
}
393+
AccountType::PlatformPayment {
394+
account,
395+
key_class,
396+
} => {
397+
let key = PlatformPaymentAccountKey {
398+
account,
399+
key_class,
400+
};
401+
self.platform_payment_accounts.get_mut(&key)
402+
}
349403
}
350404
}
351405

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

439+
accounts.extend(self.dashpay_receival_accounts.values());
440+
accounts.extend(self.dashpay_external_accounts.values());
441+
accounts.extend(self.platform_payment_accounts.values());
442+
385443
accounts
386444
}
387445

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

479+
accounts.extend(self.dashpay_receival_accounts.values_mut());
480+
accounts.extend(self.dashpay_external_accounts.values_mut());
481+
accounts.extend(self.platform_payment_accounts.values_mut());
482+
421483
accounts
422484
}
423485

key-wallet/src/account/account_type.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ pub enum AccountType {
8383
/// Our contact's identity id (32 bytes)
8484
friend_identity_id: [u8; 32],
8585
},
86+
/// Platform Payment account (DIP-17)
87+
/// Path: m/9'/coin_type'/17'/account'/key_class'/index
88+
/// Address encoding (DIP-18 bech32m) is handled by the Platform repo.
89+
PlatformPayment {
90+
/// Account index (hardened) - default 0'
91+
account: u32,
92+
/// Key class (hardened) - default 0', 1' reserved for change-like segregation
93+
key_class: u32,
94+
},
8695
}
8796

8897
impl From<AccountType> for AccountTypeToCheck {
@@ -116,6 +125,9 @@ impl From<AccountType> for AccountTypeToCheck {
116125
AccountType::DashpayExternalAccount {
117126
..
118127
} => AccountTypeToCheck::DashpayExternalAccount,
128+
AccountType::PlatformPayment {
129+
..
130+
} => AccountTypeToCheck::PlatformPayment,
119131
}
120132
}
121133
}
@@ -140,6 +152,10 @@ impl AccountType {
140152
index,
141153
..
142154
} => Some(*index),
155+
Self::PlatformPayment {
156+
account,
157+
..
158+
} => Some(*account),
143159
// Identity and provider types don't have account indices
144160
Self::IdentityRegistration
145161
| Self::IdentityTopUp {
@@ -208,6 +224,9 @@ impl AccountType {
208224
Self::DashpayExternalAccount {
209225
..
210226
} => DerivationPathReference::ContactBasedFundsExternal,
227+
Self::PlatformPayment {
228+
..
229+
} => DerivationPathReference::PlatformPayment,
211230
}
212231
}
213232

@@ -392,6 +411,30 @@ impl AccountType {
392411
});
393412
Ok(path)
394413
}
414+
Self::PlatformPayment {
415+
account,
416+
key_class,
417+
} => {
418+
// DIP-17: m/9'/coin_type'/17'/account'/key_class'
419+
// The leaf index is non-hardened and appended during address generation
420+
let mut path = match network {
421+
Network::Dash => {
422+
DerivationPath::from(crate::dip9::PLATFORM_PAYMENT_ROOT_PATH_MAINNET)
423+
}
424+
Network::Testnet => {
425+
DerivationPath::from(crate::dip9::PLATFORM_PAYMENT_ROOT_PATH_TESTNET)
426+
}
427+
_ => return Err(crate::error::Error::InvalidNetwork),
428+
};
429+
path.push(
430+
ChildNumber::from_hardened_idx(*account).map_err(crate::error::Error::Bip32)?,
431+
);
432+
path.push(
433+
ChildNumber::from_hardened_idx(*key_class)
434+
.map_err(crate::error::Error::Bip32)?,
435+
);
436+
Ok(path)
437+
}
395438
}
396439
}
397440
}

0 commit comments

Comments
 (0)