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
2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ version = "0.40.0"

[patch.crates-io]
dashcore_hashes = { path = "hashes" }
# Use fixed version of elliptic-curve-tools with DefaultIsZeroes trait bound
elliptic-curve-tools = { git = "https://github.com/mikelodder7/elliptic-curve-tools", branch = "main" }

[profile.release]
# Default to unwinding for most crates
Expand Down
35 changes: 26 additions & 9 deletions dash-spv-ffi/FFI_API.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This document provides a comprehensive reference for all FFI (Foreign Function I

**Auto-generated**: This documentation is automatically generated from the source code. Do not edit manually.

**Total Functions**: 70
**Total Functions**: 71

## Table of Contents

Expand Down Expand Up @@ -138,7 +138,7 @@ Functions: 2

### Utility Functions

Functions: 18
Functions: 19

| Function | Description | Module |
|----------|-------------|--------|
Expand All @@ -151,7 +151,7 @@ Functions: 18
| `dash_spv_ffi_client_get_stats` | Get current runtime statistics for the SPV client | client |
| `dash_spv_ffi_client_get_tip_hash` | Get the current chain tip hash (32 bytes) if available | client |
| `dash_spv_ffi_client_get_tip_height` | Get the current chain tip height (absolute) | client |
| `dash_spv_ffi_client_get_wallet_manager` | Get the wallet manager from the SPV client Returns an opaque pointer to FFIW... | client |
| `dash_spv_ffi_client_get_wallet_manager` | Get the wallet manager from the SPV client Returns a pointer to an `FFIWalle... | client |
| `dash_spv_ffi_client_record_send` | Record that we attempted to send a transaction by its txid | client |
| `dash_spv_ffi_client_rescan_blockchain` | Request a rescan of the blockchain from a given height (not yet implemented) | client |
| `dash_spv_ffi_enable_test_mode` | No description | utils |
Expand All @@ -160,6 +160,7 @@ Functions: 18
| `dash_spv_ffi_string_array_destroy` | Destroy an array of FFIString pointers (Vec<*mut FFIString>) and their contents | types |
| `dash_spv_ffi_string_destroy` | No description | types |
| `dash_spv_ffi_version` | No description | utils |
| `dash_spv_ffi_wallet_manager_free` | Release a wallet manager obtained from `dash_spv_ffi_client_get_wallet_manager` | client |

## Detailed Function Documentation

Expand Down Expand Up @@ -1117,14 +1118,14 @@ Get the current chain tip height (absolute). # Safety - `client` must be a vali
#### `dash_spv_ffi_client_get_wallet_manager`

```c
dash_spv_ffi_client_get_wallet_manager(client: *mut FFIDashSpvClient,) -> *mut c_void
dash_spv_ffi_client_get_wallet_manager(client: *mut FFIDashSpvClient,) -> *mut FFIWalletManager
```

**Description:**
Get the wallet manager from the SPV client Returns an opaque pointer to FFIWalletManager that contains a cloned Arc reference to the wallet manager. This allows direct interaction with the wallet manager without going through the client. # Safety The caller must ensure that: - The client pointer is valid - The returned pointer is freed using `wallet_manager_free` from key-wallet-ffi # Returns An opaque pointer (void*) to the wallet manager, or NULL if the client is not initialized. Swift should treat this as an OpaquePointer. Get a handle to the wallet manager owned by this client. # Safety - `client` must be a valid, non-null pointer.
Get the wallet manager from the SPV client Returns a pointer to an `FFIWalletManager` wrapper that clones the underlying `Arc<RwLock<WalletManager>>`. This allows direct interaction with the wallet manager without going back through the client for each call. # Safety The caller must ensure that: - The client pointer is valid - The returned pointer is released exactly once using `dash_spv_ffi_wallet_manager_free` # Returns A pointer to the wallet manager wrapper, or NULL if the client is not initialized.

**Safety:**
The caller must ensure that: - The client pointer is valid - The returned pointer is freed using `wallet_manager_free` from key-wallet-ffi
The caller must ensure that: - The client pointer is valid - The returned pointer is released exactly once using `dash_spv_ffi_wallet_manager_free`

**Module:** `client`

Expand Down Expand Up @@ -1237,6 +1238,22 @@ dash_spv_ffi_version() -> *const c_char

---

#### `dash_spv_ffi_wallet_manager_free`

```c
dash_spv_ffi_wallet_manager_free(manager: *mut FFIWalletManager) -> ()
```

**Description:**
Release a wallet manager obtained from `dash_spv_ffi_client_get_wallet_manager`. This simply forwards to `wallet_manager_free` in key-wallet-ffi so that lifetime management is consistent between direct key-wallet usage and the SPV client pathway. # Safety - `manager` must either be null or a pointer previously returned by `dash_spv_ffi_client_get_wallet_manager`.

**Safety:**
- `manager` must either be null or a pointer previously returned by `dash_spv_ffi_client_get_wallet_manager`.

**Module:** `client`

---

## Type Definitions

### Core Types
Expand Down Expand Up @@ -1266,7 +1283,7 @@ dash_spv_ffi_version() -> *const c_char
2. **Cleanup Required**: All returned pointers must be freed using the appropriate `_destroy` function
3. **Thread Safety**: The SPV client is thread-safe
4. **Error Handling**: Check return codes and use `dash_spv_ffi_get_last_error()` for details
5. **Opaque Pointers**: `dash_spv_ffi_client_get_wallet_manager()` returns `void*` for Swift compatibility
5. **Shared Ownership**: `dash_spv_ffi_client_get_wallet_manager()` returns `FFIWalletManager*` that must be released with `dash_spv_ffi_wallet_manager_free()`

## Usage Examples

Expand All @@ -1289,8 +1306,8 @@ if (result != 0) {
// Sync to chain tip
dash_spv_ffi_client_sync_to_tip(client, NULL, NULL);

// Get wallet manager (returns void* for Swift)
void* wallet_manager = dash_spv_ffi_client_get_wallet_manager(client);
// Get wallet manager (shares ownership with the client)
FFIWalletManager* wallet_manager = dash_spv_ffi_client_get_wallet_manager(client);

Comment on lines +1309 to 1311
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Example leaks the wallet manager; add a free call.

The “Basic SPV Client Usage” example obtains FFIWalletManager* but never frees it. This encourages leaks in client code. Add dash_spv_ffi_wallet_manager_free(wallet_manager); (before destroying the client or right after use).

Apply this diff to the example:

 // Get wallet manager (shares ownership with the client)
 FFIWalletManager* wallet_manager = dash_spv_ffi_client_get_wallet_manager(client);

+// Free the wallet manager when done
+dash_spv_ffi_wallet_manager_free(wallet_manager);
+wallet_manager = NULL;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Get wallet manager (shares ownership with the client)
FFIWalletManager* wallet_manager = dash_spv_ffi_client_get_wallet_manager(client);
// Get wallet manager (shares ownership with the client)
FFIWalletManager* wallet_manager = dash_spv_ffi_client_get_wallet_manager(client);
// Free the wallet manager when done
dash_spv_ffi_wallet_manager_free(wallet_manager);
wallet_manager = NULL;
🤖 Prompt for AI Agents
In dash-spv-ffi/FFI_API.md around lines 1309 to 1311, the example obtains an
FFIWalletManager* via dash_spv_ffi_client_get_wallet_manager(client) but never
frees it; add a call to dash_spv_ffi_wallet_manager_free(wallet_manager) after
you finish using the wallet_manager (either immediately after its last use in
the example or before destroying the client) to avoid leaking the wallet
manager.

// Clean up
dash_spv_ffi_client_destroy(client);
Expand Down
28 changes: 18 additions & 10 deletions dash-spv-ffi/dash_spv_ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -531,27 +531,35 @@ int32_t dash_spv_ffi_client_enable_mempool_tracking(struct FFIDashSpvClient *cli
/**
* Get the wallet manager from the SPV client
*
* Returns an opaque pointer to FFIWalletManager that contains a cloned Arc reference to the wallet manager.
* This allows direct interaction with the wallet manager without going through the client.
* Returns a pointer to an `FFIWalletManager` wrapper that clones the underlying
* `Arc<RwLock<WalletManager>>`. This allows direct interaction with the wallet
* manager without going back through the client for each call.
*
* # Safety
*
* The caller must ensure that:
* - The client pointer is valid
* - The returned pointer is freed using `wallet_manager_free` from key-wallet-ffi
* - The returned pointer is released exactly once using
* `dash_spv_ffi_wallet_manager_free`
*
* # Returns
*
* An opaque pointer (void*) to the wallet manager, or NULL if the client is not initialized.
* Swift should treat this as an OpaquePointer.
* Get a handle to the wallet manager owned by this client.
* A pointer to the wallet manager wrapper, or NULL if the client is not initialized.
*/
FFIWalletManager *dash_spv_ffi_client_get_wallet_manager(struct FFIDashSpvClient *client) ;

Comment on lines +534 to +550
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Blocker: FFIWalletManager not declared in this header — switch prototypes to struct-qualified to avoid compile error

FFIWalletManager is used but no typedef/forward-declaration exists in this file. C/Swift consumers will see “unknown type name ‘FFIWalletManager’”. Fix locally by using struct-qualified pointers in the signatures. Apply:

- FFIWalletManager *dash_spv_ffi_client_get_wallet_manager(struct FFIDashSpvClient *client) ;
+ struct FFIWalletManager *dash_spv_ffi_client_get_wallet_manager(struct FFIDashSpvClient *client) ;

Optionally, also re-export the type in dash-spv-ffi (e.g., pub use key_wallet_ffi::FFIWalletManager;) so cbindgen emits a proper typedef on future generations. Based on learnings.

/**
* Release a wallet manager obtained from `dash_spv_ffi_client_get_wallet_manager`.
*
* This simply forwards to `wallet_manager_free` in key-wallet-ffi so that
* lifetime management is consistent between direct key-wallet usage and the
* SPV client pathway.
*
* # Safety
* - `client` must be a valid, non-null pointer.
* - `manager` must either be null or a pointer previously returned by
* `dash_spv_ffi_client_get_wallet_manager`.
*/

void *dash_spv_ffi_client_get_wallet_manager(struct FFIDashSpvClient *client)
;
void dash_spv_ffi_wallet_manager_free(FFIWalletManager *manager) ;

Comment on lines +551 to 563
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Make free signature struct-qualified as well for consistency and C-compat

Mirror the change in the free function to avoid the same undefined type:

- void dash_spv_ffi_wallet_manager_free(FFIWalletManager *manager) ;
+ void dash_spv_ffi_wallet_manager_free(struct FFIWalletManager *manager) ;

Also re-run header generation and sync to SDK after adjusting. Based on learnings.

Run to verify header health:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "Check FFIWalletManager usage:"
rg -n "FFIWalletManager" dash-spv-ffi/dash_spv_ffi.h | sed -n '1,200p'
echo "Ensure a declaration exists (typedef or struct-qualified usage):"
rg -nP 'typedef\s+struct\s+FFIWalletManager|struct\s+FFIWalletManager\s*\*' dash-spv-ffi/dash_spv_ffi.h

echo "Check FFINetwork is declared (required by many functions):"
rg -nP 'typedef\s+enum\s+FFINetwork|enum\s+FFINetwork\b' dash-spv-ffi/dash_spv_ffi.h

Length of output: 348


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "Search for inline struct definition in header:"
rg -nP 'struct\s+FFIWalletManager\s*\{' dash-spv-ffi/dash_spv_ffi.h || echo "No inline struct definition found."
echo
echo "Search for typedef alias in header:"
rg -nP 'typedef\s+struct\s+FFIWalletManager\s+FFIWalletManager' dash-spv-ffi/dash_spv_ffi.h || echo "No typedef alias found."
echo
echo "Search entire dash-spv-ffi directory for any struct/typedef of FFIWalletManager:"
rg -nH -n 'FFIWalletManager' -C2 dash-spv-ffi

Length of output: 10333


Qualify FFIWalletManager as an opaque struct in the C header

In dash_spv_ffi_wallet_manager_free, change the parameter from a bare FFIWalletManager* to struct FFIWalletManager* to match other opaque types (e.g. struct FFIClientConfig*) and avoid undefined-type errors:

- void dash_spv_ffi_wallet_manager_free(FFIWalletManager *manager);
+ void dash_spv_ffi_wallet_manager_free(struct FFIWalletManager *manager);

After applying this, re-generate the C header and re-run ./sync-headers.sh to update the Swift SDK.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Release a wallet manager obtained from `dash_spv_ffi_client_get_wallet_manager`.
*
* This simply forwards to `wallet_manager_free` in key-wallet-ffi so that
* lifetime management is consistent between direct key-wallet usage and the
* SPV client pathway.
*
* # Safety
* - `client` must be a valid, non-null pointer.
* - `manager` must either be null or a pointer previously returned by
* `dash_spv_ffi_client_get_wallet_manager`.
*/
void *dash_spv_ffi_client_get_wallet_manager(struct FFIDashSpvClient *client)
;
void dash_spv_ffi_wallet_manager_free(FFIWalletManager *manager) ;
/**
* Release a wallet manager obtained from `dash_spv_ffi_client_get_wallet_manager`.
*
* This simply forwards to `wallet_manager_free` in key-wallet-ffi so that
* lifetime management is consistent between direct key-wallet usage and the
* SPV client pathway.
*
* # Safety
* - `manager` must either be null or a pointer previously returned by
* `dash_spv_ffi_client_get_wallet_manager`.
*/
void dash_spv_ffi_wallet_manager_free(struct FFIWalletManager *manager);
🤖 Prompt for AI Agents
In dash-spv-ffi/dash_spv_ffi.h around lines 551 to 563, the function parameter
uses a bare FFIWalletManager* which is inconsistent with other opaque types and
can trigger undefined-type errors; change the signature to accept struct
FFIWalletManager* instead of FFIWalletManager* to match the header's opaque type
declarations, then re-generate the C header and run ./sync-headers.sh to
propagate the updated declaration to the Swift SDK.

struct FFIClientConfig *dash_spv_ffi_config_new(FFINetwork network) ;

Expand Down
20 changes: 10 additions & 10 deletions dash-spv-ffi/examples/wallet_manager_usage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/// 2. No longer requires going through the client for each operation
/// 3. Cleaner and more efficient access to wallet functionality
use dash_spv_ffi::*;
use key_wallet_ffi::{wallet_manager_free, wallet_manager_wallet_count, FFIError};
use key_wallet_ffi::{wallet_manager_wallet_count, FFIError};

fn main() {
unsafe {
Expand All @@ -21,22 +21,22 @@ fn main() {
panic!("Failed to create client");
}

// Get the wallet manager - now returns void* for Swift compatibility
// This contains a cloned Arc to the wallet manager, allowing
// direct interaction without going through the client
let wallet_manager_ptr = dash_spv_ffi_client_get_wallet_manager(client);
if wallet_manager_ptr.is_null() {
// Get the wallet manager - this returns a strongly typed pointer that
// shares the Arc with the SPV client, allowing direct interaction
let wallet_manager = dash_spv_ffi_client_get_wallet_manager(client);
if wallet_manager.is_null() {
panic!("Failed to get wallet manager");
}
// Cast back to FFIWalletManager for use
let wallet_manager = wallet_manager_ptr as *mut key_wallet_ffi::FFIWalletManager;

// Now we can use the wallet manager directly
// No need to go through client -> inner -> spv_client -> wallet()

// Get the number of wallets (should be 0 initially)
let mut error = std::mem::zeroed::<FFIError>();
let wallet_count = wallet_manager_wallet_count(wallet_manager, &mut error);
let wallet_count = wallet_manager_wallet_count(
wallet_manager as *const key_wallet_ffi::FFIWalletManager,
&mut error,
);
println!("Number of wallets: {}", wallet_count);

// Note: To get total balance, you would need to iterate through wallets
Expand Down Expand Up @@ -66,7 +66,7 @@ fn main() {
// Clean up
// The wallet manager can now be independently destroyed
// It maintains its own Arc reference to the underlying wallet
wallet_manager_free(wallet_manager);
dash_spv_ffi_wallet_manager_free(wallet_manager);
dash_spv_ffi_client_destroy(client);
dash_spv_ffi_config_destroy(config);

Expand Down
39 changes: 29 additions & 10 deletions dash-spv-ffi/include/dash_spv_ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,17 @@ typedef struct FFIEventCallbacks {
void *user_data;
} FFIEventCallbacks;

/**
* Opaque handle to the wallet manager owned by the SPV client.
*
* This is intentionally zero-sized so it can be used purely as an FFI handle
* while still allowing Rust to cast to the underlying key-wallet manager
* implementation when necessary.
*/
typedef struct FFIWalletManager {
uint8_t _private[0];
} FFIWalletManager;

/**
* Handle for Core SDK that can be passed to Platform SDK
*/
Expand Down Expand Up @@ -531,27 +542,35 @@ int32_t dash_spv_ffi_client_enable_mempool_tracking(struct FFIDashSpvClient *cli
/**
* Get the wallet manager from the SPV client
*
* Returns an opaque pointer to FFIWalletManager that contains a cloned Arc reference to the wallet manager.
* This allows direct interaction with the wallet manager without going through the client.
* Returns a pointer to an `FFIWalletManager` wrapper that clones the underlying
* `Arc<RwLock<WalletManager>>`. This allows direct interaction with the wallet
* manager without going back through the client for each call.
*
* # Safety
*
* The caller must ensure that:
* - The client pointer is valid
* - The returned pointer is freed using `wallet_manager_free` from key-wallet-ffi
* - The returned pointer is released exactly once using
* `dash_spv_ffi_wallet_manager_free`
*
* # Returns
*
* An opaque pointer (void*) to the wallet manager, or NULL if the client is not initialized.
* Swift should treat this as an OpaquePointer.
* Get a handle to the wallet manager owned by this client.
* A pointer to the wallet manager wrapper, or NULL if the client is not initialized.
*/
struct FFIWalletManager *dash_spv_ffi_client_get_wallet_manager(struct FFIDashSpvClient *client) ;

/**
* Release a wallet manager obtained from `dash_spv_ffi_client_get_wallet_manager`.
*
* This simply forwards to `wallet_manager_free` in key-wallet-ffi so that
* lifetime management is consistent between direct key-wallet usage and the
* SPV client pathway.
*
* # Safety
* - `client` must be a valid, non-null pointer.
* - `manager` must either be null or a pointer previously returned by
* `dash_spv_ffi_client_get_wallet_manager`.
*/

void *dash_spv_ffi_client_get_wallet_manager(struct FFIDashSpvClient *client)
;
void dash_spv_ffi_wallet_manager_free(struct FFIWalletManager *manager) ;

struct FFIClientConfig *dash_spv_ffi_config_new(FFINetwork network) ;

Expand Down
9 changes: 6 additions & 3 deletions dash-spv-ffi/scripts/generate_ffi_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,10 @@ def generate_markdown(functions: List[FFIFunction]) -> str:
md.append("2. **Cleanup Required**: All returned pointers must be freed using the appropriate `_destroy` function")
md.append("3. **Thread Safety**: The SPV client is thread-safe")
md.append("4. **Error Handling**: Check return codes and use `dash_spv_ffi_get_last_error()` for details")
md.append("5. **Opaque Pointers**: `dash_spv_ffi_client_get_wallet_manager()` returns `void*` for Swift compatibility")
md.append(
"5. **Shared Ownership**: `dash_spv_ffi_client_get_wallet_manager()` returns `FFIWalletManager*` "
"that must be released with `dash_spv_ffi_wallet_manager_free()`"
)
md.append("")

# Usage Examples
Expand All @@ -312,8 +315,8 @@ def generate_markdown(functions: List[FFIFunction]) -> str:
md.append("// Sync to chain tip")
md.append("dash_spv_ffi_client_sync_to_tip(client, NULL, NULL);")
md.append("")
md.append("// Get wallet manager (returns void* for Swift)")
md.append("void* wallet_manager = dash_spv_ffi_client_get_wallet_manager(client);")
md.append("// Get wallet manager (shares ownership with the client)")
md.append("FFIWalletManager* wallet_manager = dash_spv_ffi_client_get_wallet_manager(client);")
md.append("")
md.append("// Clean up")
md.append("dash_spv_ffi_client_destroy(client);")
Expand Down
43 changes: 29 additions & 14 deletions dash-spv-ffi/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::{
null_check, set_last_error, FFIClientConfig, FFIDetailedSyncProgress, FFIErrorCode,
FFIEventCallbacks, FFIMempoolStrategy, FFISpvStats, FFISyncProgress,
FFIEventCallbacks, FFIMempoolStrategy, FFISpvStats, FFISyncProgress, FFIWalletManager,
};
// Import wallet types from key-wallet-ffi
use key_wallet_ffi::FFIWalletManager;
use key_wallet_ffi::FFIWalletManager as KeyWalletFFIWalletManager;

use dash_spv::storage::DiskStorageManager;
use dash_spv::types::SyncStage;
Expand Down Expand Up @@ -1485,27 +1485,24 @@ pub unsafe extern "C" fn dash_spv_ffi_client_record_send(

/// Get the wallet manager from the SPV client
///
/// Returns an opaque pointer to FFIWalletManager that contains a cloned Arc reference to the wallet manager.
/// This allows direct interaction with the wallet manager without going through the client.
/// Returns a pointer to an `FFIWalletManager` wrapper that clones the underlying
/// `Arc<RwLock<WalletManager>>`. This allows direct interaction with the wallet
/// manager without going back through the client for each call.
///
/// # Safety
///
/// The caller must ensure that:
/// - The client pointer is valid
/// - The returned pointer is freed using `wallet_manager_free` from key-wallet-ffi
/// - The returned pointer is released exactly once using
/// `dash_spv_ffi_wallet_manager_free`
///
/// # Returns
///
/// An opaque pointer (void*) to the wallet manager, or NULL if the client is not initialized.
/// Swift should treat this as an OpaquePointer.
/// Get a handle to the wallet manager owned by this client.
///
/// # Safety
/// - `client` must be a valid, non-null pointer.
/// A pointer to the wallet manager wrapper, or NULL if the client is not initialized.
#[no_mangle]
pub unsafe extern "C" fn dash_spv_ffi_client_get_wallet_manager(
client: *mut FFIDashSpvClient,
) -> *mut c_void {
) -> *mut FFIWalletManager {
null_check!(client, std::ptr::null_mut());

let client = &*client;
Expand All @@ -1517,11 +1514,29 @@ pub unsafe extern "C" fn dash_spv_ffi_client_get_wallet_manager(
let runtime = client.runtime.clone();

// Create the FFIWalletManager with the cloned Arc
let manager = FFIWalletManager::from_arc(wallet_arc, runtime);
let manager = KeyWalletFFIWalletManager::from_arc(wallet_arc, runtime);

Box::into_raw(Box::new(manager)) as *mut c_void
Box::into_raw(Box::new(manager)) as *mut FFIWalletManager
} else {
set_last_error("Client not initialized");
std::ptr::null_mut()
}
}

/// Release a wallet manager obtained from `dash_spv_ffi_client_get_wallet_manager`.
///
/// This simply forwards to `wallet_manager_free` in key-wallet-ffi so that
/// lifetime management is consistent between direct key-wallet usage and the
/// SPV client pathway.
///
/// # Safety
/// - `manager` must either be null or a pointer previously returned by
/// `dash_spv_ffi_client_get_wallet_manager`.
#[no_mangle]
pub unsafe extern "C" fn dash_spv_ffi_wallet_manager_free(manager: *mut FFIWalletManager) {
if manager.is_null() {
return;
}

key_wallet_ffi::wallet_manager::wallet_manager_free(manager as *mut KeyWalletFFIWalletManager);
}
10 changes: 10 additions & 0 deletions dash-spv-ffi/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ use dash_spv::{ChainState, PeerInfo, SpvStats, SyncProgress};
use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_void};

/// Opaque handle to the wallet manager owned by the SPV client.
///
/// This is intentionally zero-sized so it can be used purely as an FFI handle
/// while still allowing Rust to cast to the underlying key-wallet manager
/// implementation when necessary.
#[repr(C)]
pub struct FFIWalletManager {
_private: [u8; 0],
}

#[repr(C)]
pub struct FFIString {
pub ptr: *mut c_char,
Expand Down
Loading
Loading