Skip to content
Draft
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
45 changes: 45 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,11 @@ typedef enum {
Platform Payment address (DIP-17) - Path: m/9'/5'/17'/account'/key_class'/index
*/
PLATFORM_PAYMENT = 13,
/*
Platform Address Funding (DIP-17) - Path: m/9'/5'/17'/0'/2'/index
For asset lock funding keys (fixed account=0', key_class=2')
*/
PLATFORM_ADDRESS_FUNDING = 14,
} FFIAccountType;

/*
Expand Down Expand Up @@ -637,6 +642,10 @@ typedef struct {
Whether provider platform keys account exists
*/
bool has_provider_platform_keys;
/*
Whether platform address funding account exists (DIP-17)
*/
bool has_platform_address_funding;
} FFIManagedAccountCollectionSummary;

/*
Expand Down Expand Up @@ -1927,6 +1936,18 @@ bool derivation_identity_authentication_path(FFINetwork network,
FFIError *error)
;

/*
Derive platform address funding path (m/9'/5'/17'/0'/2'/index)
DIP-17: Used for asset lock funding keys
*/

bool derivation_platform_address_funding_path(FFINetwork network,
unsigned int index,
char *path_out,
size_t path_max_len,
FFIError *error)
;

/*
Derive private key for a specific path from seed

Expand Down Expand Up @@ -2954,6 +2975,30 @@ void *managed_account_collection_get_provider_platform_keys(const FFIManagedAcco
bool managed_account_collection_has_provider_platform_keys(const FFIManagedAccountCollection *collection)
;

/*
Get the platform address funding account if it exists in managed collection
DIP-17: Path: m/9'/coin_type'/17'/0'/2'/index (for asset lock funding)

# Safety

- `collection` must be a valid pointer to an FFIManagedAccountCollection
- The returned pointer must be freed with `managed_account_free` when no longer needed
*/

FFIManagedAccount *managed_account_collection_get_platform_address_funding(const FFIManagedAccountCollection *collection)
;

/*
Check if platform address funding account exists in managed collection

# Safety

- `collection` must be a valid pointer to an FFIManagedAccountCollection
*/

bool managed_account_collection_has_platform_address_funding(const FFIManagedAccountCollection *collection)
;

/*
Get the total number of accounts in the managed collection

Expand Down
2 changes: 2 additions & 0 deletions key-wallet-ffi/src/address_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ fn get_managed_account_by_type<'a>(
// Platform Payment accounts are not currently persisted in ManagedAccountCollection
None
}
AccountType::PlatformAddressFunding => collection.platform_address_funding.as_ref(),
}
}

Expand Down Expand Up @@ -113,6 +114,7 @@ fn get_managed_account_by_type_mut<'a>(
// Platform Payment accounts are not currently persisted in ManagedAccountCollection
None
}
AccountType::PlatformAddressFunding => collection.platform_address_funding.as_mut(),
}
}

Expand Down
58 changes: 58 additions & 0 deletions key-wallet-ffi/src/derivation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub enum FFIDerivationPathType {
PathBlockchainIdentityCreditInvitationFunding = 13,
PathProviderPlatformNodeKeys = 14,
PathCoinJoin = 15,
PathPlatformPayment = 16,
PathPlatformAddressFunding = 17,
PathRoot = 255,
}

Expand Down Expand Up @@ -424,6 +426,62 @@ pub extern "C" fn derivation_identity_authentication_path(
true
}

/// Derive platform address funding path (m/9'/5'/17'/0'/2'/index)
/// DIP-17: Used for asset lock funding keys
#[no_mangle]
pub extern "C" fn derivation_platform_address_funding_path(
network: FFINetwork,
index: c_uint,
path_out: *mut c_char,
path_max_len: usize,
error: *mut FFIError,
) -> bool {
if path_out.is_null() {
FFIError::set_error(
error,
FFIErrorCode::InvalidInput,
"Path output buffer is null".to_string(),
);
return false;
}

let network_rust: key_wallet::Network = network.into();

use key_wallet::bip32::DerivationPath;
let derivation = DerivationPath::platform_address_funding_path(network_rust, index);

let path_str = format!("{}", derivation);

let c_string = match CString::new(path_str) {
Ok(s) => s,
Err(_) => {
FFIError::set_error(
error,
FFIErrorCode::AllocationFailed,
"Failed to create C string".to_string(),
);
return false;
}
};

let bytes = c_string.as_bytes_with_nul();
if bytes.len() > path_max_len {
FFIError::set_error(
error,
FFIErrorCode::InvalidInput,
format!("Path too long: {} > {}", bytes.len(), path_max_len),
);
return false;
}

unsafe {
ptr::copy_nonoverlapping(bytes.as_ptr(), path_out.cast::<u8>(), bytes.len());
}

FFIError::set_success(error);
true
}

/// Derive private key for a specific path from seed
///
/// # Safety
Expand Down
8 changes: 8 additions & 0 deletions key-wallet-ffi/src/managed_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ pub unsafe extern "C" fn managed_wallet_get_account(
AccountType::PlatformPayment {
..
} => None,
AccountType::PlatformAddressFunding => {
managed_collection.platform_address_funding.as_ref()
}
};

match managed_account {
Expand Down Expand Up @@ -474,6 +477,7 @@ pub unsafe extern "C" fn managed_account_get_account_type(
AccountType::PlatformPayment {
..
} => FFIAccountType::PlatformPayment,
AccountType::PlatformAddressFunding => FFIAccountType::PlatformAddressFunding,
}
}

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

let ffi_pool = FFIAddressPool {
Expand Down
52 changes: 52 additions & 0 deletions key-wallet-ffi/src/managed_account_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ pub struct FFIManagedAccountCollectionSummary {
#[cfg(feature = "eddsa")]
/// Whether provider platform keys account exists
pub has_provider_platform_keys: bool,

/// Whether platform address funding account exists (DIP-17)
pub has_platform_address_funding: bool,
}

/// Get managed account collection for a specific network from wallet manager
Expand Down Expand Up @@ -725,6 +728,50 @@ pub unsafe extern "C" fn managed_account_collection_has_provider_platform_keys(
}
}

// Platform Address Funding account functions

/// Get the platform address funding account if it exists in managed collection
/// DIP-17: Path: m/9'/coin_type'/17'/0'/2'/index (for asset lock funding)
///
/// # Safety
///
/// - `collection` must be a valid pointer to an FFIManagedAccountCollection
/// - The returned pointer must be freed with `managed_account_free` when no longer needed
#[no_mangle]
pub unsafe extern "C" fn managed_account_collection_get_platform_address_funding(
collection: *const FFIManagedAccountCollection,
) -> *mut FFIManagedAccount {
if collection.is_null() {
return ptr::null_mut();
}

let collection = &*collection;
match &collection.collection.platform_address_funding {
Some(account) => {
let ffi_account = FFIManagedAccount::new(account);
Box::into_raw(Box::new(ffi_account))
}
None => ptr::null_mut(),
}
}

/// Check if platform address funding account exists in managed collection
///
/// # Safety
///
/// - `collection` must be a valid pointer to an FFIManagedAccountCollection
#[no_mangle]
pub unsafe extern "C" fn managed_account_collection_has_platform_address_funding(
collection: *const FFIManagedAccountCollection,
) -> bool {
if collection.is_null() {
return false;
}

let collection = &*collection;
collection.collection.platform_address_funding.is_some()
}

// Utility functions

/// Get the total number of accounts in the managed collection
Expand Down Expand Up @@ -906,6 +953,10 @@ pub unsafe extern "C" fn managed_account_collection_summary(
summary_parts.push("• Provider Platform Keys Account (EdDSA)".to_string());
}

if collection.collection.platform_address_funding.is_some() {
summary_parts.push("• Platform Address Funding Account (DIP-17)".to_string());
}

// If there are no accounts at all
if summary_parts.len() == 1 {
summary_parts.push("No accounts configured".to_string());
Expand Down Expand Up @@ -1015,6 +1066,7 @@ pub unsafe extern "C" fn managed_account_collection_summary_data(
has_provider_operator_keys: collection.collection.provider_operator_keys.is_some(),
#[cfg(feature = "eddsa")]
has_provider_platform_keys: collection.collection.provider_platform_keys.is_some(),
has_platform_address_funding: collection.collection.platform_address_funding.is_some(),
};

Box::into_raw(Box::new(summary))
Expand Down
18 changes: 18 additions & 0 deletions key-wallet-ffi/src/transaction_checking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,24 @@ pub unsafe extern "C" fn managed_wallet_check_transaction(
ffi_accounts.push(ffi_match);
continue;
}
AccountTypeMatch::PlatformAddressFunding {
involved_addresses,
} => {
// PlatformAddressFunding is used for asset lock transactions (funding)
let ffi_match = FFIAccountMatch {
account_type: 14, // PlatformAddressFunding
account_index: 0,
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
9 changes: 9 additions & 0 deletions key-wallet-ffi/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ pub enum FFIAccountType {
DashpayExternalAccount = 12,
/// Platform Payment address (DIP-17) - Path: m/9'/5'/17'/account'/key_class'/index
PlatformPayment = 13,
/// Platform Address Funding (DIP-17) - Path: m/9'/5'/17'/0'/2'/index
/// For asset lock funding keys (fixed account=0', key_class=2')
PlatformAddressFunding = 14,
}

impl FFIAccountType {
Expand Down Expand Up @@ -259,6 +262,9 @@ impl FFIAccountType {
Platform Payment account creation must use a different API path."
);
}
FFIAccountType::PlatformAddressFunding => {
key_wallet::AccountType::PlatformAddressFunding
}
}
}

Expand Down Expand Up @@ -347,6 +353,9 @@ impl FFIAccountType {
account,
key_class,
} => (FFIAccountType::PlatformPayment, *account, Some(*key_class)),
key_wallet::AccountType::PlatformAddressFunding => {
(FFIAccountType::PlatformAddressFunding, 0, None)
}
}
}
}
Expand Down
Loading
Loading