Skip to content

Commit 40244f3

Browse files
committed
refactor(sdk): run the KeyWallet helpers on platform-wallet-ffi
`TransactionDecoder.decode`, `Mnemonic.generate`, `Mnemonic.validate`, `KeyDerivation.getIdentityAuthenticationPath` and `Address.validate` keep their Swift signatures and now call `platform-wallet-ffi`. The Kotlin JNI `decodeTransaction` and `generateMnemonic` bridges do the same and map failures through `take_pwffi_error`, so `rs-unified-sdk-jni` no longer depends on `key-wallet-ffi`. `platform_wallet_mnemonic_word_list` takes its language as a plain integer too, and the Swift callers pass `MnemonicLanguage.rawValue`. The JNI bridge passes Kotlin's ordinal through unchanged, so an unknown ordinal is an error instead of English, and Kotlin's `Language` gains Japanese, Korean, Portuguese and Spanish. New Swift API lets apps stop rebuilding a `KeyWallet` wallet from the phrase: `Mnemonic.walletId(for:network:)`, `Mnemonic.firstReceiveAddress(for:network:)`, and `ManagedPlatformWallet.findBIP44AddressPath(address:)` and `bip44AddressPrivateKey(address:storage:)` for the BIP-44 account scan. The last shares `coreAddressPrivateKey`'s resolver handling. Every helper that passes a string to C rejects an embedded NUL. Parity tests pin the wallet id and the first receive address against the `KeyWallet` code they replace, for English and French phrases. `Mnemonic.generate`, `TransactionDecoder.decode` and `getIdentityAuthenticationPath` now throw `PlatformWalletError`. The other `KeyWallet` classes and `rs-unified-sdk-ffi`'s `key-wallet-ffi` dependency are unchanged.
1 parent 6ec2cae commit 40244f3

22 files changed

Lines changed: 343 additions & 243 deletions

File tree

‎Cargo.lock‎

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎packages/kotlin-sdk/build_android.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Build libdash_sdk_jni.so for Android — the analog of ../swift-sdk/build_ios.sh.
33
#
44
# Produces one cdylib per ABI containing the JNI exports of rs-unified-sdk-jni plus
5-
# the C ABI of rs-sdk-ffi / platform-wallet-ffi / key-wallet-ffi (linked in
5+
# the C ABI of rs-sdk-ffi / platform-wallet-ffi (linked in
66
# as rlibs), and drops them into sdk/src/main/jniLibs/<abi>/ where AGP
77
# packages them.
88
#

‎packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/ffi/MnemonicNative.kt‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ internal object MnemonicNative {
1616
external fun destroyResolver(handle: Long)
1717

1818
/**
19-
* Generate a BIP-39 mnemonic (key-wallet-ffi). wordCount ∈ {12,15,18,21,24};
20-
* language is the FFILanguage ordinal (0 = English).
19+
* Generate a BIP-39 mnemonic (platform-wallet-ffi). wordCount ∈ {12,15,18,21,24};
20+
* language is the FFIMnemonicLanguage ordinal (0 = English).
2121
* @throws DashSDKException on failure
2222
*/
2323
external fun generateMnemonic(wordCount: Int, language: Int): String

‎packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/ffi/TxDecodeNative.kt‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ package org.dashfoundation.dashsdk.ffi
77
internal object TxDecodeNative {
88

99
/**
10-
* Consensus-decode raw transaction bytes (key-wallet-ffi
11-
* `transaction_decode`) into the packed big-endian BLOB documented in
10+
* Consensus-decode raw transaction bytes (platform-wallet-ffi
11+
* `platform_wallet_transaction_decode`) into the packed big-endian BLOB documented in
1212
* `tx_decode.rs` / parsed by
1313
* [org.dashfoundation.dashsdk.keywallet.TransactionDecoder.parseBlob].
1414
* [networkOrd] is [org.dashfoundation.dashsdk.Network.ffiValue].

‎packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/keywallet/Mnemonic.kt‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,23 @@ import org.dashfoundation.dashsdk.ffi.MnemonicNative
66

77
/**
88
* BIP-39 mnemonic operations — port of `SwiftDashSDK/KeyWallet/Mnemonic.swift`.
9-
* Generation runs entirely in Rust (key-wallet-ffi); the phrase transits
9+
* Generation runs entirely in Rust (platform-wallet-ffi); the phrase transits
1010
* Kotlin only to be shown for backup and stored encrypted.
1111
*/
1212
object Mnemonic {
1313

14-
/** Mirror of the iOS `MnemonicLanguage` enum (FFILanguage ordinals). */
14+
/** Mirror of the iOS `MnemonicLanguage` enum (FFIMnemonicLanguage ordinals). */
1515
enum class Language(val ffiValue: Int) {
1616
ENGLISH(0),
1717
CHINESE_SIMPLIFIED(1),
1818
CHINESE_TRADITIONAL(2),
1919
CZECH(3),
2020
FRENCH(4),
2121
ITALIAN(5),
22+
JAPANESE(6),
23+
KOREAN(7),
24+
PORTUGUESE(8),
25+
SPANISH(9),
2226
}
2327

2428
/**

‎packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/keywallet/TransactionDecoder.kt‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import org.dashfoundation.dashsdk.ffi.TxDecodeNative
1010
* A consensus-decoded Dash transaction: per-output `(address, value,
1111
* script)` plus per-input previous outpoints with a best-effort P2PKH
1212
* sender address — port of `SwiftDashSDK/KeyWallet/TransactionDecoder.swift`
13-
* (platform PR #3981) over key-wallet-ffi's `transaction_decode`.
13+
* (platform PR #3981) over platform-wallet-ffi's `platform_wallet_transaction_decode`.
1414
*
1515
* Wallet persistence stores every transaction's raw bytes
1616
* (`TransactionEntity.transactionData`) but only materializes TXO rows for
@@ -88,8 +88,8 @@ class DecodedTransaction(
8888
}
8989

9090
/**
91-
* Pure utility — decodes raw transaction bytes via key-wallet-ffi's
92-
* `transaction_decode`. No wallet handle or state involved.
91+
* Pure utility — decodes raw transaction bytes via platform-wallet-ffi's
92+
* `platform_wallet_transaction_decode`. No wallet handle or state involved.
9393
*/
9494
object TransactionDecoder {
9595

@@ -99,7 +99,7 @@ object TransactionDecoder {
9999
* @param txData serialized transaction bytes (e.g. a persisted
100100
* `TransactionEntity.transactionData`).
101101
* @param network network used to render addresses (base58 version bytes).
102-
* @throws org.dashfoundation.dashsdk.errors.DashSdkError.InvalidParameter
102+
* @throws org.dashfoundation.dashsdk.errors.DashSdkError.PlatformWallet
103103
* for malformed or empty bytes (including trailing garbage).
104104
*/
105105
fun decode(txData: ByteArray, network: Network): DecodedTransaction {

‎packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/persistence/PlatformWalletPersistenceHandler.kt‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ class PlatformWalletPersistenceHandler(
134134
/**
135135
* Where the sweep pass gets a stored loser's input outpoints (the
136136
* outpoint-keyed hold, see `applySweptTransactions`). The production
137-
* default decodes the stored consensus bytes through key-wallet-ffi's
138-
* `transaction_decode`; tests inject a fake keyed by txid, since the
137+
* default decodes the stored consensus bytes through platform-wallet-ffi's
138+
* `platform_wallet_transaction_decode`; tests inject a fake keyed by txid, since the
139139
* native library is not loadable under Robolectric.
140140
*/
141141
private val storedTransactionInputs: StoredTransactionInputs =
@@ -4265,8 +4265,8 @@ fun interface StoredTransactionInputs {
42654265
}
42664266

42674267
/**
4268-
* Production [StoredTransactionInputs]: key-wallet-ffi's
4269-
* `transaction_decode` through [org.dashfoundation.dashsdk.keywallet.TransactionDecoder].
4268+
* Production [StoredTransactionInputs]: platform-wallet-ffi's
4269+
* `platform_wallet_transaction_decode` through [org.dashfoundation.dashsdk.keywallet.TransactionDecoder].
42704270
* The decoder is a stateless marshaler — it takes no wallet-manager lock —
42714271
* so calling it from inside a persistence callback (which runs while Rust
42724272
* holds that lock) cannot deadlock; the "no native calls under

‎packages/kotlin-sdk/sdk/src/test/kotlin/org/dashfoundation/dashsdk/persistence/PlatformWalletPersistenceHandlerTest.kt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class PlatformWalletPersistenceHandlerTest {
6464
/**
6565
* What the sweep pass "decodes" from a stored record's bytes, keyed by
6666
* txid. Every fixture records transactions with dummy bytes
67-
* (`ByteArray(10) { 5 }`) that key-wallet-ffi could never decode, and
67+
* (`ByteArray(10) { 5 }`) that the native decoder could never decode, and
6868
* the native decoder is not loadable under Robolectric anyway, so
6969
* [recordTransaction] registers each record's `inputOutpoints` here and
7070
* [storedInputs] hands them back. A txid never registered throws, as

‎packages/rs-platform-wallet-ffi/src/mnemonic_words.rs‎

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,22 @@ impl From<FFIMnemonicLanguage> for key_wallet::Language {
9494
/// caller owns `*out_string` and must free it via
9595
/// [`crate::xpub_render::platform_wallet_free_string`].
9696
///
97+
/// `language` is an [`FFIMnemonicLanguage`] value, taken as a plain integer so
98+
/// an unknown value fails with `ErrorInvalidParameter` instead of being
99+
/// undefined behaviour.
100+
///
97101
/// # Safety
98102
/// `out_string` must point to writable memory for one `*mut c_char`.
99103
#[no_mangle]
100104
pub unsafe extern "C" fn platform_wallet_mnemonic_word_list(
101-
language: FFIMnemonicLanguage,
105+
language: u32,
102106
out_string: *mut *mut c_char,
103107
) -> PlatformWalletFFIResult {
104108
check_ptr!(out_string);
105109
*out_string = std::ptr::null_mut();
106110

107-
let language: key_wallet::Language = language.into();
111+
let language: key_wallet::Language =
112+
unwrap_result_or_return!(FFIMnemonicLanguage::try_from(language)).into();
108113
let joined = language.word_list().join("\n");
109114
let c = unwrap_result_or_return!(CString::new(joined));
110115
*out_string = c.into_raw();
@@ -245,7 +250,8 @@ mod tests {
245250
// word_list: English -> 2048 \n-joined words including "abandon"/"zoo".
246251
let mut wl: *mut c_char = std::ptr::null_mut();
247252
unsafe {
248-
let r = platform_wallet_mnemonic_word_list(FFIMnemonicLanguage::English, &mut wl);
253+
let r =
254+
platform_wallet_mnemonic_word_list(FFIMnemonicLanguage::English as u32, &mut wl);
249255
assert_eq!(r.code, PlatformWalletFFIResultCode::Success);
250256
assert!(!wl.is_null());
251257
let s = CStr::from_ptr(wl).to_str().unwrap().to_owned();
@@ -260,7 +266,10 @@ mod tests {
260266
// confirms the enum conversion actually selects the wordlist.
261267
let mut wl_ja: *mut c_char = std::ptr::null_mut();
262268
unsafe {
263-
let r = platform_wallet_mnemonic_word_list(FFIMnemonicLanguage::Japanese, &mut wl_ja);
269+
let r = platform_wallet_mnemonic_word_list(
270+
FFIMnemonicLanguage::Japanese as u32,
271+
&mut wl_ja,
272+
);
264273
assert_eq!(r.code, PlatformWalletFFIResultCode::Success);
265274
let s = CStr::from_ptr(wl_ja).to_str().unwrap().to_owned();
266275
assert_eq!(s.split('\n').count(), 2048);
@@ -271,7 +280,7 @@ mod tests {
271280
// word_list NULL out-pointer -> error
272281
unsafe {
273282
let r = platform_wallet_mnemonic_word_list(
274-
FFIMnemonicLanguage::English,
283+
FFIMnemonicLanguage::English as u32,
275284
std::ptr::null_mut(),
276285
);
277286
assert_eq!(r.code, PlatformWalletFFIResultCode::ErrorNullPointer);
@@ -380,6 +389,10 @@ mod tests {
380389
let r = platform_wallet_mnemonic_generate(12, 10, &mut bad);
381390
assert_eq!(r.code, PlatformWalletFFIResultCode::ErrorInvalidParameter);
382391
assert!(bad.is_null());
392+
let mut list: *mut c_char = NonNull::dangling().as_ptr();
393+
let r = platform_wallet_mnemonic_word_list(10, &mut list);
394+
assert_eq!(r.code, PlatformWalletFFIResultCode::ErrorInvalidParameter);
395+
assert!(list.is_null());
383396
}
384397

385398
// validate: any supported language, but not a bad checksum or gibberish

‎packages/rs-unified-sdk-jni/Cargo.toml‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ edition = "2021"
44
version.workspace = true
55
rust-version.workspace = true
66
license = "MIT"
7-
description = "JNI bindings for the Dash Platform SDK — Android/Kotlin shim over rs-sdk-ffi, platform-wallet-ffi and key-wallet-ffi"
7+
description = "JNI bindings for the Dash Platform SDK — Android/Kotlin shim over rs-sdk-ffi and platform-wallet-ffi"
88

99
[lib]
1010
# Kotlin loads this as System.loadLibrary("dash_sdk_jni").
@@ -15,7 +15,6 @@ crate-type = ["cdylib"]
1515
jni = "0.21"
1616
rs-sdk-ffi = { path = "../rs-sdk-ffi" }
1717
platform-wallet-ffi = { path = "../rs-platform-wallet-ffi" }
18-
key-wallet-ffi = { workspace = true }
1918
dash-network = { workspace = true, features = ["ffi"] }
2019
log = "0.4"
2120
zeroize = "1"

0 commit comments

Comments
 (0)