diff --git a/Cargo.lock b/Cargo.lock index e1b45d53b24..d0614b415f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4966,6 +4966,7 @@ version = "2.1.1" dependencies = [ "bincode", "bs58", + "cbindgen 0.27.0", "dash-sdk", "dashcore", "dpp", diff --git a/packages/rs-platform-wallet-ffi/Cargo.toml b/packages/rs-platform-wallet-ffi/Cargo.toml index bc90816ccb2..43c195e360e 100644 --- a/packages/rs-platform-wallet-ffi/Cargo.toml +++ b/packages/rs-platform-wallet-ffi/Cargo.toml @@ -47,6 +47,9 @@ zeroize = { version = "1", features = ["derive"] } tempfile = "3.8" dpp = { path = "../rs-dpp", features = ["fixtures-and-mocks"] } +[build-dependencies] +cbindgen = "0.27" + [features] default = [] mocks = [] diff --git a/packages/rs-platform-wallet-ffi/build.rs b/packages/rs-platform-wallet-ffi/build.rs new file mode 100644 index 00000000000..29549edbb55 --- /dev/null +++ b/packages/rs-platform-wallet-ffi/build.rs @@ -0,0 +1,32 @@ +use std::path::Path; +use std::{env, fs}; + +fn main() { + let crate_name = env::var("CARGO_PKG_NAME").unwrap(); + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let out_dir = env::var("OUT_DIR").unwrap(); + + println!("cargo:rerun-if-changed=cbindgen.toml"); + println!("cargo:rerun-if-changed=src/"); + + let target_dir = Path::new(&out_dir) + .ancestors() + .nth(3) // This line moves up to the target/ directory + .expect("Failed to find target dir"); + + let include_dir = target_dir.join("include").join(&crate_name); + + fs::create_dir_all(&include_dir).unwrap(); + + let output_path = include_dir.join(format!("{}.h", &crate_name)); + + let config_path = Path::new(&crate_dir).join("cbindgen.toml"); + let config = cbindgen::Config::from_file(&config_path).expect("Failed to read cbindgen.toml"); + + cbindgen::Builder::new() + .with_crate(&crate_dir) + .with_config(config) + .generate() + .expect("Unable to generate bindings") + .write_to_file(&output_path); +} diff --git a/packages/rs-platform-wallet-ffi/cbindgen.toml b/packages/rs-platform-wallet-ffi/cbindgen.toml index 23c2d72c14c..6d7acb5e3e6 100644 --- a/packages/rs-platform-wallet-ffi/cbindgen.toml +++ b/packages/rs-platform-wallet-ffi/cbindgen.toml @@ -1,78 +1,25 @@ -# cbindgen configuration for Platform Wallet FFI - language = "C" pragma_once = true include_guard = "PLATFORM_WALLET_FFI_H" autogen_warning = "/* This file is auto-generated. Do not modify manually. */" include_version = true -namespaces = [] -using_namespaces = [] sys_includes = ["stdint.h", "stdbool.h"] -includes = [] no_includes = false cpp_compat = true documentation = true documentation_style = "c99" -# Forward-declare external Rust types referenced opaquely in this -# crate's FFI signatures. cbindgen cannot introspect external crates, -# so without this injection the generated header references `Sdk *` -# with no type declaration, causing the Swift build to fail with -# `unknown type name 'Sdk'`. The build_ios.sh post-processor expands -# these forward declarations into `typedef struct X { uint8_t _opaque; } X;`. -after_includes = """ -typedef struct Sdk Sdk; -""" - -[defines] - -[export] -include = ["platform_wallet_*", "identity_manager_*", "managed_identity_*", "contact_request_*", "established_contact_*"] -exclude = [] -prefix = "" -item_types = ["enums", "structs", "unions", "typedefs", "opaque", "functions"] - -[export.rename] -"Handle" = "platform_wallet_handle_t" -"PlatformWalletFFIError" = "platform_wallet_error_t" -"PlatformWalletFFIResult" = "platform_wallet_result_t" - [fn] args = "horizontal" rename_args = "snake_case" must_use = "PLATFORM_WALLET_WARN_UNUSED_RESULT" -prefix = "" -postfix = "" - -[struct] -rename_fields = "snake_case" -derive_constructor = false -derive_eq = false -derive_neq = false -derive_lt = false -derive_lte = false -derive_gt = false -derive_gte = false [enum] rename_variants = "ScreamingSnakeCase" -add_sentinel = false prefix_with_name = true -derive_helper_methods = false -derive_const_casts = false -derive_mut_casts = false -cast_assert_name = "assert" must_use = "PLATFORM_WALLET_WARN_UNUSED_RESULT" [const] allow_static_const = true allow_constexpr = false sort_by = "name" - -[macro_expansion] -bitflags = false - -[parse] -parse_deps = false -include = [] -exclude = [] diff --git a/packages/rs-platform-wallet-ffi/platform_wallet_ffi.h b/packages/rs-platform-wallet-ffi/platform_wallet_ffi.h deleted file mode 100644 index e53d5a0e9ee..00000000000 --- a/packages/rs-platform-wallet-ffi/platform_wallet_ffi.h +++ /dev/null @@ -1,670 +0,0 @@ -/* - * Platform Wallet FFI - C Header File - * - * C-compatible FFI bindings for rs-platform-wallet - * Provides unified wallet management with Platform identity support - */ - -#ifndef PLATFORM_WALLET_FFI_H -#define PLATFORM_WALLET_FFI_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* ============================================================================ - * Types - * ========================================================================== */ - -typedef uint64_t Handle; -#define NULL_HANDLE 0 - -/* Network types */ -typedef enum { - NETWORK_TYPE_MAINNET = 0, - NETWORK_TYPE_TESTNET = 1, - NETWORK_TYPE_DEVNET = 2, - NETWORK_TYPE_REGTEST = 3, -} NetworkType; - -/* FFI Result codes */ -typedef enum { - PLATFORM_WALLET_FFI_SUCCESS = 0, - PLATFORM_WALLET_FFI_ERROR_INVALID_HANDLE = 1, - PLATFORM_WALLET_FFI_ERROR_INVALID_PARAMETER = 2, - PLATFORM_WALLET_FFI_ERROR_NULL_POINTER = 3, - PLATFORM_WALLET_FFI_ERROR_SERIALIZATION = 4, - PLATFORM_WALLET_FFI_ERROR_DESERIALIZATION = 5, - PLATFORM_WALLET_FFI_ERROR_WALLET_OPERATION = 6, - PLATFORM_WALLET_FFI_ERROR_IDENTITY_NOT_FOUND = 7, - PLATFORM_WALLET_FFI_ERROR_CONTACT_NOT_FOUND = 8, - PLATFORM_WALLET_FFI_ERROR_INVALID_NETWORK = 9, - PLATFORM_WALLET_FFI_ERROR_INVALID_IDENTIFIER = 10, - PLATFORM_WALLET_FFI_ERROR_MEMORY_ALLOCATION = 11, - PLATFORM_WALLET_FFI_ERROR_UTF8_CONVERSION = 12, - PLATFORM_WALLET_FFI_ERROR_UNKNOWN = 99, -} PlatformWalletFFIResult; - -/* Error information */ -typedef struct { - PlatformWalletFFIResult code; - char* message; -} PlatformWalletFFIError; - -/* Identifier (32 bytes) */ -typedef struct { - uint8_t bytes[32]; -} IdentifierBytes; - -/* Block time */ -typedef struct { - uint64_t height; - uint32_t core_height; - uint64_t timestamp; -} BlockTime; - -/* Contact request */ -typedef struct { - IdentifierBytes identity_id; - char* label; - uint64_t timestamp; -} ContactRequest; - -/* Established contact */ -typedef struct { - IdentifierBytes identity_id; - char* label; - uint64_t established_at; -} EstablishedContact; - -/* Array of identifiers */ -typedef struct { - IdentifierBytes* items; - size_t count; -} IdentifierArray; - -/* ============================================================================ - * Library Management - * ========================================================================== */ - -/** - * Initialize the FFI library - * Must be called before using any other functions - */ -void platform_wallet_ffi_init(void); - -/** - * Get the version of the platform wallet FFI library - * @return Version string (do not free) - */ -const char* platform_wallet_ffi_version(void); - -/* ============================================================================ - * Error Management - * ========================================================================== */ - -/** - * Free error message - * @param error Error to free - */ -void platform_wallet_ffi_error_free(PlatformWalletFFIError error); - -/* ============================================================================ - * PlatformWalletInfo Functions - * ========================================================================== */ - -/** - * Create a new PlatformWalletInfo from seed bytes - * @param seed_bytes Seed bytes (typically 64 bytes) - * @param seed_len Length of seed - * @param out_handle Output handle - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult platform_wallet_info_create_from_seed( - const uint8_t* seed_bytes, - size_t seed_len, - Handle* out_handle, - PlatformWalletFFIError* out_error -); - -/** - * Create a new PlatformWalletInfo from mnemonic - * @param mnemonic BIP39 mnemonic phrase - * @param passphrase Optional passphrase (can be NULL) - * @param out_handle Output handle - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult platform_wallet_info_create_from_mnemonic( - const char* mnemonic, - const char* passphrase, - Handle* out_handle, - PlatformWalletFFIError* out_error -); - -/** - * Get the identity manager for a specific network - * @param wallet_handle Wallet handle - * @param network Network type - * @param out_handle Output handle for identity manager - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult platform_wallet_info_get_identity_manager( - Handle wallet_handle, - NetworkType network, - Handle* out_handle, - PlatformWalletFFIError* out_error -); - -/** - * Set identity manager for a network - * @param wallet_handle Wallet handle - * @param network Network type - * @param manager_handle Identity manager handle - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult platform_wallet_info_set_identity_manager( - Handle wallet_handle, - NetworkType network, - Handle manager_handle, - PlatformWalletFFIError* out_error -); - -/** - * Serialize PlatformWalletInfo to JSON - * @param wallet_handle Wallet handle - * @param out_json Output JSON string (caller must free with platform_wallet_string_free) - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult platform_wallet_info_to_json( - Handle wallet_handle, - char** out_json, - PlatformWalletFFIError* out_error -); - -/** - * Destroy PlatformWalletInfo and free resources - * @param wallet_handle Wallet handle - * @return Result code - */ -PlatformWalletFFIResult platform_wallet_info_destroy(Handle wallet_handle); - -/* ============================================================================ - * IdentityManager Functions - * ========================================================================== */ - -/** - * Create a new empty IdentityManager - * @param out_handle Output handle - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult identity_manager_create( - Handle* out_handle, - PlatformWalletFFIError* out_error -); - -/** - * Add a managed identity to the manager - * @param manager_handle Manager handle - * @param identity_handle Identity handle - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult identity_manager_add_identity( - Handle manager_handle, - Handle identity_handle, - PlatformWalletFFIError* out_error -); - -/** - * Remove an identity from the manager - * @param manager_handle Manager handle - * @param identity_id Identity ID to remove - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult identity_manager_remove_identity( - Handle manager_handle, - IdentifierBytes identity_id, - PlatformWalletFFIError* out_error -); - -/** - * Get an identity by ID - * @param manager_handle Manager handle - * @param identity_id Identity ID - * @param out_handle Output handle for identity - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult identity_manager_get_identity( - Handle manager_handle, - IdentifierBytes identity_id, - Handle* out_handle, - PlatformWalletFFIError* out_error -); - -/** - * Get all identity IDs - * @param manager_handle Manager handle - * @param out_array Output array (caller must free with platform_wallet_identifier_array_free) - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult identity_manager_get_all_identity_ids( - Handle manager_handle, - IdentifierArray* out_array, - PlatformWalletFFIError* out_error -); - -/** - * Get the primary identity ID - * @param manager_handle Manager handle - * @param out_id Output identifier - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult identity_manager_get_primary_identity_id( - Handle manager_handle, - IdentifierBytes* out_id, - PlatformWalletFFIError* out_error -); - -/** - * Set the primary identity - * @param manager_handle Manager handle - * @param identity_id Identity ID to set as primary - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult identity_manager_set_primary_identity( - Handle manager_handle, - IdentifierBytes identity_id, - PlatformWalletFFIError* out_error -); - -/** - * Get the count of identities - * @param manager_handle Manager handle - * @param out_count Output count - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult identity_manager_get_identity_count( - Handle manager_handle, - size_t* out_count, - PlatformWalletFFIError* out_error -); - -/** - * Destroy IdentityManager and free resources - * @param manager_handle Manager handle - * @return Result code - */ -PlatformWalletFFIResult identity_manager_destroy(Handle manager_handle); - -/* ============================================================================ - * ManagedIdentity Functions - * ========================================================================== */ - -/** - * Create a new ManagedIdentity from DPP Identity bytes - * @param identity_bytes Serialized identity bytes - * @param identity_len Length of identity bytes - * @param out_handle Output handle - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_create_from_identity_bytes( - const uint8_t* identity_bytes, - size_t identity_len, - Handle* out_handle, - PlatformWalletFFIError* out_error -); - -/** - * Get the identity ID - * @param identity_handle Identity handle - * @param out_id Output identifier - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_get_id( - Handle identity_handle, - IdentifierBytes* out_id, - PlatformWalletFFIError* out_error -); - -/** - * Get the identity balance - * @param identity_handle Identity handle - * @param out_balance Output balance - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_get_balance( - Handle identity_handle, - uint64_t* out_balance, - PlatformWalletFFIError* out_error -); - -/** - * Get the label - * @param identity_handle Identity handle - * @param out_label Output label (caller must free with platform_wallet_string_free, NULL if no label) - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_get_label( - Handle identity_handle, - char** out_label, - PlatformWalletFFIError* out_error -); - -/** - * Set the label - * @param identity_handle Identity handle - * @param label Label string (NULL to clear) - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_set_label( - Handle identity_handle, - const char* label, - PlatformWalletFFIError* out_error -); - -/** - * Get last updated balance block time - * @param identity_handle Identity handle - * @param out_block_time Output block time (zeroed if not set) - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_get_last_updated_balance_block_time( - Handle identity_handle, - BlockTime* out_block_time, - PlatformWalletFFIError* out_error -); - -/** - * Set last updated balance block time - * @param identity_handle Identity handle - * @param block_time Block time to set - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_set_last_updated_balance_block_time( - Handle identity_handle, - BlockTime block_time, - PlatformWalletFFIError* out_error -); - -/** - * Get last synced keys block time - * @param identity_handle Identity handle - * @param out_block_time Output block time (zeroed if not set) - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_get_last_synced_keys_block_time( - Handle identity_handle, - BlockTime* out_block_time, - PlatformWalletFFIError* out_error -); - -/** - * Serialize ManagedIdentity to JSON - * @param identity_handle Identity handle - * @param out_json Output JSON string (caller must free with platform_wallet_string_free) - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_to_json( - Handle identity_handle, - char** out_json, - PlatformWalletFFIError* out_error -); - -/** - * Destroy ManagedIdentity and free resources - * @param identity_handle Identity handle - * @return Result code - */ -PlatformWalletFFIResult managed_identity_destroy(Handle identity_handle); - -/* ============================================================================ - * Contact Management Functions - * ========================================================================== */ - -/** - * Add a sent contact request - * @param identity_handle Identity handle - * @param contact_id Contact identity ID - * @param label Optional label (can be NULL) - * @param timestamp Request timestamp - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_add_sent_contact_request( - Handle identity_handle, - IdentifierBytes contact_id, - const char* label, - uint64_t timestamp, - PlatformWalletFFIError* out_error -); - -/** - * Add an incoming contact request - * @param identity_handle Identity handle - * @param contact_id Contact identity ID - * @param label Optional label (can be NULL) - * @param timestamp Request timestamp - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_add_incoming_contact_request( - Handle identity_handle, - IdentifierBytes contact_id, - const char* label, - uint64_t timestamp, - PlatformWalletFFIError* out_error -); - -/** - * Remove a sent contact request - * @param identity_handle Identity handle - * @param contact_id Contact identity ID - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_remove_sent_contact_request( - Handle identity_handle, - IdentifierBytes contact_id, - PlatformWalletFFIError* out_error -); - -/** - * Remove an incoming contact request - * @param identity_handle Identity handle - * @param contact_id Contact identity ID - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_remove_incoming_contact_request( - Handle identity_handle, - IdentifierBytes contact_id, - PlatformWalletFFIError* out_error -); - -/** - * Get all sent contact request IDs - * @param identity_handle Identity handle - * @param out_array Output array (caller must free with platform_wallet_identifier_array_free) - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_get_sent_contact_request_ids( - Handle identity_handle, - IdentifierArray* out_array, - PlatformWalletFFIError* out_error -); - -/** - * Get all incoming contact request IDs - * @param identity_handle Identity handle - * @param out_array Output array (caller must free with platform_wallet_identifier_array_free) - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_get_incoming_contact_request_ids( - Handle identity_handle, - IdentifierArray* out_array, - PlatformWalletFFIError* out_error -); - -/** - * Get all established contact IDs - * @param identity_handle Identity handle - * @param out_array Output array (caller must free with platform_wallet_identifier_array_free) - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_get_established_contact_ids( - Handle identity_handle, - IdentifierArray* out_array, - PlatformWalletFFIError* out_error -); - -/** - * Check if a contact is established - * @param identity_handle Identity handle - * @param contact_id Contact identity ID - * @param out_is_established Output boolean - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_is_contact_established( - Handle identity_handle, - IdentifierBytes contact_id, - bool* out_is_established, - PlatformWalletFFIError* out_error -); - -/** - * Remove an established contact - * @param identity_handle Identity handle - * @param contact_id Contact identity ID - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult managed_identity_remove_established_contact( - Handle identity_handle, - IdentifierBytes contact_id, - PlatformWalletFFIError* out_error -); - -/* ============================================================================ - * Utility Functions - * ========================================================================== */ - -/** - * Serialize JSON string to bytes - * @param json_string JSON string - * @param out_bytes Output bytes (caller must free with platform_wallet_bytes_free) - * @param out_len Output length - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult platform_wallet_serialize_to_json_bytes( - const char* json_string, - uint8_t** out_bytes, - size_t* out_len, - PlatformWalletFFIError* out_error -); - -/** - * Deserialize JSON bytes to string - * @param bytes Input bytes - * @param len Input length - * @param out_json_string Output JSON string (caller must free with platform_wallet_string_free) - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult platform_wallet_deserialize_from_json_bytes( - const uint8_t* bytes, - size_t len, - char** out_json_string, - PlatformWalletFFIError* out_error -); - -/** - * Generate random identifier - * @param out_id Output identifier - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult platform_wallet_generate_random_identifier( - IdentifierBytes* out_id, - PlatformWalletFFIError* out_error -); - -/** - * Convert identifier to hex string - * @param id Identifier - * @param out_hex Output hex string (caller must free with platform_wallet_string_free) - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult platform_wallet_identifier_to_hex( - IdentifierBytes id, - char** out_hex, - PlatformWalletFFIError* out_error -); - -/** - * Convert hex string to identifier - * @param hex Hex string - * @param out_id Output identifier - * @param out_error Optional error output - * @return Result code - */ -PlatformWalletFFIResult platform_wallet_identifier_from_hex( - const char* hex, - IdentifierBytes* out_id, - PlatformWalletFFIError* out_error -); - -/** - * Free identifier array - * @param array Array to free - */ -void platform_wallet_identifier_array_free(IdentifierArray array); - -/** - * Free a C string - * @param s String to free - */ -void platform_wallet_string_free(char* s); - -/** - * Free bytes allocated by FFI functions - * @param bytes Bytes to free - * @param len Length of bytes - */ -void platform_wallet_bytes_free(uint8_t* bytes, size_t len); - -#ifdef __cplusplus -} -#endif - -#endif /* PLATFORM_WALLET_FFI_H */ diff --git a/packages/rs-platform-wallet-ffi/src/core_address_types.rs b/packages/rs-platform-wallet-ffi/src/core_address_types.rs index 1fd455b71b4..402fecfddd2 100644 --- a/packages/rs-platform-wallet-ffi/src/core_address_types.rs +++ b/packages/rs-platform-wallet-ffi/src/core_address_types.rs @@ -7,9 +7,7 @@ //! (`PersistentCoreAddress`) so the Storage Explorer can render //! derivation paths + pubkeys reactively via `@Query`. -use std::os::raw::{c_char, c_void}; - -use crate::wallet_restore_types::AccountSpecFFI; +use std::os::raw::c_char; /// Pool-type discriminant matching `key_wallet::managed_account::AddressPoolType`. /// Kept stable across releases — it lands in SwiftData rows. @@ -51,18 +49,3 @@ pub struct CoreAddressEntryFFI { // itself carries no state that outlives the call. unsafe impl Send for CoreAddressEntryFFI {} unsafe impl Sync for CoreAddressEntryFFI {} - -/// Fires once per account whose address pool needs persisting. The -/// `account` pointer identifies which `PersistentAccount` row to link -/// the addresses to (Swift matches by the same key used in -/// `on_persist_account_fn`). The addresses slice is contiguous. -/// -/// Returns 0 on success, non-zero to surface an error; Rust logs and -/// continues regardless. -pub type PersistAccountAddressesFn = unsafe extern "C" fn( - context: *mut c_void, - wallet_id: *const u8, - account: *const AccountSpecFFI, - addresses: *const CoreAddressEntryFFI, - count: usize, -) -> i32; diff --git a/packages/rs-platform-wallet-ffi/src/manager.rs b/packages/rs-platform-wallet-ffi/src/manager.rs index cf32e5fedbb..aa31abb9adf 100644 --- a/packages/rs-platform-wallet-ffi/src/manager.rs +++ b/packages/rs-platform-wallet-ffi/src/manager.rs @@ -10,18 +10,28 @@ use dash_sdk::Sdk; use key_wallet::wallet::initialization::WalletAccountCreationOptions; use key_wallet::Network; use platform_wallet::PlatformWalletManager; +use std::os::raw::c_void; use std::sync::Arc; /// Create a new PlatformWalletManager. /// -/// `sdk_ptr` must point to a valid `Sdk` instance (the FFI caller is -/// responsible for keeping it alive). The Sdk is cloned and wrapped in Arc. +/// `sdk_ptr` must point to a valid `dash_sdk::Sdk` instance — typically +/// obtained from `dash_sdk_get_inner_sdk_ptr` in `rs-sdk-ffi`, which +/// hands back a `*const c_void` pointing at the live `Sdk` field of the +/// wrapper. The FFI caller is responsible for keeping that `Sdk` alive +/// for the duration of this call. The Sdk is cloned and wrapped in Arc +/// before being stored on the manager. +/// +/// We deliberately accept `*const c_void` here rather than `*const Sdk` +/// so that this header is self-contained — `Sdk` is a `dash-sdk` type +/// that cbindgen cannot expose without dragging the entire crate's +/// internal layout into the C ABI. /// /// `persistence` and `event_handler` are callback vtables whose `context` /// pointers must remain valid for the lifetime of the manager. #[no_mangle] pub unsafe extern "C" fn platform_wallet_manager_create( - sdk_ptr: *const Sdk, + sdk_ptr: *const c_void, persistence: *const PersistenceCallbacks, event_handler: *const EventHandlerCallbacks, out_handle: *mut Handle, @@ -35,7 +45,7 @@ pub unsafe extern "C" fn platform_wallet_manager_create( return PlatformWalletFFIResult::ErrorNullPointer; } - let sdk = Arc::new((*sdk_ptr).clone()); + let sdk = Arc::new((*(sdk_ptr as *const Sdk)).clone()); let persister = Arc::new(FFIPersister::new(std::ptr::read(persistence))); let handler: Arc = Arc::new(FFIEventHandler::new(std::ptr::read(event_handler))); diff --git a/packages/rs-platform-wallet-ffi/src/persistence.rs b/packages/rs-platform-wallet-ffi/src/persistence.rs index cb7715e609e..1084ea78ca8 100644 --- a/packages/rs-platform-wallet-ffi/src/persistence.rs +++ b/packages/rs-platform-wallet-ffi/src/persistence.rs @@ -25,9 +25,7 @@ use std::ffi::CString; use std::os::raw::c_void; use std::slice; -use crate::core_address_types::{ - AddressPoolTypeTagFFI, CoreAddressEntryFFI, PersistAccountAddressesFn, -}; +use crate::core_address_types::{AddressPoolTypeTagFFI, CoreAddressEntryFFI}; use crate::core_wallet_types::{free_wallet_changeset_ffi, WalletChangeSetFFI}; use crate::identity_persistence::{ free_identity_entry_ffi, free_identity_key_entry_ffi, IdentityEntryFFI, IdentityKeyEntryFFI, @@ -36,8 +34,7 @@ use crate::identity_persistence::{ use crate::platform_address_types::AddressBalanceEntryFFI; use crate::wallet_restore_types::{ AccountSpecFFI, AccountTypeTagFFI, IdentityKeyRestoreFFI, IdentityRestoreEntryFFI, - LoadWalletListFn, LoadWalletListFreeFn, PersistAccountFn, PersistWalletMetadataFn, - StandardAccountTypeTagFFI, WalletRestoreEntryFFI, + LoadWalletListFreeFn, StandardAccountTypeTagFFI, WalletRestoreEntryFFI, }; use dpp::address_funds::PlatformAddress; use dpp::identity::identity_public_key::v0::IdentityPublicKeyV0; @@ -116,23 +113,76 @@ pub struct PersistenceCallbacks { ) -> i32, >, /// Called once per account when the account is added to a wallet. - /// Caller should upsert keyed by `(wallet_id, account spec)`. See - /// [`PersistAccountFn`]. - pub on_persist_account_fn: Option, + /// Caller should upsert keyed by `(wallet_id, account spec)`. + /// Returns 0 on success. A non-zero return is propagated as a + /// `PersistenceError` from `store_account`, aborting the + /// caller's operation. + pub on_persist_account_fn: Option< + unsafe extern "C" fn( + context: *mut c_void, + wallet_id: *const u8, + spec: *const AccountSpecFFI, + ) -> i32, + >, /// Invoked on [`FFIPersister::load`] to pull the persisted wallet - /// list back into Rust for watch-only reconstruction. See - /// [`LoadWalletListFn`] for the allocation / lifetime contract. - pub on_load_wallet_list_fn: Option, + /// list back into Rust for watch-only reconstruction. + /// + /// Implementations must set `*out_entries` to a Swift-allocated + /// array of `WalletRestoreEntryFFI` and `*out_count` to the + /// length. The allocation is freed by the caller via + /// `on_load_wallet_list_free_fn` once Rust has consumed it. + /// Returns 0 on success, non-zero on failure; on failure Rust + /// does not call the free callback. + pub on_load_wallet_list_fn: Option< + unsafe extern "C" fn( + context: *mut c_void, + out_entries: *mut *const WalletRestoreEntryFFI, + out_count: *mut usize, + ) -> i32, + >, /// Paired free callback for `on_load_wallet_list_fn`. See - /// [`LoadWalletListFreeFn`]. - pub on_load_wallet_list_free_fn: Option, + /// [`LoadWalletListFreeFn`] for the allocation / lifetime contract. + pub on_load_wallet_list_free_fn: Option< + unsafe extern "C" fn( + context: *mut c_void, + entries: *const WalletRestoreEntryFFI, + count: usize, + ), + >, /// Called once per wallet at registration with network tag and - /// birth height. See [`PersistWalletMetadataFn`]. - pub on_persist_wallet_metadata_fn: Option, + /// birth height. `network` uses the same discriminant as + /// `WalletRestoreEntryFFI.network` (0 = Mainnet, 1 = Testnet, + /// 2 = Devnet, 3 = Regtest). `birth_height` is the best estimate + /// of the block at which the wallet started; zero means + /// "scan from genesis / unknown". Returns 0 on success. A + /// non-zero return is propagated as a `PersistenceError` from + /// `store_wallet_metadata`, aborting the caller's operation. + pub on_persist_wallet_metadata_fn: Option< + unsafe extern "C" fn( + context: *mut c_void, + wallet_id: *const u8, + network: u8, + birth_height: u32, + ) -> i32, + >, /// Called per account whenever its address pool content changes - /// (initial population, pool extension, `used` flip). See - /// [`PersistAccountAddressesFn`]. - pub on_persist_account_addresses_fn: Option, + /// (initial population, pool extension, `used` flip). The + /// `account` pointer identifies which `PersistentAccount` row to + /// link the addresses to (Swift matches by the same key used in + /// `on_persist_account_fn`). The addresses slice is contiguous + /// and Rust-owned; Swift must copy any string before returning. + /// Returns 0 on success. A non-zero return is propagated as a + /// `PersistenceError` from `store_account_addresses`, aborting + /// the caller's operation. + pub on_persist_account_addresses_fn: Option< + unsafe extern "C" fn( + context: *mut c_void, + wallet_id: *const u8, + account: *const AccountSpecFFI, + addresses: *const CoreAddressEntryFFI, + count: usize, + ) -> i32, + >, /// Called with an `IdentityChangeSet` slice — scalar-only /// identity upserts (id / balance / revision / status / /// wallet_id / identity_index) and identity-id removals. Swift diff --git a/packages/rs-platform-wallet-ffi/src/tokens/burn.rs b/packages/rs-platform-wallet-ffi/src/tokens/burn.rs index acee683fd20..ab33b27de5f 100644 --- a/packages/rs-platform-wallet-ffi/src/tokens/burn.rs +++ b/packages/rs-platform-wallet-ffi/src/tokens/burn.rs @@ -86,7 +86,7 @@ pub unsafe extern "C" fn platform_wallet_token_burn( None } else { match CStr::from_ptr(public_note).to_str() { - Ok(s) if s.is_empty() => None, + Ok("") => None, Ok(s) => Some(s.to_owned()), Err(e) => { if !out_error.is_null() { diff --git a/packages/rs-platform-wallet-ffi/src/tokens/claim.rs b/packages/rs-platform-wallet-ffi/src/tokens/claim.rs index 10d6d4c66ef..bde927e3a5a 100644 --- a/packages/rs-platform-wallet-ffi/src/tokens/claim.rs +++ b/packages/rs-platform-wallet-ffi/src/tokens/claim.rs @@ -102,7 +102,7 @@ pub unsafe extern "C" fn platform_wallet_token_claim( None } else { match CStr::from_ptr(public_note).to_str() { - Ok(s) if s.is_empty() => None, + Ok("") => None, Ok(s) => Some(s.to_owned()), Err(e) => { if !out_error.is_null() { diff --git a/packages/rs-platform-wallet-ffi/src/tokens/destroy_frozen_funds.rs b/packages/rs-platform-wallet-ffi/src/tokens/destroy_frozen_funds.rs index 7d6c493f268..beccb3bcebb 100644 --- a/packages/rs-platform-wallet-ffi/src/tokens/destroy_frozen_funds.rs +++ b/packages/rs-platform-wallet-ffi/src/tokens/destroy_frozen_funds.rs @@ -97,7 +97,7 @@ pub unsafe extern "C" fn platform_wallet_token_destroy_frozen_funds( None } else { match CStr::from_ptr(public_note).to_str() { - Ok(s) if s.is_empty() => None, + Ok("") => None, Ok(s) => Some(s.to_owned()), Err(e) => { if !out_error.is_null() { diff --git a/packages/rs-platform-wallet-ffi/src/tokens/freeze.rs b/packages/rs-platform-wallet-ffi/src/tokens/freeze.rs index 5a4611a9828..65ac058d880 100644 --- a/packages/rs-platform-wallet-ffi/src/tokens/freeze.rs +++ b/packages/rs-platform-wallet-ffi/src/tokens/freeze.rs @@ -99,7 +99,7 @@ pub unsafe extern "C" fn platform_wallet_token_freeze( None } else { match CStr::from_ptr(public_note).to_str() { - Ok(s) if s.is_empty() => None, + Ok("") => None, Ok(s) => Some(s.to_owned()), Err(e) => { if !out_error.is_null() { diff --git a/packages/rs-platform-wallet-ffi/src/tokens/group_queries.rs b/packages/rs-platform-wallet-ffi/src/tokens/group_queries.rs index 0d6fb2262dd..f93b3a76d90 100644 --- a/packages/rs-platform-wallet-ffi/src/tokens/group_queries.rs +++ b/packages/rs-platform-wallet-ffi/src/tokens/group_queries.rs @@ -221,10 +221,13 @@ unsafe fn emit_json( /// "proposer": "", /// "tokenContractPosition": , /// "closed": , -/// "params": { /* per-variant payload, e.g. mint -> { amount, recipient, publicNote } */ } +/// "params": { ...per-variant payload... } /// } /// ``` /// +/// `params` carries the per-variant payload, e.g. for mint: +/// `{ "amount": "...", "recipient": "...", "publicNote": "..." }`. +/// /// `amount` / `pricePerToken` / `totalCost` are emitted as JSON /// strings to dodge JS's 53-bit integer precision cliff. Swift /// decodes them straight into `UInt64` via a helper. diff --git a/packages/rs-platform-wallet-ffi/src/tokens/mint.rs b/packages/rs-platform-wallet-ffi/src/tokens/mint.rs index fdbc8765ac8..21b5393b66e 100644 --- a/packages/rs-platform-wallet-ffi/src/tokens/mint.rs +++ b/packages/rs-platform-wallet-ffi/src/tokens/mint.rs @@ -110,7 +110,7 @@ pub unsafe extern "C" fn platform_wallet_token_mint( None } else { match CStr::from_ptr(public_note).to_str() { - Ok(s) if s.is_empty() => None, + Ok("") => None, Ok(s) => Some(s.to_owned()), Err(e) => { if !out_error.is_null() { diff --git a/packages/rs-platform-wallet-ffi/src/tokens/pause.rs b/packages/rs-platform-wallet-ffi/src/tokens/pause.rs index 06ec9a12cbd..24012bc689b 100644 --- a/packages/rs-platform-wallet-ffi/src/tokens/pause.rs +++ b/packages/rs-platform-wallet-ffi/src/tokens/pause.rs @@ -85,7 +85,7 @@ pub unsafe extern "C" fn platform_wallet_token_pause( None } else { match CStr::from_ptr(public_note).to_str() { - Ok(s) if s.is_empty() => None, + Ok("") => None, Ok(s) => Some(s.to_owned()), Err(e) => { if !out_error.is_null() { diff --git a/packages/rs-platform-wallet-ffi/src/tokens/resume.rs b/packages/rs-platform-wallet-ffi/src/tokens/resume.rs index 55d36ef9771..30ab20124c3 100644 --- a/packages/rs-platform-wallet-ffi/src/tokens/resume.rs +++ b/packages/rs-platform-wallet-ffi/src/tokens/resume.rs @@ -85,7 +85,7 @@ pub unsafe extern "C" fn platform_wallet_token_resume( None } else { match CStr::from_ptr(public_note).to_str() { - Ok(s) if s.is_empty() => None, + Ok("") => None, Ok(s) => Some(s.to_owned()), Err(e) => { if !out_error.is_null() { diff --git a/packages/rs-platform-wallet-ffi/src/tokens/set_price.rs b/packages/rs-platform-wallet-ffi/src/tokens/set_price.rs index 2e8186dd1d0..cf7daf17074 100644 --- a/packages/rs-platform-wallet-ffi/src/tokens/set_price.rs +++ b/packages/rs-platform-wallet-ffi/src/tokens/set_price.rs @@ -96,7 +96,7 @@ pub unsafe extern "C" fn platform_wallet_token_set_price( None } else { match CStr::from_ptr(public_note).to_str() { - Ok(s) if s.is_empty() => None, + Ok("") => None, Ok(s) => Some(s.to_owned()), Err(e) => { if !out_error.is_null() { diff --git a/packages/rs-platform-wallet-ffi/src/tokens/transfer.rs b/packages/rs-platform-wallet-ffi/src/tokens/transfer.rs index 981edf50442..de4677cfe48 100644 --- a/packages/rs-platform-wallet-ffi/src/tokens/transfer.rs +++ b/packages/rs-platform-wallet-ffi/src/tokens/transfer.rs @@ -99,7 +99,7 @@ pub unsafe extern "C" fn platform_wallet_token_transfer( None } else { match CStr::from_ptr(public_note).to_str() { - Ok(s) if s.is_empty() => None, + Ok("") => None, Ok(s) => Some(s.to_owned()), Err(e) => { if !out_error.is_null() { diff --git a/packages/rs-platform-wallet-ffi/src/tokens/unfreeze.rs b/packages/rs-platform-wallet-ffi/src/tokens/unfreeze.rs index 0ab11b4f422..d9fd8a80a20 100644 --- a/packages/rs-platform-wallet-ffi/src/tokens/unfreeze.rs +++ b/packages/rs-platform-wallet-ffi/src/tokens/unfreeze.rs @@ -97,7 +97,7 @@ pub unsafe extern "C" fn platform_wallet_token_unfreeze( None } else { match CStr::from_ptr(public_note).to_str() { - Ok(s) if s.is_empty() => None, + Ok("") => None, Ok(s) => Some(s.to_owned()), Err(e) => { if !out_error.is_null() { diff --git a/packages/rs-platform-wallet-ffi/src/tokens/update_config.rs b/packages/rs-platform-wallet-ffi/src/tokens/update_config.rs index 7222111805a..7c3a02a82db 100644 --- a/packages/rs-platform-wallet-ffi/src/tokens/update_config.rs +++ b/packages/rs-platform-wallet-ffi/src/tokens/update_config.rs @@ -226,7 +226,7 @@ pub unsafe extern "C" fn platform_wallet_token_update_config( None } else { match CStr::from_ptr(public_note).to_str() { - Ok(s) if s.is_empty() => None, + Ok("") => None, Ok(s) => Some(s.to_owned()), Err(e) => { if !out_error.is_null() { diff --git a/packages/rs-platform-wallet-ffi/src/wallet_restore_types.rs b/packages/rs-platform-wallet-ffi/src/wallet_restore_types.rs index 10a370a8cac..ab641964177 100644 --- a/packages/rs-platform-wallet-ffi/src/wallet_restore_types.rs +++ b/packages/rs-platform-wallet-ffi/src/wallet_restore_types.rs @@ -256,60 +256,13 @@ unsafe impl Sync for IdentityRestoreEntryFFI {} unsafe impl Send for WalletRestoreEntryFFI {} unsafe impl Sync for WalletRestoreEntryFFI {} -/// Function-pointer type for the load callback. -/// -/// Implementations must set `*out_entries` to a Swift-allocated array -/// of `WalletRestoreEntryFFI` and `*out_count` to the length. The -/// allocation is freed by the caller via `LoadWalletListFreeFn` once -/// Rust has consumed it. -/// -/// Returns 0 on success, non-zero on failure. On failure Rust does not -/// call the free callback. -pub type LoadWalletListFn = unsafe extern "C" fn( - context: *mut c_void, - out_entries: *mut *const WalletRestoreEntryFFI, - out_count: *mut usize, -) -> i32; - -/// Paired free callback for `LoadWalletListFn`. Releases any memory -/// Swift allocated for the entries array, the per-wallet accounts -/// arrays, the optional per-wallet platform-address balance arrays, -/// every xpub byte buffer, the per-wallet identity arrays, every -/// nested c-string + c-string pointer array carried by the identity -/// entries, and every per-identity `IdentityKeyRestoreFFI` array -/// together with the public-key byte buffers each row points at. -/// Called exactly once after a successful `LoadWalletListFn` -/// invocation. +/// Paired free callback for the wallet-list load callback. Releases +/// any memory Swift allocated for the entries array, the per-wallet +/// accounts arrays, the optional per-wallet platform-address balance +/// arrays, every xpub byte buffer, the per-wallet identity arrays, +/// every nested c-string + c-string pointer array carried by the +/// identity entries, and every per-identity `IdentityKeyRestoreFFI` +/// array together with the public-key byte buffers each row points +/// at. Called exactly once after a successful load. pub type LoadWalletListFreeFn = unsafe extern "C" fn(context: *mut c_void, entries: *const WalletRestoreEntryFFI, count: usize); - -/// Fires once per account when it's added to a wallet. Swift should -/// upsert into `PersistentAccount` keyed by `(wallet_id, type_tag, -/// index, ...)`. -/// -/// `spec.account_xpub_bytes` is valid only for the duration of the -/// callback. -pub type PersistAccountFn = unsafe extern "C" fn( - context: *mut c_void, - wallet_id: *const u8, - spec: *const AccountSpecFFI, -) -> i32; - -/// Fires once per wallet at registration time carrying Swift-visible -/// metadata that isn't derivable from the xpub: network tag + birth -/// height. -/// -/// `network` uses the same discriminant as -/// [`WalletRestoreEntryFFI.network`] (0 = Mainnet, 1 = Testnet, -/// 2 = Devnet, 3 = Regtest). -/// -/// `birth_height` is the best estimate of the block height at which -/// the wallet started. Zero means "scan from genesis / unknown"; -/// callers can overwrite with a better value when SPV discovers the -/// chain tip. -pub type PersistWalletMetadataFn = unsafe extern "C" fn( - context: *mut c_void, - wallet_id: *const u8, - network: u8, - birth_height: u32, -) -> i32; diff --git a/packages/rs-platform-wallet/src/wallet/tokens/group_queries.rs b/packages/rs-platform-wallet/src/wallet/tokens/group_queries.rs index c4b7aa95e3e..bff64e6ad59 100644 --- a/packages/rs-platform-wallet/src/wallet/tokens/group_queries.rs +++ b/packages/rs-platform-wallet/src/wallet/tokens/group_queries.rs @@ -124,7 +124,7 @@ impl TokenWallet { limit, }; - let rows = GroupAction::fetch_many(&*self.sdk, query) + let rows = GroupAction::fetch_many(&self.sdk, query) .await .map_err(|e| { PlatformWalletError::TokenError(format!("Fetch group actions failed: {}", e)) @@ -236,7 +236,7 @@ impl TokenWallet { action_id, }; - let rows = GroupMemberPower::fetch_many(&*self.sdk, query) + let rows = GroupMemberPower::fetch_many(&self.sdk, query) .await .map_err(|e| { PlatformWalletError::TokenError(format!("Fetch group action signers failed: {}", e)) diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/FFI/KeychainSigner.swift b/packages/swift-sdk/Sources/SwiftDashSDK/FFI/KeychainSigner.swift index a4efb2b2701..5d596e1f676 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/FFI/KeychainSigner.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/FFI/KeychainSigner.swift @@ -86,11 +86,16 @@ import SwiftData public final class KeychainSigner: Signer, @unchecked Sendable { // MARK: Public surface - /// Owned for the lifetime of this object. Pass this to any - /// `_with_signer` FFI entry point. Freed in `deinit` via - /// `dash_sdk_signer_destroy`. - public var handle: OpaquePointer { - OpaquePointer(handlePtr) + /// FFI signer handle. Pass to any `*_with_signer` entry point; + /// the underlying pointer is the C-imported + /// `UnsafeMutablePointer` from `platform-wallet-ffi.h` + /// (and equivalently `rs-sdk-ffi.h`). Owned by this object — + /// freed in `deinit` via `dash_sdk_signer_destroy`. Caller must + /// keep the `KeychainSigner` alive for the duration of any FFI + /// call that captured this pointer (see the keepalive contract + /// above). + public var handle: UnsafeMutablePointer { + handlePtr } // MARK: Errors @@ -499,7 +504,7 @@ public final class KeychainSigner: Signer, @unchecked Sendable { // signature-shape additions without an ABI change. Defer- // scrubbed below regardless of success/failure. var sigBuf = [UInt8](repeating: 0, count: 128) - var sigLen: Int = 0 + var sigLen: UInt = 0 var errTag: UInt8 = 0 defer { sigBuf.withUnsafeMutableBufferPointer { ptr in @@ -526,11 +531,11 @@ public final class KeychainSigner: Signer, @unchecked Sendable { walletPtr, pPtr, dataBase, - dataRaw.count, + UInt(dataRaw.count), ecdsaSecp256k1KeyType, self.network, bufPtr.baseAddress, - bufPtr.count, + UInt(bufPtr.count), &sigLen, &errTag ) @@ -553,7 +558,7 @@ public final class KeychainSigner: Signer, @unchecked Sendable { // Copy out the leading `sigLen` bytes BEFORE the deferred // scrub erases them. - let signature = Data(sigBuf.prefix(sigLen)) + let signature = Data(sigBuf.prefix(Int(sigLen))) return .success(signature) } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/FFI/MnemonicResolverAndPersister.swift b/packages/swift-sdk/Sources/SwiftDashSDK/FFI/MnemonicResolverAndPersister.swift index 66aab53e874..44dade9c1dc 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/FFI/MnemonicResolverAndPersister.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/FFI/MnemonicResolverAndPersister.swift @@ -139,8 +139,8 @@ public final class MnemonicResolver: @unchecked Sendable { fileprivate func resolve( walletId: Data, outBuffer: UnsafeMutablePointer, - outCapacity: Int, - outLen: UnsafeMutablePointer + outCapacity: UInt, + outLen: UnsafeMutablePointer ) -> MnemonicResolverResult { let mnemonicUTF8Bytes: Data do { @@ -172,7 +172,7 @@ public final class MnemonicResolver: @unchecked Sendable { return maskedMnemonic.withDeobfuscatedBytes { bytes -> MnemonicResolverResult in let mnemonicLen = bytes.count // Need room for the data plus a trailing NUL byte. - guard mnemonicLen + 1 <= outCapacity else { + guard UInt(mnemonicLen) + 1 <= outCapacity else { return .bufferTooSmall } guard let srcBase = bytes.baseAddress else { @@ -188,7 +188,7 @@ public final class MnemonicResolver: @unchecked Sendable { // works off `out_len` not strlen but matching the // wire contract is cheap insurance. (outBuffer + mnemonicLen).pointee = 0 - outLen.pointee = mnemonicLen + outLen.pointee = UInt(mnemonicLen) return .success } } @@ -200,8 +200,8 @@ private func mnemonicResolverResolveTrampoline( ctx: UnsafeRawPointer?, walletIdBytes: UnsafePointer?, outBuffer: UnsafeMutablePointer?, - outCapacity: Int, - outLen: UnsafeMutablePointer? + outCapacity: UInt, + outLen: UnsafeMutablePointer? ) -> Int32 { guard let ctx, let walletIdBytes, let outBuffer, let outLen else { return MnemonicResolverResult.other.rawValue @@ -281,11 +281,6 @@ public final class IdentityKeyPersister: @unchecked Sendable { private var handlePtr: UnsafeMutablePointer? public init(keychain: KeychainManager = .shared) { - // Layout sanity check before the trampoline starts firing. - // Catches Rust `#[repr(C)]` drift at construction rather - // than letting `assumingMemoryBound` blow up mid-derive. - assertPersistKeyArgsLayout() - self.keychain = keychain let ctx = Unmanaged.passUnretained(self).toOpaque() @@ -324,7 +319,7 @@ public final class IdentityKeyPersister: @unchecked Sendable { let walletIdBytes = Data(bytes: walletIdPtr, count: 32) let walletIdHex = walletIdBytes.map { String(format: "%02x", $0) }.joined() let derivationPath = String(cString: pathPtr) - let publicKeyData = Data(bytes: pubKeyPtr, count: a.public_key_len) + let publicKeyData = Data(bytes: pubKeyPtr, count: Int(a.public_key_len)) let publicKeyHex = publicKeyData.map { String(format: "%02x", $0) }.joined() let publicKeyHashData = Data(bytes: pubHashPtr, count: 20) let publicKeyHashHex = publicKeyHashData @@ -397,12 +392,11 @@ public final class IdentityKeyPersister: @unchecked Sendable { private func identityKeyPersisterPersistTrampoline( ctx: UnsafeRawPointer?, - args: UnsafeRawPointer? + args: UnsafePointer? ) -> UInt8 { - guard let ctx, let args else { return PERSIST_KEY_FAILURE } + guard let ctx, let args else { return UInt8(PERSIST_KEY_FAILURE) } let persister = Unmanaged.fromOpaque(ctx).takeUnretainedValue() - let typedArgs = args.assumingMemoryBound(to: PersistKeyArgs.self) - return persister.persist(args: typedArgs) ? PERSIST_KEY_SUCCESS : PERSIST_KEY_FAILURE + return persister.persist(args: args) ? UInt8(PERSIST_KEY_SUCCESS) : UInt8(PERSIST_KEY_FAILURE) } /// No-op destructor — see `mnemonicResolverDestroyTrampoline`. diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/AssetLock/AssetLockFFI.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/AssetLock/AssetLockFFI.swift deleted file mode 100644 index c22a4acb8a6..00000000000 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/AssetLock/AssetLockFFI.swift +++ /dev/null @@ -1,114 +0,0 @@ -// FFI declarations for AssetLockManager operations. - -import Foundation - -// MARK: - Types - -struct TrackedAssetLockFFI { - var txid: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) - var vout: UInt32 - var account_index: UInt32 - var funding_type: UInt32 - var identity_index: UInt32 - var amount: UInt64 - var status: UInt32 - var has_proof: Bool -} - -// MARK: - Manager - -@_silgen_name("asset_lock_manager_destroy") -func asset_lock_manager_destroy( - _ handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("asset_lock_manager_list_tracked_locks") -func asset_lock_manager_list_tracked_locks( - _ handle: Handle, - _ out_locks: UnsafeMutablePointer?>, - _ out_count: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("asset_lock_manager_free_tracked_locks") -func asset_lock_manager_free_tracked_locks( - _ locks: UnsafeMutablePointer?, - _ count: Int -) - -// MARK: - Build - -@_silgen_name("asset_lock_manager_build_transaction") -func asset_lock_manager_build_transaction( - _ handle: Handle, - _ amount_duffs: UInt64, - _ account_index: UInt32, - _ funding_type: UInt32, - _ identity_index: UInt32, - _ out_tx_bytes: UnsafeMutablePointer?>, - _ out_tx_len: UnsafeMutablePointer, - _ out_private_key: UnsafeMutablePointer<(UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("asset_lock_manager_create_funded_proof") -func asset_lock_manager_create_funded_proof( - _ handle: Handle, - _ amount_duffs: UInt64, - _ account_index: UInt32, - _ funding_type: UInt32, - _ identity_index: UInt32, - _ out_proof_bytes: UnsafeMutablePointer?>, - _ out_proof_len: UnsafeMutablePointer, - _ out_private_key: UnsafeMutablePointer<(UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)>, - _ out_txid: UnsafeMutablePointer<(UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("asset_lock_manager_free_tx_bytes") -func asset_lock_manager_free_tx_bytes(_ bytes: UnsafeMutablePointer?, _ len: Int) - -@_silgen_name("asset_lock_manager_free_proof_bytes") -func asset_lock_manager_free_proof_bytes(_ bytes: UnsafeMutablePointer?, _ len: Int) - -// MARK: - Sync - -@_silgen_name("asset_lock_manager_resume") -func asset_lock_manager_resume( - _ handle: Handle, - _ txid: UnsafePointer<(UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)>, - _ vout: UInt32, - _ timeout_secs: UInt64, - _ out_proof_bytes: UnsafeMutablePointer?>, - _ out_proof_len: UnsafeMutablePointer, - _ out_private_key: UnsafeMutablePointer<(UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// MARK: - Wallet accessor - -@_silgen_name("platform_wallet_get_asset_locks") -func platform_wallet_get_asset_locks( - _ handle: Handle, - _ out_asset_lock_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/AssetLock/ManagedAssetLockManager.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/AssetLock/ManagedAssetLockManager.swift index 64407cb2dc3..7a14861a138 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/AssetLock/ManagedAssetLockManager.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/AssetLock/ManagedAssetLockManager.swift @@ -78,18 +78,18 @@ public class ManagedAssetLockManager { /// List all tracked asset locks. public func listTrackedLocks() throws -> [TrackedAssetLock] { var locksPtr: UnsafeMutablePointer? = nil - var count: Int = 0 + var count: UInt = 0 var error = PlatformWalletFFIError() let result = asset_lock_manager_list_tracked_locks(handle, &locksPtr, &count, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } defer { asset_lock_manager_free_tracked_locks(locksPtr, count) } guard let locks = locksPtr, count > 0 else { return [] } - return (0.. BuildResult { var txBytesPtr: UnsafeMutablePointer? = nil - var txLen: Int = 0 + var txLen: UInt = 0 var privateKey: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, @@ -127,12 +127,15 @@ public class ManagedAssetLockManager { handle, amountDuffs, accountIndex, fundingType.rawValue, identityIndex, &txBytesPtr, &txLen, &privateKey, &error ) - guard result == Success, let txPtr = txBytesPtr, txLen > 0 else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } + guard let txPtr = txBytesPtr, txLen > 0 else { + throw PlatformWalletError.unknown("FFI returned success but transaction buffer was empty") + } defer { asset_lock_manager_free_tx_bytes(txPtr, txLen) } - let txData = Data(bytes: txPtr, count: txLen) + let txData = Data(bytes: txPtr, count: Int(txLen)) let keyData = withUnsafeBytes(of: &privateKey) { Data($0) } return BuildResult(transaction: txData, privateKey: keyData) } @@ -145,7 +148,7 @@ public class ManagedAssetLockManager { identityIndex: UInt32 = 0 ) throws -> FundedProofResult { var proofBytesPtr: UnsafeMutablePointer? = nil - var proofLen: Int = 0 + var proofLen: UInt = 0 var privateKey: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, @@ -162,13 +165,16 @@ public class ManagedAssetLockManager { handle, amountDuffs, accountIndex, fundingType.rawValue, identityIndex, &proofBytesPtr, &proofLen, &privateKey, &txid, &error ) - guard result == Success, let proofPtr = proofBytesPtr, proofLen > 0 else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } + guard let proofPtr = proofBytesPtr, proofLen > 0 else { + throw PlatformWalletError.unknown("FFI returned success but proof buffer was empty") + } defer { asset_lock_manager_free_proof_bytes(proofPtr, proofLen) } return FundedProofResult( - proofBytes: Data(bytes: proofPtr, count: proofLen), + proofBytes: Data(bytes: proofPtr, count: Int(proofLen)), privateKey: withUnsafeBytes(of: &privateKey) { Data($0) }, txid: withUnsafeBytes(of: &txid) { Data($0) } ) @@ -187,7 +193,7 @@ public class ManagedAssetLockManager { } var proofBytesPtr: UnsafeMutablePointer? = nil - var proofLen: Int = 0 + var proofLen: UInt = 0 var privateKey: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, @@ -210,13 +216,16 @@ public class ManagedAssetLockManager { handle, &txidTuple, vout, timeoutSeconds, &proofBytesPtr, &proofLen, &privateKey, &error ) - guard result == Success, let proofPtr = proofBytesPtr, proofLen > 0 else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } + guard let proofPtr = proofBytesPtr, proofLen > 0 else { + throw PlatformWalletError.unknown("FFI returned success but proof buffer was empty") + } defer { asset_lock_manager_free_proof_bytes(proofPtr, proofLen) } return ResumeResult( - proofBytes: Data(bytes: proofPtr, count: proofLen), + proofBytes: Data(bytes: proofPtr, count: Int(proofLen)), privateKey: withUnsafeBytes(of: &privateKey) { Data($0) } ) } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ContactRequest.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ContactRequest.swift index 929182f50ca..b34eb2efb69 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ContactRequest.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ContactRequest.swift @@ -44,7 +44,7 @@ public final class ContactRequest: @unchecked Sendable { recipientKeyIndex, accountReference, keyPtr.baseAddress?.assumingMemoryBound(to: UInt8.self), - encryptedPublicKey.count, + UInt(encryptedPublicKey.count), coreHeightCreatedAt, createdAt, &handle, @@ -54,7 +54,7 @@ public final class ContactRequest: @unchecked Sendable { } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -69,7 +69,7 @@ public final class ContactRequest: @unchecked Sendable { let result = buf.withUnsafeMutableBufferPointer { bp -> PlatformWalletFFIResult in contact_request_get_sender_id(handle, bp.baseAddress!, &error) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -84,7 +84,7 @@ public final class ContactRequest: @unchecked Sendable { let result = buf.withUnsafeMutableBufferPointer { bp -> PlatformWalletFFIResult in contact_request_get_recipient_id(handle, bp.baseAddress!, &error) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -97,7 +97,7 @@ public final class ContactRequest: @unchecked Sendable { var error = PlatformWalletFFIError() let result = contact_request_get_sender_key_index(handle, &keyIndex, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -110,7 +110,7 @@ public final class ContactRequest: @unchecked Sendable { var error = PlatformWalletFFIError() let result = contact_request_get_recipient_key_index(handle, &keyIndex, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -123,7 +123,7 @@ public final class ContactRequest: @unchecked Sendable { var error = PlatformWalletFFIError() let result = contact_request_get_account_reference(handle, &accountRef, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -133,11 +133,11 @@ public final class ContactRequest: @unchecked Sendable { /// Get the encrypted public key public func getEncryptedPublicKey() throws -> Data { var bytesPtr: UnsafeMutablePointer? = nil - var length: Int = 0 + var length: UInt = 0 var error = PlatformWalletFFIError() let result = contact_request_get_encrypted_public_key(handle, &bytesPtr, &length, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -160,7 +160,7 @@ public final class ContactRequest: @unchecked Sendable { var error = PlatformWalletFFIError() let result = contact_request_get_created_at(handle, &createdAt, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ContestVoteState.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ContestVoteState.swift index ec846fa5a8f..da50b9f539e 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ContestVoteState.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ContestVoteState.swift @@ -66,8 +66,8 @@ extension ContestVoteState { var contenders: [ContestContender] = [] if let ptr = ffi.contenders_ptr, ffi.contenders_count > 0 { - contenders.reserveCapacity(ffi.contenders_count) - for i in 0.. -) -> PlatformWalletFFIResult - -@_silgen_name("core_wallet_get_balance") -func core_wallet_get_balance( - _ handle: Handle, - _ out_confirmed: UnsafeMutablePointer?, - _ out_unconfirmed: UnsafeMutablePointer?, - _ out_immature: UnsafeMutablePointer?, - _ out_locked: UnsafeMutablePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("core_wallet_get_network") -func core_wallet_get_network( - _ handle: Handle, - _ out_network: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("core_wallet_next_receive_address") -func core_wallet_next_receive_address( - _ handle: Handle, - _ account_index: UInt32, - _ out_address: UnsafeMutablePointer?>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("core_wallet_next_change_address") -func core_wallet_next_change_address( - _ handle: Handle, - _ account_index: UInt32, - _ out_address: UnsafeMutablePointer?>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("core_wallet_free_address") -func core_wallet_free_address(_ address: UnsafeMutablePointer?) - -@_silgen_name("core_wallet_broadcast_transaction") -func core_wallet_broadcast_transaction( - _ handle: Handle, - _ tx_bytes: UnsafePointer?, - _ tx_bytes_len: Int, - _ out_txid: UnsafeMutablePointer?>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("core_wallet_send_to_addresses") -func core_wallet_send_to_addresses( - _ handle: Handle, - _ account_type: UInt32, - _ account_index: UInt32, - _ addresses: UnsafePointer?>?, - _ amounts: UnsafePointer?, - _ count: Int, - _ out_tx_bytes: UnsafeMutablePointer?>, - _ out_tx_len: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("core_wallet_free_tx_bytes") -func core_wallet_free_tx_bytes(_ bytes: UnsafeMutablePointer?, _ len: Int) diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/CoreWallet/ManagedCoreWallet.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/CoreWallet/ManagedCoreWallet.swift index 6cbe9ce347c..010014e85e0 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/CoreWallet/ManagedCoreWallet.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/CoreWallet/ManagedCoreWallet.swift @@ -44,7 +44,7 @@ public class ManagedCoreWallet { let result = core_wallet_get_balance( handle, &confirmed, &unconfirmed, &immature, &locked, &error ) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -62,7 +62,7 @@ public class ManagedCoreWallet { var error = PlatformWalletFFIError() let result = core_wallet_get_network(handle, &networkValue, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -77,7 +77,7 @@ public class ManagedCoreWallet { var error = PlatformWalletFFIError() let result = core_wallet_next_receive_address(handle, accountIndex, &addressPtr, &error) - guard result == Success, let ptr = addressPtr else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS, let ptr = addressPtr else { throw PlatformWalletError(result: result, error: error) } defer { core_wallet_free_address(ptr) } @@ -91,7 +91,7 @@ public class ManagedCoreWallet { var error = PlatformWalletFFIError() let result = core_wallet_next_change_address(handle, accountIndex, &addressPtr, &error) - guard result == Success, let ptr = addressPtr else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS, let ptr = addressPtr else { throw PlatformWalletError(result: result, error: error) } defer { core_wallet_free_address(ptr) } @@ -116,7 +116,7 @@ public class ManagedCoreWallet { recipients: [(address: String, amountDuffs: UInt64)] ) throws -> Data { var txBytesPtr: UnsafeMutablePointer? = nil - var txLen: Int = 0 + var txLen: UInt = 0 var error = PlatformWalletFFIError() // Build C string array @@ -131,7 +131,7 @@ public class ManagedCoreWallet { accountIndex, addrBuf.baseAddress, amountBuf.baseAddress, - recipients.count, + UInt(recipients.count), &txBytesPtr, &txLen, &error @@ -139,12 +139,12 @@ public class ManagedCoreWallet { } } - guard result == Success, let ptr = txBytesPtr, txLen > 0 else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS, let ptr = txBytesPtr, txLen > 0 else { throw PlatformWalletError(result: result, error: error) } defer { core_wallet_free_tx_bytes(ptr, txLen) } - return Data(bytes: ptr, count: txLen) + return Data(bytes: ptr, count: Int(txLen)) } /// Broadcast a raw signed transaction. @@ -158,13 +158,13 @@ public class ManagedCoreWallet { core_wallet_broadcast_transaction( handle, txBuf.baseAddress?.assumingMemoryBound(to: UInt8.self), - txData.count, + UInt(txData.count), &txidPtr, &error ) } - guard result == Success, let ptr = txidPtr else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS, let ptr = txidPtr else { throw PlatformWalletError(result: result, error: error) } defer { core_wallet_free_address(ptr) } // same free for C strings diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/CoreWalletChangeSetFFI.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/CoreWalletChangeSetFFI.swift deleted file mode 100644 index 1fde43bdc25..00000000000 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/CoreWalletChangeSetFFI.swift +++ /dev/null @@ -1,107 +0,0 @@ -// Swift-side mirrors of the repr(C) structs in -// `rs-platform-wallet-ffi/src/core_wallet_types.rs`. -// -// These structs are never constructed on the Swift side — the Rust -// persister allocates them, fires the `on_persist_wallet_changeset_fn` -// callback with a pointer, and the Swift handler casts the pointer to -// walk the data. Rust owns all heap allocations and frees them after -// the callback returns. - -import Foundation - -// 32-byte tuple type used for txids / block hashes. -typealias FFIHash32 = ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 -) - -struct OutPointFFI { - var txid: FFIHash32 - var vout: UInt32 -} - -struct ChainChangeSetFFI { - var has_synced_height: Bool - var synced_height: UInt32 - var has_block_hash: Bool - var block_hash: FFIHash32 -} - -struct BalanceChangeSetFFI { - var confirmed_delta: Int64 - var unconfirmed_delta: Int64 - var immature_delta: Int64 - var locked_delta: Int64 -} - -struct UtxoEntryFFI { - var outpoint: OutPointFFI - var amount: UInt64 - var address: UnsafeMutablePointer? - var script_pubkey: UnsafeMutablePointer? - var script_pubkey_len: Int - var height: UInt32 - var is_coinbase: Bool - var is_confirmed: Bool - var is_instantlocked: Bool - var is_locked: Bool -} - -struct TransactionRecordFFI { - var txid: FFIHash32 - var tx_data: UnsafeMutablePointer? - var tx_data_len: Int - var context: UInt32 - var block_height: UInt32 - var block_hash: FFIHash32 - var block_timestamp: UInt32 - var direction: UInt32 - var transaction_type: UnsafeMutablePointer? - var net_amount: Int64 - var fee: UInt64 - var has_fee: Bool - var label: UnsafeMutablePointer? - var first_seen: UInt64 -} - -struct AccountChangeSetFFI { - var account_type_name: UnsafeMutablePointer? - var account_index: UInt32 - var utxos_added: UnsafeMutablePointer? - var utxos_added_count: Int - var utxos_spent: UnsafeMutablePointer? - var utxos_spent_count: Int - var utxos_instant_locked: UnsafeMutablePointer? - var utxos_instant_locked_count: Int - var transactions: UnsafeMutablePointer? - var transactions_count: Int - var external_highest_used: Int32 - var has_external_highest_used: Bool - var internal_highest_used: Int32 - var has_internal_highest_used: Bool -} - -struct WalletChangeSetFFI { - var has_chain: Bool - var chain: ChainChangeSetFFI - var has_balance: Bool - var balance: BalanceChangeSetFFI - var accounts: UnsafeMutablePointer? - var accounts_count: Int -} - -// MARK: - Helpers - -/// Convert a 32-byte FFI tuple into `Data` for SwiftData persistence. -func hashData(_ hash: FFIHash32) -> Data { - withUnsafeBytes(of: hash) { Data($0) } -} - -/// Hex-encode a 32-byte FFI tuple. -func hashHex(_ hash: FFIHash32) -> String { - withUnsafeBytes(of: hash) { buf in - buf.map { String(format: "%02x", $0) }.joined() - } -} diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/EstablishedContact.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/EstablishedContact.swift index 53d490ce43d..f3937ff331e 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/EstablishedContact.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/EstablishedContact.swift @@ -24,7 +24,7 @@ public final class EstablishedContact: @unchecked Sendable { let result = buf.withUnsafeMutableBufferPointer { bp -> PlatformWalletFFIResult in established_contact_get_contact_identity_id(handle, bp.baseAddress!, &error) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -38,11 +38,11 @@ public final class EstablishedContact: @unchecked Sendable { let result = established_contact_get_alias(handle, &aliasPtr, &error) - if result == ErrorContactNotFound { + if result == PLATFORM_WALLET_FFI_RESULT_ERROR_CONTACT_NOT_FOUND { return nil } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -65,7 +65,7 @@ public final class EstablishedContact: @unchecked Sendable { let aliasCStr = (alias as NSString).utf8String let result = established_contact_set_alias(handle, aliasCStr, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } } @@ -75,7 +75,7 @@ public final class EstablishedContact: @unchecked Sendable { var error = PlatformWalletFFIError() let result = established_contact_clear_alias(handle, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } } @@ -87,11 +87,11 @@ public final class EstablishedContact: @unchecked Sendable { let result = established_contact_get_note(handle, ¬ePtr, &error) - if result == ErrorContactNotFound { + if result == PLATFORM_WALLET_FFI_RESULT_ERROR_CONTACT_NOT_FOUND { return nil } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -114,7 +114,7 @@ public final class EstablishedContact: @unchecked Sendable { let noteCStr = (note as NSString).utf8String let result = established_contact_set_note(handle, noteCStr, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } } @@ -124,7 +124,7 @@ public final class EstablishedContact: @unchecked Sendable { var error = PlatformWalletFFIError() let result = established_contact_clear_note(handle, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } } @@ -135,7 +135,7 @@ public final class EstablishedContact: @unchecked Sendable { var error = PlatformWalletFFIError() let result = established_contact_is_hidden(handle, &hidden, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -147,7 +147,7 @@ public final class EstablishedContact: @unchecked Sendable { var error = PlatformWalletFFIError() let result = established_contact_hide(handle, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } } @@ -157,7 +157,7 @@ public final class EstablishedContact: @unchecked Sendable { var error = PlatformWalletFFIError() let result = established_contact_unhide(handle, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/IdentityManager.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/IdentityManager.swift index 5ae7c09b490..95bd3c09012 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/IdentityManager.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/IdentityManager.swift @@ -24,7 +24,7 @@ public class IdentityManager { var error = PlatformWalletFFIError() let result = identity_manager_create(&handle, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -36,7 +36,7 @@ public class IdentityManager { var error = PlatformWalletFFIError() let result = identity_manager_add_identity(handle, identity.handle, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } } @@ -47,7 +47,7 @@ public class IdentityManager { let result = identityId.withFFIBytes { idPtr in identity_manager_remove_identity(handle, idPtr, &error) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } } @@ -60,7 +60,7 @@ public class IdentityManager { let result = identityId.withFFIBytes { idPtr in identity_manager_get_identity(handle, idPtr, &identityHandle, &error) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -73,7 +73,7 @@ public class IdentityManager { var error = PlatformWalletFFIError() let result = identity_manager_get_all_identity_ids(handle, &array, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -86,8 +86,8 @@ public class IdentityManager { } var identifiers: [Identifier] = [] - identifiers.reserveCapacity(array.count) - for i in 0.. Int { - var count: Int = 0 + var count: UInt = 0 var error = PlatformWalletFFIError() let result = identity_manager_get_identity_count(handle, &count, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } - return count + return Int(count) } } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/IdentityRegistrationFFI.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/IdentityRegistrationFFI.swift deleted file mode 100644 index 8c5ed5c18f2..00000000000 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/IdentityRegistrationFFI.swift +++ /dev/null @@ -1,198 +0,0 @@ -// Identity registration FFI function declarations -// Mirrors packages/rs-platform-wallet-ffi/src/identity_registration.rs. -// -// The rs-platform-wallet-ffi crate does not emit a public C header (see -// its `lib.rs`: everything is `#[no_mangle] extern "C"`), so the Swift -// side declares the symbols with @_silgen_name the same way the rest -// of the platform-wallet FFI surface is wired up. - -import Foundation - -// MARK: - FFI Structs - -/// Mirrors `IdentityFundingInputFFI` from Rust. -/// -/// Nonces are intentionally absent — the SDK fetches each address's -/// on-chain nonce at submit time, so callers only need to name the -/// address + the credit amount to spend. -/// -/// - `address_type`: 0 = P2PKH, 1 = P2SH. -/// - `hash`: 20-byte address hash (BE tuple of `UInt8` x 20). -/// - `credits`: credits to spend from this address. -@frozen -public struct IdentityFundingInputFFI { - public var address_type: UInt8 - public var hash: ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - ) - public var credits: UInt64 -} - -/// Mirrors `IdentityFundingOutputFFI` from Rust. When `has_output` is -/// false the remaining fields are ignored. -@frozen -public struct IdentityFundingOutputFFI { - public var has_output: Bool - public var address_type: UInt8 - public var hash: ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - ) - public var credits: UInt64 -} - -/// Mirrors `IdentityPubkeyFFI` from Rust -/// (`packages/rs-platform-wallet-ffi/src/identity_registration_with_signer.rs`). -/// -/// One already-derived authentication public key the caller wants the -/// new identity to register. Used by -/// `platform_wallet_register_identity_with_signer` in place of the -/// previous `key_count: UInt32` argument so that pubkey derivation can -/// happen entirely in Swift (via -/// `dash_sdk_derive_identity_keys_from_mnemonic`, which works for -/// watch-only wallets) rather than via the wallet handle on the Rust -/// side. -/// -/// Field discriminants match the DPP `repr(u8)` enum layouts: -/// - `key_type`: KeyType discriminant (0 = ECDSA_SECP256K1, etc.) -/// - `purpose`: Purpose discriminant (0 = AUTHENTICATION, etc.) -/// - `security_level`: SecurityLevel discriminant (0 = MASTER, 1 = -/// CRITICAL, 2 = HIGH, 3 = MEDIUM) -/// -/// `pubkey_bytes` is borrowed by the FFI for the duration of the call; -/// the caller retains ownership of the buffer. -@frozen -public struct IdentityPubkeyFFI { - public var key_id: UInt32 - public var key_type: UInt8 - public var purpose: UInt8 - public var security_level: UInt8 - public var pubkey_bytes: UnsafePointer? - public var pubkey_len: Int - public var read_only: Bool - /// Contract-bounds discriminant. `0` = no bounds (Authentication - /// / Transfer / etc.), `1` = `SingleContract` (Encryption / - /// Decryption restricted to a contract), `2` = - /// `SingleContractDocumentType` (further narrowed to a - /// document type within the contract). - public var contract_bounds_kind: UInt8 - /// 32-byte contract id when `contract_bounds_kind != 0`. Null - /// otherwise. Borrowed for the duration of the FFI call. - public var contract_bounds_id: UnsafePointer? - /// NUL-terminated UTF-8 document type name when - /// `contract_bounds_kind == 2`. Null otherwise. Borrowed for - /// the duration of the FFI call. - public var contract_bounds_document_type: UnsafePointer? -} - -// MARK: - FFI Functions - -// NOTE: The legacy mnemonic-driven `platform_wallet_register_identity_from_addresses` -// FFI has been deleted; the Rust crate no longer exports it. The -// signer-driven entry point below is the only supported path. - -/// Mirrors `platform_wallet_register_identity_with_signer` from Rust. -/// -/// Drops the BIP-39 mnemonic + passphrase parameters in favor of TWO -/// opaque `*mut SignerHandle`s — one for the new identity's -/// state-transition keys, one for each input platform address's -/// funding-contribution signature. The new identity's authentication -/// pubkeys are passed in by the caller via `identity_pubkeys` (an -/// array of `IdentityPubkeyFFI` rows) — Swift derives them via -/// `dash_sdk_derive_identity_keys_from_mnemonic` first, which works -/// for watch-only wallets where Rust has no in-process xpriv loaded. -/// Every signature crosses the FFI through the appropriate signer. -/// -/// The two-handle split keeps the FFI explicit about both signing -/// roles (callers pass the same `KeychainSigner.handle` for both in -/// the common iOS case; future watch-only / hardware paths can wire -/// distinct signers per role without another ABI change). The -/// underlying `VTableSigner` implements `Signer` -/// AND `Signer` and dispatches by `key_type` byte -/// (KeyType discriminants 0–4 → identity-key lookup; `0xFF` → -/// platform-address-hash lookup; see `KeychainSigner.swift`). -@_silgen_name("platform_wallet_register_identity_with_signer") -func platform_wallet_register_identity_with_signer( - _ wallet_handle: Handle, - _ identity_index: UInt32, - // Caller-derived authentication pubkeys for the new identity. - // Each row carries `(key_id, key_type, purpose, security_level, - // pubkey_bytes, pubkey_len, read_only)`. The buffer is borrowed — - // Rust copies what it needs before the call returns. - _ identity_pubkeys: UnsafePointer?, - _ identity_pubkeys_count: Int, - // Raw `*mut SignerHandle` produced by `dash_sdk_signer_create_with_ctx` - // (e.g. via `KeychainSigner.handle`). Used as `Signer`. - // Caller retains ownership; this function does NOT destroy it. - _ signer_identity_handle: OpaquePointer?, - // Raw `*mut SignerHandle`. Used as `Signer` — - // the trampoline receives `key_type == 0xFF` and a 20-byte - // address hash. Typically the same value as - // `signer_identity_handle`; pass distinct handles for watch-only - // wallets that route the two roles to different stores. - _ signer_address_handle: OpaquePointer?, - _ inputs: UnsafePointer?, - _ inputs_count: Int, - _ output: UnsafePointer?, - _ out_identity_id: UnsafeMutablePointer<( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - )>, - _ out_identity_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -/// Mirrors `platform_wallet_top_up_from_addresses_with_signer` from -/// Rust (`packages/rs-platform-wallet-ffi/src/identity_top_up.rs`). -/// -/// Top up an existing identity's credit balance from one or more -/// Platform addresses. Reuses the `IdentityFundingInputFFI` row shape -/// the registration FFI exposes — each row names one input address + -/// the credit amount to spend from it. -/// -/// Top-up state-transitions are signed with the Platform address -/// inputs' private keys (not the identity's authentication keys), so -/// only one signer handle is required: `signer_address_handle`, -/// dispatching `key_type == 0xFF` through the Swift `KeychainSigner` -/// trampoline. -/// -/// On success `out_new_balance` is populated with the post-transition -/// credit balance returned by Platform. The Rust-side -/// `ManagedIdentity` for `identity_id` has its balance updated -/// inside the library call; subsequent reads through the same handle -/// reflect the new value without a round trip. -@_silgen_name("platform_wallet_top_up_from_addresses_with_signer") -func platform_wallet_top_up_from_addresses_with_signer( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer<( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - )>, - _ inputs: UnsafePointer?, - _ inputs_count: Int, - _ signer_address_handle: OpaquePointer?, - _ out_new_balance: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// MARK: - Platform-address private-key pre-derivation — REMOVED -// -// The previous design pre-derived platform-address private keys in -// Rust, exported them across the FFI as 32-byte scalars, and had -// Swift persist them in the Keychain keyed by 20-byte address hash. -// That violated the rule that platform-address private keys are -// NEVER persisted — they are pure derivation outputs of -// `(mnemonic, path)` and exist only for the duration of a single -// signing call. -// -// The replacement is `dash_sdk_sign_with_mnemonic_and_path` in -// `KeychainSigner.swift`'s `key_type == 0xFF` branch: pull mnemonic -// from Keychain + derivation path from `PersistentPlatformAddress`, -// hand both to one Rust FFI call that derives, signs, and zeroes -// in-place. No `PlatformAddressPrivateKey(s)FFI`, no Keychain entry -// for the derived bytes, no exporting them across the FFI. diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ManagedIdentity.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ManagedIdentity.swift index a0cc55bfc32..345233b1f29 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ManagedIdentity.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ManagedIdentity.swift @@ -26,13 +26,13 @@ public final class ManagedIdentity: @unchecked Sendable { let result = bytes.withUnsafeBytes { bytesPtr in managed_identity_create_from_identity_bytes( bytesPtr.baseAddress?.assumingMemoryBound(to: UInt8.self), - bytes.count, + UInt(bytes.count), &handle, &error ) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -47,7 +47,7 @@ public final class ManagedIdentity: @unchecked Sendable { let result = buf.withUnsafeMutableBufferPointer { bp -> PlatformWalletFFIResult in managed_identity_get_id(handle, bp.baseAddress!, &error) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -60,7 +60,7 @@ public final class ManagedIdentity: @unchecked Sendable { var error = PlatformWalletFFIError() let result = managed_identity_get_balance(handle, &balance, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -77,7 +77,7 @@ public final class ManagedIdentity: @unchecked Sendable { var error = PlatformWalletFFIError() let result = managed_identity_get_revision(handle, &revision, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } return revision @@ -99,7 +99,7 @@ public final class ManagedIdentity: @unchecked Sendable { var error = PlatformWalletFFIError() let result = managed_identity_get_identity_index(handle, &hasIndex, &index, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } return hasIndex ? index : nil @@ -112,7 +112,7 @@ public final class ManagedIdentity: @unchecked Sendable { var error = PlatformWalletFFIError() let result = managed_identity_get_status(handle, &raw, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } return IdentityStatus(rawValue: raw) ?? .unknown @@ -142,7 +142,7 @@ public final class ManagedIdentity: @unchecked Sendable { /// returning. public func getPublicKeys() throws -> [IdentityPublicKeyInfo] { var outPtr: UnsafeMutablePointer? = nil - var outCount: Int = 0 + var outCount: UInt = 0 var error = PlatformWalletFFIError() let result = managed_identity_get_public_keys( @@ -151,7 +151,7 @@ public final class ManagedIdentity: @unchecked Sendable { &outCount, &error ) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -165,8 +165,8 @@ public final class ManagedIdentity: @unchecked Sendable { } var keys: [IdentityPublicKeyInfo] = [] - keys.reserveCapacity(outCount) - for i in 0.. 0 { - data = Data(bytes: blob, count: ffi.data_len) + data = Data(bytes: blob, count: Int(ffi.data_len)) } else { data = Data() } @@ -213,11 +213,11 @@ public final class ManagedIdentity: @unchecked Sendable { let result = managed_identity_get_label(handle, &labelPtr, &error) - if result == ErrorIdentityNotFound { + if result == PLATFORM_WALLET_FFI_RESULT_ERROR_IDENTITY_NOT_FOUND { return nil } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -240,69 +240,69 @@ public final class ManagedIdentity: @unchecked Sendable { let labelCStr = (label as NSString).utf8String let result = managed_identity_set_label(handle, labelCStr, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } } /// Get the last updated balance block time public func getLastUpdatedBalanceBlockTime() throws -> BlockTime? { - var ffiBlockTime = FFIBlockTime(height: 0, core_height: 0, timestamp: 0) + var blockTime = BlockTime() var error = PlatformWalletFFIError() - let result = managed_identity_get_last_updated_balance_block_time(handle, &ffiBlockTime, &error) + let result = managed_identity_get_last_updated_balance_block_time(handle, &blockTime, &error) - if result == ErrorIdentityNotFound { + if result == PLATFORM_WALLET_FFI_RESULT_ERROR_IDENTITY_NOT_FOUND { return nil } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } - return BlockTime(ffiBlockTime: ffiBlockTime) + return blockTime } /// Set the last updated balance block time public func setLastUpdatedBalanceBlockTime(_ blockTime: BlockTime) throws { var error = PlatformWalletFFIError() - var ffiBlockTime = blockTime.ffiValue + var bt = blockTime let result = managed_identity_set_last_updated_balance_block_time( - handle, &ffiBlockTime, &error + handle, &bt, &error ) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } } /// Get the last synced keys block time public func getLastSyncedKeysBlockTime() throws -> BlockTime? { - var ffiBlockTime = FFIBlockTime(height: 0, core_height: 0, timestamp: 0) + var blockTime = BlockTime() var error = PlatformWalletFFIError() - let result = managed_identity_get_last_synced_keys_block_time(handle, &ffiBlockTime, &error) + let result = managed_identity_get_last_synced_keys_block_time(handle, &blockTime, &error) - if result == ErrorIdentityNotFound { + if result == PLATFORM_WALLET_FFI_RESULT_ERROR_IDENTITY_NOT_FOUND { return nil } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } - return BlockTime(ffiBlockTime: ffiBlockTime) + return blockTime } // MARK: - Contact Request Management /// Get all sent contact request IDs public func getSentContactRequestIds() throws -> [Identifier] { - var array = IdentifierArray(items: nil, count: 0) + var array = IdentifierArray() var error = PlatformWalletFFIError() let result = managed_identity_get_sent_contact_request_ids(handle, &array, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -315,8 +315,8 @@ public final class ManagedIdentity: @unchecked Sendable { } var identifiers: [Identifier] = [] - identifiers.reserveCapacity(array.count) - for i in 0.. [Identifier] { - var array = IdentifierArray(items: nil, count: 0) + var array = IdentifierArray() var error = PlatformWalletFFIError() let result = managed_identity_get_incoming_contact_request_ids(handle, &array, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -342,8 +342,8 @@ public final class ManagedIdentity: @unchecked Sendable { } var identifiers: [Identifier] = [] - identifiers.reserveCapacity(array.count) - for i in 0.. [Identifier] { - var array = IdentifierArray(items: nil, count: 0) + var array = IdentifierArray() var error = PlatformWalletFFIError() let result = managed_identity_get_established_contact_ids(handle, &array, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -369,8 +369,8 @@ public final class ManagedIdentity: @unchecked Sendable { } var identifiers: [Identifier] = [] - identifiers.reserveCapacity(array.count) - for i in 0.. PlatformWalletFFIResult ) throws -> [String] { - var array = DpnsNameArray(labels: nil, count: 0) + var array = DpnsNameArray() var error = PlatformWalletFFIError() let result = fetch(&array, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } defer { dpns_name_array_free(&array) } @@ -528,8 +528,8 @@ public final class ManagedIdentity: @unchecked Sendable { return [] } var names: [String] = [] - names.reserveCapacity(array.count) - for i in 0.. DashPayProfile? { - var ffiProfile = dashPayProfileFFIEmpty() + var ffiProfile = DashPayProfileFFI() var hasProfile: Bool = false var error = PlatformWalletFFIError() @@ -557,7 +557,7 @@ public final class ManagedIdentity: @unchecked Sendable { &hasProfile, &error ) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ManagedPlatformAddressWallet.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ManagedPlatformAddressWallet.swift index 8f1e6cf73e6..42329908a01 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ManagedPlatformAddressWallet.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ManagedPlatformAddressWallet.swift @@ -40,7 +40,7 @@ public final class ManagedPlatformAddressWallet: @unchecked Sendable { let result = platform_address_wallet_total_credits(handle, &credits, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -50,14 +50,14 @@ public final class ManagedPlatformAddressWallet: @unchecked Sendable { /// Get all platform addresses with their cached balances. public func addressesWithBalances() throws -> [AddressBalance] { var entriesPtr: UnsafeMutablePointer? - var count: Int = 0 + var count: UInt = 0 var error = PlatformWalletFFIError() let result = platform_address_wallet_addresses_with_balances( handle, &entriesPtr, &count, &error ) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -69,7 +69,7 @@ public final class ManagedPlatformAddressWallet: @unchecked Sendable { return [] } - return (0.. 0 { - pubData = Data(bytes: pubPtr, count: row.public_key_len) + pubData = Data(bytes: pubPtr, count: Int(row.public_key_len)) pubHex = pubData.map { String(format: "%02x", $0) }.joined() } else { pubData = Data() @@ -903,7 +903,7 @@ extension ManagedPlatformWallet { } let resolver = MnemonicResolver(storage: storage) - var row = identityKeyPreviewFFIEmpty() + var row = IdentityKeyPreviewFFI() var error = PlatformWalletFFIError() let result = self.walletId.withUnsafeBytes { walletBytes -> PlatformWalletFFIResult in @@ -920,7 +920,7 @@ extension ManagedPlatformWallet { } defer { dash_sdk_derive_identity_key_at_slot_free(&row) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -930,7 +930,7 @@ extension ManagedPlatformWallet { let pubData: Data let pubHex: String if let pubPtr = row.public_key, row.public_key_len > 0 { - pubData = Data(bytes: pubPtr, count: row.public_key_len) + pubData = Data(bytes: pubPtr, count: Int(row.public_key_len)) pubHex = pubData.map { String(format: "%02x", $0) }.joined() } else { pubData = Data() @@ -1034,7 +1034,7 @@ extension ManagedPlatformWallet { let resolver = MnemonicResolver(storage: storage) let persister = IdentityKeyPersister(keychain: keychain) - var out = identityRegistrationKeyDerivationsFFIEmpty() + var out = IdentityRegistrationKeyDerivationsFFI() var error = PlatformWalletFFIError() // `walletId` is `Data`; bind into a 32-byte UInt8 pointer @@ -1055,7 +1055,7 @@ extension ManagedPlatformWallet { } defer { dash_sdk_derive_identity_keys_from_mnemonic_free(&out) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -1077,7 +1077,7 @@ extension ManagedPlatformWallet { // fail loudly so the caller learns about the ABI break // immediately. let captured = persister.persistedKeys - guard captured.count == out.count, out.count == Int(keyCount) else { + guard captured.count == Int(out.count), Int(out.count) == Int(keyCount) else { throw PlatformWalletError.walletOperation( "derive_and_persist_identity_keys returned \(out.count) pubkeys for " + "\(keyCount) requested keys; persister captured \(captured.count)" @@ -1085,8 +1085,8 @@ extension ManagedPlatformWallet { } var pubkeys: [IdentityPubkey] = [] - pubkeys.reserveCapacity(out.count) - for i in 0.. [Identifier] in - var found = discoveredIdentityIdsFFIEmpty() + var found = DiscoveredIdentityIdsFFI() var error = PlatformWalletFFIError() let result = platform_wallet_discover_identities( handle, @@ -1186,15 +1186,15 @@ extension ManagedPlatformWallet { &error ) defer { platform_wallet_discover_identities_free(&found) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } guard let base = found.ids, found.count > 0 else { return [] } var ids: [Identifier] = [] - ids.reserveCapacity(found.count) - for i in 0.. [DpnsSearchResult] in var outPtr: UnsafeMutablePointer? = nil - var outCount: Int = 0 + var outCount: UInt = 0 var error = PlatformWalletFFIError() let result = prefix.withCString { prefixPtr in platform_wallet_search_dpns_names( @@ -1339,7 +1339,7 @@ extension ManagedPlatformWallet { &error ) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } guard let ptr = outPtr, outCount > 0 else { @@ -1347,8 +1347,8 @@ extension ManagedPlatformWallet { } defer { dpns_search_results_free(ptr, outCount) } var results: [DpnsSearchResult] = [] - results.reserveCapacity(outCount) - for i in 0.. ContestVoteState? in - var state = contestVoteStateFFIEmpty() + var state = ContestVoteStateFFI() var found = false var error = PlatformWalletFFIError() let result = idBytes.withUnsafeBufferPointer { idBp -> PlatformWalletFFIResult in @@ -1429,7 +1429,7 @@ extension ManagedPlatformWallet { } } defer { contest_vote_state_ffi_free(&state) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } guard found else { return nil } @@ -1465,7 +1465,7 @@ extension ManagedPlatformWallet { &error ) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } return count @@ -1495,7 +1495,7 @@ extension ManagedPlatformWallet { &error ) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } return ManagedIdentity(handle: outHandle) @@ -1509,10 +1509,10 @@ extension ManagedPlatformWallet { public func syncContactRequests() async throws -> [ContactRequest] { let handle = self.handle return try await Task.detached(priority: .userInitiated) { () -> [ContactRequest] in - var array = ContactRequestHandleArray(handles: nil, count: 0) + var array = ContactRequestHandleArray() var error = PlatformWalletFFIError() let result = platform_wallet_sync_contact_requests(handle, &array, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } defer { platform_wallet_contact_request_handle_array_free(&array) } @@ -1520,8 +1520,8 @@ extension ManagedPlatformWallet { return [] } var requests: [ContactRequest] = [] - requests.reserveCapacity(array.count) - for i in 0.. DashPayProfile? { - var ffiProfile = dashPayProfileFFIEmpty() + var ffiProfile = DashPayProfileFFI() var hasProfile: Bool = false var error = PlatformWalletFFIError() @@ -1808,7 +1808,7 @@ extension ManagedPlatformWallet { } defer { dashpay_profile_ffi_free(&ffiProfile) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } guard hasProfile else { return nil } @@ -1836,7 +1836,7 @@ extension ManagedPlatformWallet { &syncedCount, &error ) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } return syncedCount @@ -1899,7 +1899,7 @@ extension ManagedPlatformWallet { return try await Task.detached(priority: .userInitiated) { () -> DashPayProfile in _ = signer - var outProfile = dashPayProfileFFIEmpty() + var outProfile = DashPayProfileFFI() var error = PlatformWalletFFIError() let result: PlatformWalletFFIResult = idBytes.withUnsafeBufferPointer { @@ -1921,7 +1921,7 @@ extension ManagedPlatformWallet { msgPtr, urlPtr, bytesPtr, - avatarBytes.count, + UInt(avatarBytes.count), doCreate, signerHandle, &outProfile, @@ -1949,7 +1949,7 @@ extension ManagedPlatformWallet { defer { dashpay_profile_ffi_free(&outProfile) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } return DashPayProfile(ffi: outProfile) @@ -2034,23 +2034,23 @@ extension ManagedPlatformWallet { /// counts and watermarks the Wallet Memory Explorer view surfaces /// at the top of the per-wallet detail screen. public func inMemorySummary() throws -> InMemoryWalletSummary { - var ffi = platformWalletMemorySummaryFFIEmpty() + var ffi = PlatformWalletMemorySummaryFFI() var error = PlatformWalletFFIError() let result = platform_wallet_get_in_memory_summary(handle, &ffi, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } return InMemoryWalletSummary( - identitiesCount: ffi.identities_count, - watchedCount: ffi.watched_count, + identitiesCount: Int(ffi.identities_count), + watchedCount: Int(ffi.watched_count), lastScannedIndex: ffi.last_scanned_index, // Primary-identity selection no longer lives on the Rust // side; UI layer owns it now. primaryIdentityId: nil, - trackedAssetLocksCount: ffi.tracked_asset_locks_count, - tokenBalancesCount: ffi.token_balances_count + trackedAssetLocksCount: Int(ffi.tracked_asset_locks_count), + tokenBalancesCount: Int(ffi.token_balances_count) ) } @@ -2061,10 +2061,10 @@ extension ManagedPlatformWallet { private func readIdentifierArray( _ fetch: (inout IdentifierArray, inout PlatformWalletFFIError) -> PlatformWalletFFIResult ) throws -> [Identifier] { - var array = IdentifierArray(items: nil, count: 0) + var array = IdentifierArray() var error = PlatformWalletFFIError() let result = fetch(&array, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } defer { platform_wallet_identifier_array_free(&array) } @@ -2072,8 +2072,8 @@ extension ManagedPlatformWallet { return [] } var ids: [Identifier] = [] - ids.reserveCapacity(array.count) - for i in 0..?, - _ seed_len: Int, - _ out_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_info_create_from_mnemonic") -func platform_wallet_info_create_from_mnemonic( - _ network: NetworkType, - _ mnemonic: UnsafePointer?, - _ passphrase: UnsafePointer?, - _ out_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_info_get_identity_manager") -func platform_wallet_info_get_identity_manager( - _ wallet_handle: Handle, - _ out_manager_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_info_set_identity_manager") -func platform_wallet_info_set_identity_manager( - _ wallet_handle: Handle, - _ manager_handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_info_destroy") -func platform_wallet_info_destroy(_ handle: Handle) -> PlatformWalletFFIResult - -// MARK: - IdentityManager Functions - -@_silgen_name("identity_manager_create") -func identity_manager_create( - _ out_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("identity_manager_add_identity") -func identity_manager_add_identity( - _ manager_handle: Handle, - _ identity_handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("identity_manager_remove_identity") -func identity_manager_remove_identity( - _ manager_handle: Handle, - _ identity_id: UnsafePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("identity_manager_get_identity") -func identity_manager_get_identity( - _ manager_handle: Handle, - _ identity_id: UnsafePointer, - _ out_identity_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("identity_manager_get_all_identity_ids") -func identity_manager_get_all_identity_ids( - _ manager_handle: Handle, - _ out_array: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// Note: `identity_manager_get_primary_identity_id` / -// `identity_manager_set_primary_identity` were removed alongside the -// underlying Rust field. Primary-identity selection moved to the UI -// layer (e.g. `WalletDataModel.selectedIdentityId` on the Swift side). - -@_silgen_name("identity_manager_get_identity_count") -func identity_manager_get_identity_count( - _ manager_handle: Handle, - _ out_count: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("identity_manager_destroy") -func identity_manager_destroy(_ handle: Handle) -> PlatformWalletFFIResult - -// MARK: - ManagedIdentity Functions - -@_silgen_name("managed_identity_create_from_identity_bytes") -func managed_identity_create_from_identity_bytes( - _ bytes: UnsafePointer?, - _ bytes_len: Int, - _ out_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_get_id") -func managed_identity_get_id( - _ identity_handle: Handle, - _ out_id: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_get_balance") -func managed_identity_get_balance( - _ identity_handle: Handle, - _ out_balance: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_get_label") -func managed_identity_get_label( - _ identity_handle: Handle, - _ out_label: UnsafeMutablePointer?>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_set_label") -func managed_identity_set_label( - _ identity_handle: Handle, - _ label: UnsafePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_get_last_updated_balance_block_time") -func managed_identity_get_last_updated_balance_block_time( - _ identity_handle: Handle, - _ out_block_time: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_set_last_updated_balance_block_time") -func managed_identity_set_last_updated_balance_block_time( - _ identity_handle: Handle, - _ block_time: UnsafePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_get_last_synced_keys_block_time") -func managed_identity_get_last_synced_keys_block_time( - _ identity_handle: Handle, - _ out_block_time: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// MARK: - Revision / public keys - -@_silgen_name("managed_identity_get_revision") -func managed_identity_get_revision( - _ identity_handle: Handle, - _ out_revision: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -/// Mirrors `IdentityPublicKeyFFI` from -/// `rs-platform-wallet-ffi/src/managed_identity.rs`. See there for -/// the field semantics and ownership rules. -struct IdentityPublicKeyFFI { - var key_id: UInt32 - var purpose: UInt8 - var security_level: UInt8 - var key_type: UInt8 - var read_only: Bool - var disabled_at_is_some: Bool - var disabled_at: UInt64 - var data_ptr: UnsafeMutablePointer? - var data_len: Int -} - -@_silgen_name("managed_identity_get_public_keys") -func managed_identity_get_public_keys( - _ identity_handle: Handle, - _ out_keys: UnsafeMutablePointer?>, - _ out_count: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_free_public_keys") -func managed_identity_free_public_keys( - _ keys: UnsafeMutablePointer?, - _ count: Int -) - -@_silgen_name("managed_identity_get_sent_contact_request_ids") -func managed_identity_get_sent_contact_request_ids( - _ identity_handle: Handle, - _ out_array: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_get_incoming_contact_request_ids") -func managed_identity_get_incoming_contact_request_ids( - _ identity_handle: Handle, - _ out_array: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_get_established_contact_ids") -func managed_identity_get_established_contact_ids( - _ identity_handle: Handle, - _ out_array: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_get_sent_contact_request") -func managed_identity_get_sent_contact_request( - _ identity_handle: Handle, - _ recipient_id: UnsafePointer, - _ out_request_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_get_incoming_contact_request") -func managed_identity_get_incoming_contact_request( - _ identity_handle: Handle, - _ sender_id: UnsafePointer, - _ out_request_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_get_established_contact") -func managed_identity_get_established_contact( - _ identity_handle: Handle, - _ contact_id: UnsafePointer, - _ out_contact_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_is_contact_established") -func managed_identity_is_contact_established( - _ identity_handle: Handle, - _ contact_id: UnsafePointer, - _ out_is_established: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_send_contact_request") -func managed_identity_send_contact_request( - _ identity_handle: Handle, - _ request_handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_accept_contact_request") -func managed_identity_accept_contact_request( - _ identity_handle: Handle, - _ request_handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_reject_contact_request") -func managed_identity_reject_contact_request( - _ identity_handle: Handle, - _ sender_id: UnsafePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_destroy") -func managed_identity_destroy(_ handle: Handle) -> PlatformWalletFFIResult - -// MARK: - DashPay Profile - -/// Mirrors `DashPayProfileFFI` from -/// `rs-platform-wallet-ffi/src/dashpay_profile.rs`. See there for -/// field semantics and ownership rules. -/// -/// `display_name`, `public_message`, `avatar_url` are heap-allocated -/// C strings (nullable); the caller releases them with -/// `dashpay_profile_ffi_free`. `avatar_hash` / `avatar_fingerprint` -/// are inline arrays — read them only when the corresponding -/// `_is_some` flag is true. -struct DashPayProfileFFI { - var display_name: UnsafeMutablePointer? - var public_message: UnsafeMutablePointer? - var avatar_url: UnsafeMutablePointer? - var avatar_hash_is_some: Bool - var avatar_hash: ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - ) - var avatar_fingerprint_is_some: Bool - var avatar_fingerprint: ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - ) -} - -/// All-zero `DashPayProfileFFI` — used as the out-param initial -/// value. Writing an empty instance before the FFI call guarantees -/// any early-exit paths still leave a well-defined struct. -func dashPayProfileFFIEmpty() -> DashPayProfileFFI { - DashPayProfileFFI( - display_name: nil, - public_message: nil, - avatar_url: nil, - avatar_hash_is_some: false, - avatar_hash: ( - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0 - ), - avatar_fingerprint_is_some: false, - avatar_fingerprint: (0, 0, 0, 0, 0, 0, 0, 0) - ) -} - -@_silgen_name("managed_identity_get_dashpay_profile") -func managed_identity_get_dashpay_profile( - _ identity_handle: Handle, - _ out_profile: UnsafeMutablePointer, - _ out_has_profile: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_get_dashpay_profile") -func platform_wallet_get_dashpay_profile( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ out_profile: UnsafeMutablePointer, - _ out_has_profile: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("dashpay_profile_ffi_free") -func dashpay_profile_ffi_free(_ profile: UnsafeMutablePointer) - -@_silgen_name("platform_wallet_sync_dashpay_profiles") -func platform_wallet_sync_dashpay_profiles( - _ wallet_handle: Handle, - _ out_synced_count: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -/// Mirrors `platform_wallet_create_or_update_dashpay_profile_with_signer` -/// from Rust (`packages/rs-platform-wallet-ffi/src/dashpay_profile.rs`). -/// -/// `do_create == true` calls -/// `IdentityWallet::create_profile_with_external_signer`; `false` -/// calls `update_profile_with_external_signer`. Both route the -/// document state-transition signature through the supplied -/// `signer_handle` (typically `KeychainSigner.handle`). Required for -/// watch-only wallets and the architecturally correct path per -/// `swift-sdk/CLAUDE.md`. -@_silgen_name("platform_wallet_create_or_update_dashpay_profile_with_signer") -func platform_wallet_create_or_update_dashpay_profile_with_signer( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ display_name: UnsafePointer?, - _ public_message: UnsafePointer?, - _ avatar_url: UnsafePointer?, - _ avatar_bytes: UnsafePointer?, - _ avatar_bytes_len: Int, - _ do_create: Bool, - _ signer_handle: OpaquePointer?, - _ out_profile: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// MARK: - ContactRequest Functions - -@_silgen_name("contact_request_create") -func contact_request_create( - _ sender_id: UnsafePointer, - _ recipient_id: UnsafePointer, - _ sender_key_index: UInt32, - _ recipient_key_index: UInt32, - _ account_reference: UInt32, - _ encrypted_public_key: UnsafePointer?, - _ encrypted_public_key_len: Int, - _ core_height_created_at: UInt32, - _ created_at: UInt64, - _ out_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("contact_request_get_sender_id") -func contact_request_get_sender_id( - _ request_handle: Handle, - _ out_id: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("contact_request_get_recipient_id") -func contact_request_get_recipient_id( - _ request_handle: Handle, - _ out_id: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("contact_request_get_sender_key_index") -func contact_request_get_sender_key_index( - _ request_handle: Handle, - _ out_index: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("contact_request_get_recipient_key_index") -func contact_request_get_recipient_key_index( - _ request_handle: Handle, - _ out_index: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("contact_request_get_account_reference") -func contact_request_get_account_reference( - _ request_handle: Handle, - _ out_reference: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("contact_request_get_encrypted_public_key") -func contact_request_get_encrypted_public_key( - _ request_handle: Handle, - _ out_bytes: UnsafeMutablePointer?>, - _ out_len: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("contact_request_get_created_at") -func contact_request_get_created_at( - _ request_handle: Handle, - _ out_timestamp: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("contact_request_destroy") -func contact_request_destroy(_ handle: Handle) -> PlatformWalletFFIResult - -// MARK: - EstablishedContact Functions - -@_silgen_name("established_contact_get_contact_identity_id") -func established_contact_get_contact_identity_id( - _ contact_handle: Handle, - _ out_id: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("established_contact_get_alias") -func established_contact_get_alias( - _ contact_handle: Handle, - _ out_alias: UnsafeMutablePointer?>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("established_contact_set_alias") -func established_contact_set_alias( - _ contact_handle: Handle, - _ alias: UnsafePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("established_contact_clear_alias") -func established_contact_clear_alias( - _ contact_handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("established_contact_get_note") -func established_contact_get_note( - _ contact_handle: Handle, - _ out_note: UnsafeMutablePointer?>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("established_contact_set_note") -func established_contact_set_note( - _ contact_handle: Handle, - _ note: UnsafePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("established_contact_clear_note") -func established_contact_clear_note( - _ contact_handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("established_contact_is_hidden") -func established_contact_is_hidden( - _ contact_handle: Handle, - _ out_is_hidden: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("established_contact_hide") -func established_contact_hide( - _ contact_handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("established_contact_unhide") -func established_contact_unhide( - _ contact_handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("established_contact_destroy") -func established_contact_destroy(_ handle: Handle) -> PlatformWalletFFIResult - -// MARK: - Utility Functions - -@_silgen_name("platform_wallet_generate_random_identifier") -func platform_wallet_generate_random_identifier( - _ out_id: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_identifier_array_free") -func platform_wallet_identifier_array_free(_ array: UnsafeMutablePointer) - -@_silgen_name("platform_wallet_string_free") -func platform_wallet_string_free(_ string: UnsafeMutablePointer) - -@_silgen_name("platform_wallet_bytes_free") -func platform_wallet_bytes_free(_ bytes: UnsafeMutablePointer, _ len: Int) - -@_silgen_name("platform_wallet_ffi_error_free") -func platform_wallet_ffi_error_free(_ error: UnsafeMutablePointer) - -/// hash160 = RIPEMD160(SHA256(data)). 20-byte output. -/// -/// Mirrors `platform_wallet_hash160` from -/// `rs-platform-wallet-ffi/src/utils.rs`. Exposed so the keychain -/// metadata writer can stamp `publicKeyHash` without pulling a -/// RIPEMD-160 implementation into the Swift side (CommonCrypto and -/// CryptoKit don't expose one). Returns 0 on success, -1 on a null / -/// zero-length input. -@_silgen_name("platform_wallet_hash160") -func platform_wallet_hash160( - _ data: UnsafePointer?, - _ data_len: Int, - _ out_hash: UnsafeMutablePointer? -) -> Int32 - -// MARK: - DPNS name FFI - -/// Mirrors `DpnsSearchResultFFI` from -/// `rs-platform-wallet-ffi/src/dpns.rs`. Caller owns each entry's -/// `label` C-string; release the whole array (labels included) via -/// `dpns_search_results_free`. -struct DpnsSearchResultFFI { - var identity_id: ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - ) - var label: UnsafeMutablePointer? -} - -/// Mirrors `platform_wallet_register_dpns_name_with_signer` from Rust -/// (`packages/rs-platform-wallet-ffi/src/dpns.rs`). -/// -/// Signing is routed through the supplied `signer_handle` (typically -/// `KeychainSigner.handle`). Required for watch-only wallets where -/// the seed lives in iOS Keychain rather than the in-process -/// `WalletManager`. -/// -/// The wallet handle is still required so Rust can look up the -/// identity from the in-process `IdentityManager` and pick the -/// HIGH/CRITICAL authentication key DPP requires for document state -/// transitions — but no signing happens via the wallet's own seed. -/// -/// Caller retains ownership of the signer handle. -@_silgen_name("platform_wallet_register_dpns_name_with_signer") -func platform_wallet_register_dpns_name_with_signer( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ name: UnsafePointer?, - // Raw `*mut SignerHandle` produced by `dash_sdk_signer_create_with_ctx` - // (e.g. via `KeychainSigner.handle`). Used as `Signer`. - // Caller retains ownership; this function does NOT destroy it. - _ signer_handle: OpaquePointer?, - _ out_full_domain_name: UnsafeMutablePointer?>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_resolve_dpns_name") -func platform_wallet_resolve_dpns_name( - _ wallet_handle: Handle, - _ name: UnsafePointer?, - _ out_identity_id: UnsafeMutablePointer, - _ out_found: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_search_dpns_names") -func platform_wallet_search_dpns_names( - _ wallet_handle: Handle, - _ prefix: UnsafePointer?, - _ limit: UInt32, - _ out_results: UnsafeMutablePointer?>, - _ out_count: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("dpns_search_results_free") -func dpns_search_results_free( - _ results: UnsafeMutablePointer?, - _ count: Int -) - -/// Mirrors `DpnsNameArray` from `rs-platform-wallet-ffi/src/dpns.rs`. -/// Each `labels[i]` is an owned NUL-terminated UTF-8 C-string; -/// release the whole array (labels included) via -/// `dpns_name_array_free`. -struct DpnsNameArray { - var labels: UnsafeMutablePointer?>? - var count: Int -} - -@_silgen_name("platform_wallet_sync_dpns_names") -func platform_wallet_sync_dpns_names( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ out_added: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_get_dpns_names") -func managed_identity_get_dpns_names( - _ identity_handle: Handle, - _ out_array: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("dpns_name_array_free") -func dpns_name_array_free(_ array: UnsafeMutablePointer) - -@_silgen_name("platform_wallet_sync_contested_dpns_names") -func platform_wallet_sync_contested_dpns_names( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ out_count: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_get_contested_dpns_names") -func managed_identity_get_contested_dpns_names( - _ identity_handle: Handle, - _ out_array: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// MARK: - Wallet Memory Explorer FFI - -/// Mirrors `PlatformWalletMemorySummaryFFI` from -/// `rs-platform-wallet-ffi/src/memory_explorer.rs`. -/// -/// Caller-owned struct — Rust populates the slot the caller already -/// allocates, no `_free` is required. -struct PlatformWalletMemorySummaryFFI { - var identities_count: Int - var watched_count: Int - /// One past the wallet's highest already-registered identity - /// index — the resume position the gap-limit scanner uses next. - /// `0` when nothing has been registered yet. - var last_scanned_index: UInt32 - var tracked_asset_locks_count: Int - var token_balances_count: Int -} - -/// All-zero initial value — passed in before the FFI call so that -/// any early-exit path leaves a well-defined struct. -func platformWalletMemorySummaryFFIEmpty() -> PlatformWalletMemorySummaryFFI { - PlatformWalletMemorySummaryFFI( - identities_count: 0, - watched_count: 0, - last_scanned_index: 0, - tracked_asset_locks_count: 0, - token_balances_count: 0 - ) -} - -@_silgen_name("platform_wallet_list_in_memory_identity_ids") -func platform_wallet_list_in_memory_identity_ids( - _ wallet_handle: Handle, - _ out_array: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_list_in_memory_watched_identity_ids") -func platform_wallet_list_in_memory_watched_identity_ids( - _ wallet_handle: Handle, - _ out_array: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_get_in_memory_summary") -func platform_wallet_get_in_memory_summary( - _ wallet_handle: Handle, - _ out: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_get_identity_index") -func managed_identity_get_identity_index( - _ identity_handle: Handle, - _ out_has_index: UnsafeMutablePointer, - _ out_index: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("managed_identity_get_status") -func managed_identity_get_status( - _ identity_handle: Handle, - _ out_status: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// MARK: - Contest vote state FFI - -/// Mirrors `ContestContenderFFI` from -/// `rs-platform-wallet-ffi/src/dpns.rs`. Plain scalar struct; no -/// owned allocations (reclaimed wholesale when the parent's -/// contenders buffer is freed via `contest_vote_state_ffi_free`). -struct ContestContenderFFI { - var identity_id: FFIByteTuple32 - var vote_tally: UInt32 -} - -/// Mirrors `ContestVoteStateFFI`. Caller owns `label` + the -/// `contenders_ptr` array; release via -/// `contest_vote_state_ffi_free`. Safe to free on a zeroed default. -struct ContestVoteStateFFI { - var label: UnsafeMutablePointer? - var end_time_ms: UInt64 - var contenders_ptr: UnsafeMutablePointer? - var contenders_count: Int - var abstain_votes: UInt32 - var lock_votes: UInt32 - /// 0 = None, 1 = WonByIdentity, 2 = Locked. - /// `winner_identity_id` only valid when `winner_kind == 1`. - var winner_kind: UInt8 - var winner_identity_id: FFIByteTuple32 -} - -/// All-zero initial value — the "not found" path leaves this -/// shape, and `contest_vote_state_ffi_free` treats it as a no-op. -func contestVoteStateFFIEmpty() -> ContestVoteStateFFI { - ContestVoteStateFFI( - label: nil, - end_time_ms: 0, - contenders_ptr: nil, - contenders_count: 0, - abstain_votes: 0, - lock_votes: 0, - winner_kind: 0, - winner_identity_id: ( - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ) - ) -} - -@_silgen_name("platform_wallet_fetch_contest_vote_state") -func platform_wallet_fetch_contest_vote_state( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ label: UnsafePointer?, - _ out_state: UnsafeMutablePointer, - _ out_found: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("contest_vote_state_ffi_free") -func contest_vote_state_ffi_free(_ state: UnsafeMutablePointer) - -// MARK: - DashPay contact requests + payments FFI - -/// Mirrors `ContactRequestHandleArray` from -/// `rs-platform-wallet-ffi/src/dashpay.rs`. Caller owns both the -/// array and every handle inside it; release via -/// `platform_wallet_contact_request_handle_array_free` (array) and -/// `contact_request_destroy` (each handle). -struct ContactRequestHandleArray { - var handles: UnsafeMutablePointer? - var count: Int -} - -@_silgen_name("platform_wallet_contact_request_handle_array_free") -func platform_wallet_contact_request_handle_array_free( - _ array: UnsafeMutablePointer -) - -@_silgen_name("platform_wallet_get_managed_identity") -func platform_wallet_get_managed_identity( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ out_managed_identity_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_sync_contact_requests") -func platform_wallet_sync_contact_requests( - _ wallet_handle: Handle, - _ out_array: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_reject_contact_request") -func platform_wallet_reject_contact_request( - _ wallet_handle: Handle, - _ our_identity_id: UnsafePointer, - _ contact_identity_id: UnsafePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_fetch_sent_contact_requests") -func platform_wallet_fetch_sent_contact_requests( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ out_array: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_send_dashpay_payment") -func platform_wallet_send_dashpay_payment( - _ wallet_handle: Handle, - _ from_identity_id: UnsafePointer, - _ to_contact_identity_id: UnsafePointer, - _ amount_duffs: UInt64, - _ memo: UnsafePointer?, - _ out_txid: UnsafeMutablePointer<( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - )>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -/// Mirrors `platform_wallet_send_contact_request_with_signer` from -/// Rust. The document state-transition signature is routed through -/// `signer_handle` (typically `KeychainSigner.handle`). -@_silgen_name("platform_wallet_send_contact_request_with_signer") -func platform_wallet_send_contact_request_with_signer( - _ wallet_handle: Handle, - _ sender_identity_id: UnsafePointer, - _ recipient_identity_id: UnsafePointer, - _ account_label: UnsafePointer?, - _ auto_accept_proof: UnsafePointer?, - _ auto_accept_proof_len: Int, - _ signer_handle: OpaquePointer?, - _ out_request_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -/// Mirrors `platform_wallet_accept_contact_request_with_signer` from -/// Rust. -@_silgen_name("platform_wallet_accept_contact_request_with_signer") -func platform_wallet_accept_contact_request_with_signer( - _ wallet_handle: Handle, - _ request_handle: Handle, - _ signer_handle: OpaquePointer?, - _ out_established_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// MARK: - Identity transfer / withdraw / update — external-signer FFI - -/// Mirrors `PlatformAddressCreditOutputFFI` from -/// `rs-platform-wallet-ffi/src/identity_transfer.rs`. Stripped-down -/// version of `AddressBalanceEntryFFI` — only carries -/// `(address_type, hash, credits)` because the SDK fetches the -/// platform-address nonce at submit time. -@frozen -public struct PlatformAddressCreditOutputFFI { - public var address_type: UInt8 - public var hash: ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - ) - public var credits: UInt64 -} - -/// Mirrors `platform_wallet_transfer_credits_with_signer` from Rust -/// (`packages/rs-platform-wallet-ffi/src/identity_transfer.rs`). -/// -/// Identity → identity credit transfer routed through the supplied -/// `signer_handle` (typically `KeychainSigner.handle`). -@_silgen_name("platform_wallet_transfer_credits_with_signer") -func platform_wallet_transfer_credits_with_signer( - _ wallet_handle: Handle, - _ from_identity_id: UnsafePointer, - _ to_identity_id: UnsafePointer, - _ amount: UInt64, - _ signer_handle: OpaquePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -/// Mirrors `platform_wallet_transfer_credits_to_addresses_with_signer` -/// from Rust. Identity → 1+ platform addresses transfer. -/// -/// `out_new_balance` (when non-null) receives the sender's remaining -/// balance after the transfer. -@_silgen_name("platform_wallet_transfer_credits_to_addresses_with_signer") -func platform_wallet_transfer_credits_to_addresses_with_signer( - _ wallet_handle: Handle, - _ from_identity_id: UnsafePointer, - _ outputs: UnsafePointer?, - _ outputs_count: Int, - _ signer_handle: OpaquePointer?, - _ out_new_balance: UnsafeMutablePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -/// Mirrors `platform_wallet_withdraw_credits_with_signer` from Rust -/// (`packages/rs-platform-wallet-ffi/src/identity_withdrawal.rs`). -/// -/// `to_address` is a NUL-terminated UTF-8 C-string carrying a -/// network-aware Dash P2PKH address (e.g. `"yNPbcFf..."` for -/// testnet). -@_silgen_name("platform_wallet_withdraw_credits_with_signer") -func platform_wallet_withdraw_credits_with_signer( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ amount: UInt64, - _ to_address: UnsafePointer?, - _ signer_handle: OpaquePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -/// Mirrors `platform_wallet_update_identity_with_signer` from Rust -/// (`packages/rs-platform-wallet-ffi/src/identity_update.rs`). -/// -/// Add and/or disable identity public keys; signs the -/// `IdentityUpdateTransition` with the identity's MASTER auth key -/// via the supplied `signer_handle`. -/// -/// The new keys are passed in as flat `IdentityPubkeyFFI` rows -/// (re-uses the registration-with-signer key-row shape). Caller is -/// responsible for pre-persisting each new key's private material to -/// whatever store the signer reads from (iOS Keychain in the typical -/// case) BEFORE calling this — the signer here only signs the -/// update transition itself with an existing MASTER key. -/// -/// Pass `(nil, 0)` for either array to skip the corresponding -/// operation (e.g. disable-only or add-only updates). -@_silgen_name("platform_wallet_update_identity_with_signer") -func platform_wallet_update_identity_with_signer( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ add_public_keys: UnsafePointer?, - _ add_public_keys_count: Int, - _ disable_public_key_ids: UnsafePointer?, - _ disable_public_key_ids_count: Int, - _ signer_handle: OpaquePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -/// Mirrors `platform_wallet_create_data_contract_with_signer` from -/// Rust (`packages/rs-platform-wallet-ffi/src/data_contract.rs`). -/// -/// Replaces the rs-sdk-ffi `dash_sdk_data_contract_create` + -/// `dash_sdk_data_contract_put_to_platform_and_wait` pair. The -/// platform-wallet runtime (`runtime.rs`) configures an 8 MB -/// worker stack — proof verification on the broadcast response -/// crashes through the rs-sdk-ffi runtime's mobile-tuned default -/// stack. Architecturally this also lines up with the -/// swift-sdk/CLAUDE.md "high-level operations go through -/// platform-wallet" rule: contract creation spans an identity, a -/// signer, and persistent state. -/// -/// Every JSON pointer beyond `documents_schema_json` is optional — -/// pass NULL to skip. `out_contract_id` receives the 32-byte -/// deterministic contract id (`H = hash(owner_id || nonce)`) on -/// success; the Swift caller can re-fetch the contract with that -/// id once it lands. -@_silgen_name("platform_wallet_create_data_contract_with_signer") -func platform_wallet_create_data_contract_with_signer( - _ wallet_handle: Handle, - _ owner_identity_id: UnsafePointer, - _ documents_schema_json: UnsafePointer, - _ tokens_schema_json: UnsafePointer?, - _ groups_schema_json: UnsafePointer?, - _ keywords_json: UnsafePointer?, - _ description: UnsafePointer?, - _ config_json: UnsafePointer?, - _ signer_handle: OpaquePointer?, - _ out_contract_id: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -/// Mirrors `platform_wallet_register_identity_with_funding_signer` -/// from Rust -/// (`packages/rs-platform-wallet-ffi/src/identity_registration_funded_with_signer.rs`). -/// -/// Asset-lock-funded identity registration driven by an external -/// signer. The asset lock proof is built Rust-side from -/// `amount_duffs` (wallet must have spendable Core UTXOs); the -/// IdentityCreate state transition is signed via `signer_handle`. -/// -/// Caller pre-derives the new identity's authentication pubkeys via -/// `dash_sdk_derive_identity_keys_from_mnemonic` (works for -/// watch-only wallets, unlike the wallet-handle variant) and ships -/// them in via `identity_pubkeys`. Caller is also responsible for -/// pre-persisting each key's matching private material to the -/// signer's store (iOS Keychain in the typical case) BEFORE calling -/// this so the IdentityCreate signature can complete. -@_silgen_name("platform_wallet_register_identity_with_funding_signer") -func platform_wallet_register_identity_with_funding_signer( - _ wallet_handle: Handle, - _ amount_duffs: UInt64, - _ identity_index: UInt32, - _ identity_pubkeys: UnsafePointer?, - _ identity_pubkeys_count: Int, - _ signer_handle: OpaquePointer?, - _ out_identity_id: UnsafeMutablePointer<( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - )>, - _ out_identity_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// MARK: - Identity persistence FFI +// MARK: - Fixed-size byte-tuple aliases +// +// Swift imports `uint8_t x[N]` from C as a flat tuple of `N` `UInt8` +// values. The two sizes Platform actually traffics in are 32 bytes +// (identity ids, wallet ids, etc.) and 20 bytes +// (RIPEMD160(SHA256) public-key hashes). Naming them once at module +// scope keeps `withUnsafeBytes(of:)` / `assumingMemoryBound(to:)` +// callsites and ABI-typed function pointers from spelling out a 32- +// or 20-tuple inline every time. -/// 32-byte C tuple — mirrors a single `[u8; 32]` on the Rust side. -/// Swift imports fixed-size byte arrays this way; every persister- -/// callback struct that carries an `identity_id` / `wallet_id` uses -/// this shape. typealias FFIByteTuple32 = ( UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, @@ -1039,367 +18,21 @@ typealias FFIByteTuple32 = ( UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 ) -/// Mirrors `IdentityEntryFFI` from -/// `rs-platform-wallet-ffi/src/identity_persistence.rs`. See that -/// file for the field-by-field semantics. No heap allocations cross -/// the boundary on this struct anymore — every field is a scalar or -/// inline byte tuple. -/// -/// `identity_index_is_some` mirrors the new `Option` shape on -/// `ManagedIdentity.identity_index`: false means the source identity -/// is out-of-wallet (observed) and the `identity_index` field should -/// be ignored. -struct IdentityEntryFFI { - var identity_id: FFIByteTuple32 - var balance: UInt64 - var revision: UInt64 - var identity_index_is_some: Bool - var identity_index: UInt32 - var status: UInt8 - var wallet_id_is_some: Bool - var wallet_id: FFIByteTuple32 -} - -/// 20-byte C tuple — mirrors a single `[u8; 20]` on the Rust side. -/// Used for RIPEMD160(SHA256) public-key hashes on identity keys. typealias FFIByteTuple20 = ( UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 ) -/// Mirrors `IdentityKeyEntryFFI` from -/// `rs-platform-wallet-ffi/src/identity_persistence.rs`. -/// -/// No private-key bytes cross this boundary — when -/// `wallet_id_is_some` + `derivation_indices_is_some` are both -/// true, the client should re-derive the 32-byte ECDSA scalar from -/// the named wallet's mnemonic at the DIP-9 identity authentication -/// path `m/9'/coin'/5'/0'/ECDSA'/identity_index'/key_index'` and -/// persist it to the keychain on its own side. Any of those flags -/// false = watch-only. -/// -/// `public_key_hash` is the precomputed 20-byte -/// RIPEMD160(SHA256) of the public-key bytes — convenience so -/// clients without a RIPEMD-160 implementation can still attach -/// the hash as metadata on the keychain item. -struct IdentityKeyEntryFFI { - var identity_id: FFIByteTuple32 - var key_id: UInt32 - var purpose: UInt8 - var security_level: UInt8 - var key_type: UInt8 - var read_only: Bool - var disabled_at_is_some: Bool - var disabled_at: UInt64 - var public_key_data_ptr: UnsafeMutablePointer? - var public_key_data_len: Int - var public_key_hash: FFIByteTuple20 - var wallet_id_is_some: Bool - var wallet_id: FFIByteTuple32 - var derivation_indices_is_some: Bool - var identity_index: UInt32 - var key_index: UInt32 -} - -/// Expected size of `IdentityKeyEntryFFI` as laid out by Rust's -/// `#[repr(C)]` on 64-bit targets. Mirrors the compile-time -/// assertion at the bottom of `rs-platform-wallet-ffi/src/ -/// identity_persistence.rs`. Tested at callback entry via -/// `assertIdentityKeyEntryLayout()`. -let EXPECTED_IDENTITY_KEY_ENTRY_FFI_SIZE: Int = 136 - -/// Verify the Swift `IdentityKeyEntryFFI` mirror lays out to the -/// same 136-byte shape that Rust's `#[repr(C)]` produces. Called -/// once per process from the persistence-callback hot path so a -/// drift between the two sides surfaces as a clean assertion -/// failure rather than an EXC_BAD_ACCESS in memmove. -func assertIdentityKeyEntryLayout() { - let actual = MemoryLayout.size - let actualStride = MemoryLayout.stride - precondition( - actual == EXPECTED_IDENTITY_KEY_ENTRY_FFI_SIZE - && actualStride == EXPECTED_IDENTITY_KEY_ENTRY_FFI_SIZE, - "IdentityKeyEntryFFI layout mismatch: size=\(actual) stride=\(actualStride), " - + "expected \(EXPECTED_IDENTITY_KEY_ENTRY_FFI_SIZE). Rust-side " - + "#[repr(C)] and Swift-side struct have diverged; fix one side." - ) -} - -/// Mirrors `IdentityKeyRemovalFFI` from -/// `rs-platform-wallet-ffi/src/identity_persistence.rs` — the -/// `(identity_id, key_id)` composite used by the keys-changeset -/// `removed` surface. -struct IdentityKeyRemovalFFI { - var identity_id: FFIByteTuple32 - var key_id: UInt32 -} - -// MARK: - Identity discovery FFI - -/// Mirrors `DiscoveredIdentityIdsFFI` from -/// `rs-platform-wallet-ffi/src/identity_discovery.rs`. `ids` points -/// at a contiguous `[[u8; 32]; count]` buffer; reclaim the whole -/// struct by handing it back to -/// `platform_wallet_discover_identities_free`. Safe to free on a -/// zero / null struct (no-op). -struct DiscoveredIdentityIdsFFI { - var ids: UnsafeMutablePointer? - var count: Int -} - -/// Initial all-zero value. Useful as a placeholder before calling -/// the FFI and for the unused-error branches. -func discoveredIdentityIdsFFIEmpty() -> DiscoveredIdentityIdsFFI { - DiscoveredIdentityIdsFFI(ids: nil, count: 0) -} - -/// Gap-limit scan of the wallet's DIP-9 identity auth-key path. -/// `start_index_or_neg1 >= 0` starts at that index; negative means -/// "resume from the wallet's cached last_scanned_index". Pass -/// `gap_limit = 0` to use the Rust default (`IDENTITY_GAP_LIMIT`, -/// currently 5). On success, `out_found` receives a heap-allocated -/// id array the caller frees via -/// `platform_wallet_discover_identities_free`. -@_silgen_name("platform_wallet_discover_identities") -func platform_wallet_discover_identities( - _ wallet_handle: Handle, - _ start_index_or_neg1: Int64, - _ gap_limit: UInt32, - _ out_found: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_discover_identities_free") -func platform_wallet_discover_identities_free( - _ found: UnsafeMutablePointer -) - -// MARK: - Identity-registration-key preview FFI - -/// Mirrors `IdentityKeyPreviewFFI` from -/// `rs-platform-wallet-ffi/src/identity_key_preview.rs`. -/// -/// All heap allocations (`derivation_path`, `public_key`, -/// `private_key_wif`) are owned by Rust; reclaim each row by -/// handing the enclosing `IdentityKeyPreviewsFFI` back to -/// `platform_wallet_preview_identity_registration_keys_free`. Never -/// free these fields individually. -struct IdentityKeyPreviewFFI { - var identity_index: UInt32 - var derivation_path: UnsafeMutablePointer? - var public_key: UnsafeMutablePointer? - var public_key_len: Int - var private_key_wif: UnsafeMutablePointer? - /// Inline 32-byte ECDSA private-key scalar. Mirror of the - /// `[u8; 32]` field on the Rust struct. Treat as sensitive — the - /// Swift caller is expected to copy it straight into the iOS - /// Keychain (via `KeychainManager.storeIdentityPrivateKey`) and - /// drop the local reference. - var private_key_bytes: ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - ) -} - -/// Mirrors `IdentityKeyPreviewsFFI`. `items` points at a contiguous -/// `[IdentityKeyPreviewFFI; count]` buffer. Release the whole -/// struct (rows + their owned strings + pubkey buffers) via -/// `platform_wallet_preview_identity_registration_keys_free`. Safe -/// to free on a zero / null struct (no-op). -struct IdentityKeyPreviewsFFI { - var items: UnsafeMutablePointer? - var count: Int -} - -/// Initial all-zero value — lets us pass a well-defined struct into -/// the FFI call and into `_free` on the cleanup path regardless of -/// whether the call succeeded. -func identityKeyPreviewsFFIEmpty() -> IdentityKeyPreviewsFFI { - IdentityKeyPreviewsFFI(items: nil, count: 0) -} - -/// All-zero / null `IdentityKeyPreviewFFI` value for the single-row -/// callers (`dash_sdk_derive_identity_key_at_slot`). The -/// 32-byte tuple is laid out as Swift's nested-tuple representation -/// of `[u8; 32]`; spelled out as 32 zero bytes here so a freshly- -/// declared `out_row` is safe to hand to the FFI even on the -/// failure paths where `_free` will run. -func identityKeyPreviewFFIEmpty() -> IdentityKeyPreviewFFI { - IdentityKeyPreviewFFI( - identity_index: 0, - derivation_path: nil, - public_key: nil, - public_key_len: 0, - private_key_wif: nil, - private_key_bytes: ( - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 - ) - ) -} - -/// Derive the first N MASTER identity-authentication keypairs this -/// wallet would probe during a discovery scan. `count_or_neg1< 0` -/// picks the Rust-side default (`IDENTITY_GAP_LIMIT`, currently 5). -/// On success, `out_previews` receives a heap-allocated row array -/// the caller frees via -/// `platform_wallet_preview_identity_registration_keys_free`. -@_silgen_name("platform_wallet_preview_identity_registration_keys") -func platform_wallet_preview_identity_registration_keys( - _ wallet_handle: Handle, - _ start_index: UInt32, - _ count_or_neg1: Int32, - _ out_previews: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_preview_identity_registration_keys_free") -func platform_wallet_preview_identity_registration_keys_free( - _ previews: UnsafeMutablePointer -) - -// MARK: - Pre-registration key derivation - -/// Mirrors `IdentityRegistrationKeyDerivationsFFI` from -/// `rs-platform-wallet-ffi/src/identity_registration_with_signer.rs`. -/// Same row layout as `IdentityKeyPreviewsFFI` (re-uses -/// `IdentityKeyPreviewFFI`), but each row is one -/// `(identity_index, key_id)` pair fixed to a single identity_index. -struct IdentityRegistrationKeyDerivationsFFI { - var items: UnsafeMutablePointer? - var count: Int -} - -func identityRegistrationKeyDerivationsFFIEmpty() -> IdentityRegistrationKeyDerivationsFFI { - IdentityRegistrationKeyDerivationsFFI(items: nil, count: 0) -} - -/// Derive every authentication-key pair the upcoming -/// `platform_wallet_register_identity_with_signer` call will need -/// for `identity_index`, returning one row per `key_id` in -/// `0..key_count`. -@_silgen_name("platform_wallet_derive_identity_keys_for_index") -func platform_wallet_derive_identity_keys_for_index( - _ wallet_handle: Handle, - _ identity_index: UInt32, - _ key_count: UInt32, - _ out_rows: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_derive_identity_keys_for_index_free") -func platform_wallet_derive_identity_keys_for_index_free( - _ rows: UnsafeMutablePointer -) - -// MARK: - Mnemonic-driven pre-registration key derivation -// -// Companion entry point to -// `platform_wallet_derive_identity_keys_for_index` that takes the -// BIP-39 mnemonic directly instead of routing through a wallet -// handle. The wallet-handle variant fails for wallets restored from -// SwiftData persistence (the seed lives in iOS Keychain, not in the -// in-process `WalletManager`); this one works for every wallet shape -// because it pulls the seed from the caller per call. -// -// Same row layout as the wallet-handle variant -// (`IdentityRegistrationKeyDerivationsFFI` over `IdentityKeyPreviewFFI`). -// Paired free function frees the matching shape — distinct symbol -// name purely so call sites pair allocator with deallocator 1:1. -@_silgen_name("dash_sdk_derive_identity_keys_from_mnemonic") -func dash_sdk_derive_identity_keys_from_mnemonic( - _ mnemonic_cstr: UnsafePointer, - _ passphrase_cstr: UnsafePointer?, - _ network: DashSDKNetwork, - _ identity_index: UInt32, - _ key_count: UInt32, - _ out_rows: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("dash_sdk_derive_identity_keys_from_mnemonic_free") -func dash_sdk_derive_identity_keys_from_mnemonic_free( - _ rows: UnsafeMutablePointer -) - -// MARK: - dash_sdk_derive_identity_key_at_slot -// -// Single-slot variant of `dash_sdk_derive_identity_keys_from_mnemonic` -// for the "add a new key to an existing identity" flow. Returns ONE -// row at an arbitrary `(identity_index, key_index)` instead of a -// `0..key_count` range — the caller picks the slot (typically -// `max(existing_key_ids) + 1`). -// -// Currently ECDSA-only. The caller maps the resulting 33-byte -// compressed pubkey into either `ECDSA_SECP256K1` (raw bytes) or -// `ECDSA_HASH160` (ripemd160(sha256(pubkey))) when constructing the -// `IdentityPublicKey` for the eventual `addPublicKeys` state -// transition. -@_silgen_name("dash_sdk_derive_identity_key_at_slot") -func dash_sdk_derive_identity_key_at_slot( - _ mnemonic_cstr: UnsafePointer, - _ passphrase_cstr: UnsafePointer?, - _ network: DashSDKNetwork, - _ identity_index: UInt32, - _ key_index: UInt32, - _ out_row: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("dash_sdk_derive_identity_key_at_slot_free") -func dash_sdk_derive_identity_key_at_slot_free( - _ row: UnsafeMutablePointer -) - -// Resolver-based sibling. Replaces the raw mnemonic c-string with -// a `MnemonicResolverHandle` keyed by `wallet_id_bytes` so the -// BIP-39 mnemonic never lives in a Swift `String` outside the -// resolver trampoline's stack frame. Closes the -// `swift-sdk/CLAUDE.md` "no mnemonic round-tripping" rule the -// raw-cstring entry point violates. Use this from new Swift call -// sites; the raw-cstring variant stays available for tests / any -// non-iOS caller that already has the mnemonic in hand. -@_silgen_name("dash_sdk_derive_identity_key_at_slot_with_resolver") -func dash_sdk_derive_identity_key_at_slot_with_resolver( - _ network: DashSDKNetwork, - _ wallet_id_bytes: UnsafePointer, - _ mnemonic_resolver_handle: UnsafeMutablePointer?, - _ identity_index: UInt32, - _ key_index: UInt32, - _ out_row: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// MARK: - Derive-and-persist callback handles -// -// Used by `dash_sdk_derive_and_persist_identity_keys` (below). The -// Swift side hands the Rust derivation loop two opaque callback -// handles — one for fetching the BIP-39 mnemonic out of Keychain, -// one for writing each derived key back into Keychain — and the -// Rust loop owns the orchestration. Closes the -// "no mnemonic round-tripping" rule that ManagedPlatformWallet's -// `prePersistIdentityKeysForRegistration` previously violated. - -/// Opaque Rust-side handle to a Swift-owned mnemonic resolver. -/// Allocated via `dash_sdk_mnemonic_resolver_create`, freed via -/// `dash_sdk_mnemonic_resolver_destroy`. The Rust struct itself -/// is private; Swift only ever holds the pointer. -public struct MnemonicResolverHandle {} - -/// Opaque Rust-side handle to a Swift-owned identity-key persister. -public struct IdentityKeyPersisterHandle {} +// MARK: - Mnemonic-resolver callback result codes /// Mirrors the Rust `mnemonic_resolver_result` constants in -/// `derive_and_persist_callbacks.rs`. Used as the return value of -/// the resolver callback so the Rust derivation loop can -/// distinguish "buffer too small" (a programmer error) from -/// "wallet has no mnemonic stored" (a recoverable user-visible -/// error). +/// `derive_and_persist_callbacks.rs`. The C header surfaces them as +/// bare `#define`s with awkwardly generic names (`SUCCESS`, +/// `NOT_FOUND`, ...); we re-expose them as a typed enum so callers +/// don't reach for those globals by accident and the resolver +/// callback's return value reads as a domain-specific code instead +/// of a magic `Int32`. enum MnemonicResolverResult: Int32 { case success = 0 case notFound = 1 @@ -1407,184 +40,7 @@ enum MnemonicResolverResult: Int32 { case other = 3 } -/// Buffer capacity (bytes, excluding trailing NUL) the resolver -/// callback is given to write the mnemonic into. Mirrors the Rust -/// `MNEMONIC_RESOLVER_BUFFER_CAPACITY` constant. -let MNEMONIC_RESOLVER_BUFFER_CAPACITY: Int = 1024 - -/// Function pointer type for the mnemonic-resolve callback. -/// Returns one of [`MnemonicResolverResult`]'s raw values. -typealias MnemonicResolveCallback = @convention(c) ( - _ ctx: UnsafeRawPointer?, - _ wallet_id_bytes: UnsafePointer?, - _ out_mnemonic_utf8: UnsafeMutablePointer?, - _ out_capacity: Int, - _ out_len: UnsafeMutablePointer? -) -> Int32 - -/// Mirrors the Rust `PersistKeyArgs` `#[repr(C)]` struct. Pointer- -/// based per-call payload for the identity-key persister callback. -/// Field order, sizes, and trailing-byte alignment match the Rust -/// definition. -struct PersistKeyArgs { - var wallet_id_bytes: UnsafePointer? - var identity_index: UInt32 - var key_id: UInt32 - var key_index: UInt32 - var derivation_path_cstr: UnsafePointer? - var public_key_bytes: UnsafePointer? - var public_key_len: Int - var public_key_hash_bytes: UnsafePointer? - var private_key_bytes: UnsafePointer? - var key_type: UInt8 - var purpose: UInt8 - var security_level: UInt8 -} - -/// Expected stride of `PersistKeyArgs` as laid out by Rust's -/// `#[repr(C)]` on 64-bit targets. Mirrors the compile-time -/// assertion in `rs-platform-wallet-ffi/src/ -/// derive_and_persist_callbacks.rs`. Tested at trampoline entry -/// via `assertPersistKeyArgsLayout()`. -/// -/// We compare `MemoryLayout.stride` (not `.size`) here. Rust's -/// `size_of::()` includes trailing padding so an array of `T` -/// has the right element-to-element distance — that's what the -/// Rust compile-time assertion pins to 72. Swift's `size` excludes -/// trailing padding (would return 67 for this struct because the -/// last field is a `UInt8` at offset 66 with 5 bytes of trailing -/// pad to 8-align the next array element); Swift's `stride` is -/// the equivalent of Rust's `size_of`. Earlier revisions checked -/// `size == 72` AND `stride == 72`, which never held — Swift's -/// 67-byte `size` for this struct made the assertion abort at the -/// first persister construction. -let EXPECTED_PERSIST_KEY_ARGS_STRIDE: Int = 72 - -/// Verify the Swift `PersistKeyArgs` mirror lays out to the same -/// 72-byte shape Rust's `#[repr(C)]` produces. Called once per -/// process from the persister-callback hot path so a drift -/// between the two sides surfaces as a clean assertion failure -/// rather than an EXC_BAD_ACCESS in `assumingMemoryBound`. -func assertPersistKeyArgsLayout() { - let actualStride = MemoryLayout.stride - precondition( - actualStride == EXPECTED_PERSIST_KEY_ARGS_STRIDE, - "PersistKeyArgs stride mismatch: \(actualStride), expected " - + "\(EXPECTED_PERSIST_KEY_ARGS_STRIDE). Rust-side #[repr(C)] " - + "and Swift-side struct have diverged; fix one side." - ) - // Belt-and-braces field-offset checks. If a field is - // reordered or resized on either side the offsets will drift - // even when the total stride happens to stay the same, and - // `assumingMemoryBound` would silently read the wrong field. - precondition( - MemoryLayout.offset(of: \.wallet_id_bytes) == 0 - && MemoryLayout.offset(of: \.identity_index) == 8 - && MemoryLayout.offset(of: \.key_id) == 12 - && MemoryLayout.offset(of: \.key_index) == 16 - && MemoryLayout.offset(of: \.derivation_path_cstr) == 24 - && MemoryLayout.offset(of: \.public_key_bytes) == 32 - && MemoryLayout.offset(of: \.public_key_len) == 40 - && MemoryLayout.offset(of: \.public_key_hash_bytes) == 48 - && MemoryLayout.offset(of: \.private_key_bytes) == 56 - && MemoryLayout.offset(of: \.key_type) == 64 - && MemoryLayout.offset(of: \.purpose) == 65 - && MemoryLayout.offset(of: \.security_level) == 66, - "PersistKeyArgs field offsets diverged from Rust #[repr(C)] layout" - ) -} - -/// Function pointer type for the per-key persist callback. -/// Returns [`PERSIST_KEY_SUCCESS`] on a successful Keychain write, -/// [`PERSIST_KEY_FAILURE`] to abort the rest of the Rust derivation -/// loop with an `ErrorWalletOperation`. -/// -/// The args parameter is `UnsafeRawPointer?` rather than the more -/// natural `UnsafePointer?` because Swift's -/// `@convention(c)` typealiases can only carry types representable -/// in Objective-C, and a pointer to a non-`@objc` Swift struct -/// fails that check. The Rust side ships a `*const PersistKeyArgs` -/// regardless; the Swift trampoline unwraps via -/// `assumingMemoryBound(to: PersistKeyArgs.self)`. Same ABI shape -/// as the Rust `extern "C" fn(_, *const PersistKeyArgs) -> u8` -/// declaration. -typealias PersistKeyCallback = @convention(c) ( - _ ctx: UnsafeRawPointer?, - _ args: UnsafeRawPointer? -) -> UInt8 - -/// Persister-callback success/failure tags. Mirror the -/// `PERSIST_KEY_SUCCESS` / `PERSIST_KEY_FAILURE` constants in -/// `derive_and_persist_callbacks.rs`. Trampoline implementations -/// return one of these to keep the wire shape consistent. -let PERSIST_KEY_SUCCESS: UInt8 = 1 -let PERSIST_KEY_FAILURE: UInt8 = 0 - -/// Generic Rust-callable destructor for any Swift-owned `ctx` -/// pointer (typically `Unmanaged.passRetained(self).toOpaque()`). -typealias DeriveAndPersistCtxDestroy = @convention(c) ( - _ ctx: UnsafeMutableRawPointer? -) -> Void - -@_silgen_name("dash_sdk_mnemonic_resolver_create") -func dash_sdk_mnemonic_resolver_create( - _ ctx: UnsafeMutableRawPointer?, - _ resolve_callback: MnemonicResolveCallback, - _ destroy_callback: DeriveAndPersistCtxDestroy -) -> UnsafeMutablePointer? - -@_silgen_name("dash_sdk_mnemonic_resolver_destroy") -func dash_sdk_mnemonic_resolver_destroy( - _ handle: UnsafeMutablePointer? -) - -@_silgen_name("dash_sdk_identity_key_persister_create") -func dash_sdk_identity_key_persister_create( - _ ctx: UnsafeMutableRawPointer?, - _ persist_callback: PersistKeyCallback, - _ destroy_callback: DeriveAndPersistCtxDestroy -) -> UnsafeMutablePointer? - -@_silgen_name("dash_sdk_identity_key_persister_destroy") -func dash_sdk_identity_key_persister_destroy( - _ handle: UnsafeMutablePointer? -) - -/// Single-FFI identity-key derivation + persistence pipeline. -/// -/// Companion to the lower-level -/// `dash_sdk_derive_identity_keys_from_mnemonic` (which leaves -/// orchestration to the caller). This entry point owns the -/// per-key loop on the Rust side and calls back into Swift only -/// for the iOS-only Keychain primitives. -/// -/// On success `out_pubkeys` is populated with the derived -/// pubkeys (and their paths) for the caller to build -/// `IdentityPubkey` rows for the subsequent registration call; -/// the 32-byte ECDSA private scalars are NOT included — they -/// were already handed to the persister callback per iteration. -/// Release `out_pubkeys` with -/// `dash_sdk_derive_identity_keys_from_mnemonic_free` (same -/// memory layout, intentionally shares the free function). -@_silgen_name("dash_sdk_derive_and_persist_identity_keys") -func dash_sdk_derive_and_persist_identity_keys( - _ network: DashSDKNetwork, - _ wallet_id_bytes: UnsafePointer?, - _ identity_index: UInt32, - _ key_count: UInt32, - _ mnemonic_resolver_handle: UnsafeMutablePointer?, - _ persister_handle: UnsafeMutablePointer?, - _ out_pubkeys: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// MARK: - Resolver-driven one-shot sign -// -// Sibling of the lower-level `dash_sdk_sign_with_mnemonic_and_path` -// in rs-sdk-ffi. Routes the mnemonic fetch through a Swift-owned -// `MnemonicResolverHandle` instead of taking it as a raw C-string, -// closing the same swift-sdk/CLAUDE.md "no mnemonic round-tripping" -// rule for the platform-address signing path. +// MARK: - Resolver-driven sign error codes /// Mirrors the Rust `SIGN_WITH_RESOLVER_*` byte tags. Returned via /// the `out_error` byte parameter on a non-zero rc. @@ -1602,17 +58,18 @@ enum SignWithMnemonicResolverError: UInt8 { case resolverFailed = 10 } -@_silgen_name("dash_sdk_sign_with_mnemonic_resolver_and_path") -func dash_sdk_sign_with_mnemonic_resolver_and_path( - _ mnemonic_resolver_handle: UnsafeMutablePointer?, - _ wallet_id_bytes: UnsafePointer?, - _ derivation_path_cstr: UnsafePointer?, - _ data: UnsafePointer?, - _ data_len: Int, - _ key_type: UInt8, - _ network: DashSDKNetwork, - _ out_signature: UnsafeMutablePointer?, - _ out_signature_capacity: Int, - _ out_signature_len: UnsafeMutablePointer?, - _ out_error: UnsafeMutablePointer? -) -> Int32 +// MARK: - 32-byte tuple helpers + +/// Convert a 32-byte FFI tuple into `Data` for SwiftData persistence. +@inline(__always) +func hashData(_ hash: FFIByteTuple32) -> Data { + Swift.withUnsafeBytes(of: hash) { Data($0) } +} + +/// Hex-encode a 32-byte FFI tuple. +@inline(__always) +func hashHex(_ hash: FFIByteTuple32) -> String { + Swift.withUnsafeBytes(of: hash) { buf in + buf.map { String(format: "%02x", $0) }.joined() + } +} diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManager.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManager.swift index a62e0d7cb3f..5a9c471caf6 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManager.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManager.swift @@ -126,7 +126,7 @@ public class PlatformWalletManager: ObservableObject { &error ) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -181,7 +181,7 @@ public class PlatformWalletManager: ObservableObject { ) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -222,7 +222,7 @@ public class PlatformWalletManager: ObservableObject { handle, network.rawValue, seedPtr.baseAddress?.assumingMemoryBound(to: UInt8.self), - seed.count, + UInt(seed.count), accountOptions, &walletHandle, &walletId, @@ -230,7 +230,7 @@ public class PlatformWalletManager: ObservableObject { ) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } @@ -268,7 +268,7 @@ public class PlatformWalletManager: ObservableObject { var error = PlatformWalletFFIError() let loadResult = platform_wallet_manager_load_from_persistor(handle, &error) - guard loadResult == Success else { + guard loadResult == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: loadResult, error: error) } @@ -288,8 +288,11 @@ public class PlatformWalletManager: ObservableObject { var walletHandle: Handle = NULL_HANDLE var fetchError = PlatformWalletFFIError() let fetchResult = walletId.withUnsafeBytes { idPtr -> PlatformWalletFFIResult in - guard let base = idPtr.baseAddress?.assumingMemoryBound(to: UInt8.self) else { - return ErrorNullPointer + // C signature is `const uint8_t (*wallet_id)[32]`, which Swift + // imports as `UnsafePointer?`. Rebind the raw + // 32-byte buffer to that 32-tuple shape so the call type-checks. + guard let base = idPtr.baseAddress?.assumingMemoryBound(to: FFIByteTuple32.self) else { + return PLATFORM_WALLET_FFI_RESULT_ERROR_NULL_POINTER } return platform_wallet_manager_get_wallet( handle, @@ -298,7 +301,7 @@ public class PlatformWalletManager: ObservableObject { &fetchError ) } - if fetchResult == Success { + if fetchResult == PLATFORM_WALLET_FFI_RESULT_SUCCESS { let managedWallet = ManagedPlatformWallet(handle: walletHandle, walletId: walletId) restored.append(managedWallet) self.wallets[walletId] = managedWallet @@ -350,16 +353,16 @@ public class PlatformWalletManager: ObservableObject { var error = PlatformWalletFFIError() let result: PlatformWalletFFIResult = bytes.withUnsafeBytes { raw in guard let base = raw.baseAddress?.assumingMemoryBound(to: UInt8.self) else { - return ErrorNullPointer + return PLATFORM_WALLET_FFI_RESULT_ERROR_NULL_POINTER } return platform_wallet_account_xpub_to_string( base, - bytes.count, + UInt(bytes.count), &outPtr, &error ) } - guard result == Success, let cStr = outPtr else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS, let cStr = outPtr else { return nil } let str = String(cString: cStr) diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManagerAddressSync.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManagerAddressSync.swift index b249e0d90ed..ee8e46b53b3 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManagerAddressSync.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManagerAddressSync.swift @@ -16,8 +16,8 @@ public struct PlatformAddressWalletSyncResult: Sendable { var walletId = ffi.wallet_id self.walletId = withUnsafeBytes(of: &walletId) { Data($0) } self.success = ffi.success - self.foundCount = ffi.found_count - self.absentCount = ffi.absent_count + self.foundCount = Int(ffi.found_count) + self.absentCount = Int(ffi.absent_count) self.checkpointHeight = ffi.checkpoint_height self.newSyncHeight = ffi.new_sync_height self.newSyncTimestamp = ffi.new_sync_timestamp @@ -53,8 +53,8 @@ final class PlatformWalletEventHandler { private func platformAddressSyncCompletedCallback( context: UnsafeMutableRawPointer?, - resultsRaw: UnsafeRawPointer?, - count: Int, + resultsPtr: UnsafePointer?, + count: UInt, syncUnixSeconds: UInt64 ) { guard let context else { return } @@ -64,10 +64,9 @@ private func platformAddressSyncCompletedCallback( .takeUnretainedValue() var results: [PlatformAddressWalletSyncResult] = [] - if let resultsRaw, count > 0 { - let resultsPtr = resultsRaw.assumingMemoryBound(to: PlatformAddressSyncWalletResultFFI.self) - results.reserveCapacity(count) - for i in 0.. 0 { + results.reserveCapacity(Int(count)) + for i in 0..? - ) -> Int32)? = nil - /// Fires at the bottom of every Rust `store()` round, after every - /// per-kind callback. `Bool` argument is `true` iff every per-kind - /// callback returned 0; Swift saves on success, rolls back - /// otherwise. Must match the field order on the Rust struct — - /// keep this tuple in sync with - /// `rs-platform-wallet-ffi/src/persistence.rs::PersistenceCallbacks`. - var on_changeset_end_fn: (@convention(c) ( - UnsafeMutableRawPointer?, - UnsafePointer?, - Bool - ) -> Int32)? = nil - var on_store_fn: (@convention(c) (UnsafeMutableRawPointer?, UnsafePointer?) -> Int32)? = nil - var on_flush_fn: (@convention(c) (UnsafeMutableRawPointer?, UnsafePointer?) -> Int32)? = nil - var on_persist_address_balances_fn: (@convention(c) ( - UnsafeMutableRawPointer?, - UnsafePointer?, - UnsafeRawPointer?, - Int - ) -> Int32)? = nil - var on_persist_wallet_changeset_fn: (@convention(c) ( - UnsafeMutableRawPointer?, - UnsafePointer?, - UnsafeRawPointer? - ) -> Int32)? = nil - var on_persist_sync_state_fn: (@convention(c) ( - UnsafeMutableRawPointer?, - UnsafePointer?, - UInt64, - UInt64, - UInt64 - ) -> Int32)? = nil - var on_persist_account_fn: (@convention(c) ( - UnsafeMutableRawPointer?, - UnsafePointer?, - UnsafeRawPointer? - ) -> Int32)? = nil - var on_load_wallet_list_fn: (@convention(c) ( - UnsafeMutableRawPointer?, - UnsafeMutablePointer?, - UnsafeMutablePointer? - ) -> Int32)? = nil - var on_load_wallet_list_free_fn: (@convention(c) ( - UnsafeMutableRawPointer?, - UnsafeRawPointer?, - Int - ) -> Void)? = nil - var on_persist_wallet_metadata_fn: (@convention(c) ( - UnsafeMutableRawPointer?, - UnsafePointer?, - UInt8, - UInt32 - ) -> Int32)? = nil - var on_persist_account_addresses_fn: (@convention(c) ( - UnsafeMutableRawPointer?, - UnsafePointer?, - UnsafeRawPointer?, - UnsafeRawPointer?, - Int - ) -> Int32)? = nil - /// Mirrors `on_persist_identities_fn` on the Rust - /// `PersistenceCallbacks`. Carries scalar `IdentityEntryFFI` - /// upserts + a `[u8; 32]` tombstone array. See - /// `rs-platform-wallet-ffi/src/identity_persistence.rs` for the - /// payload shape. Primary-identity selection and the gap-limit - /// scan watermark are no longer carried — the former is a UI - /// concern, the latter is now derived from the manager's - /// highest-registered slot. - /// - /// Pointers are typed on the Rust side but flow through the Swift - /// struct as `UnsafeRawPointer?` because `@convention(c)` rejects - /// non-`@objc`-bridgeable typed pointers (Swift structs like - /// `IdentityEntryFFI` aren't bridged). The receiving callback - /// casts via `assumingMemoryBound(to:)`. - var on_persist_identities_fn: (@convention(c) ( - UnsafeMutableRawPointer?, // context - UnsafePointer?, // wallet_id - UnsafeRawPointer?, // upserts_ptr (cast to *IdentityEntryFFI) - Int, // upserts_count - UnsafeRawPointer?, // removed_ptr (cast to *[UInt8;32] tuple) - Int // removed_count - ) -> Int32)? = nil - /// Mirrors `on_persist_identity_keys_fn`. Per-key upserts + - /// `(identity_id, key_id)` removals, maps onto - /// `PersistentPublicKey` rows on Swift side. - var on_persist_identity_keys_fn: (@convention(c) ( - UnsafeMutableRawPointer?, // context - UnsafePointer?, // wallet_id - UnsafeRawPointer?, // upserts_ptr (cast to *IdentityKeyEntryFFI) - Int, // upserts_count - UnsafeRawPointer?, // removed_ptr (cast to *IdentityKeyRemovalFFI) - Int // removed_count - ) -> Int32)? = nil -} - -// MARK: - Core Address Entry -// -// Mirrors `rs-platform-wallet-ffi/src/core_address_types.rs`. Field -// order and types must match bit-for-bit — Rust sends an array of -// these via `on_persist_account_addresses_fn`. String pointers are -// Rust-owned and valid only for the duration of the callback. - -struct CoreAddressEntryFFI { - // 33-byte compressed pubkey (zero when `has_public_key == false`). - var public_key: ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - ) = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) - var has_public_key: Bool = false - var pool_type_tag: UInt8 = 0 - var address_index: UInt32 = 0 - var is_used: Bool = false - var balance: UInt64 = 0 - var address_base58: UnsafePointer? = nil - var derivation_path: UnsafePointer? = nil -} - -// MARK: - Watch-only Restore Types -// -// Mirrors `rs-platform-wallet-ffi/src/wallet_restore_types.rs`. Field -// order and types must match bit-for-bit — Rust reads the array -// elements as `#[repr(C)]` structs via `slice::from_raw_parts`. All -// pointer fields are Swift-owned during the load-callback window and -// released by `on_load_wallet_list_free_fn`. - -struct AccountSpecFFI { - var type_tag: UInt8 = 0 - var standard_tag: UInt8 = 0 - var index: UInt32 = 0 - var registration_index: UInt32 = 0 - var key_class: UInt32 = 0 - // Fixed 32-byte buffers. Swift imports a fixed-size C array as a - // tuple; `withUnsafeMutableBytes` / `withUnsafeBytes` to fill and - // read. - var user_identity_id: ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - ) = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) - var friend_identity_id: ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - ) = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) - var account_xpub_bytes: UnsafePointer? = nil - var account_xpub_bytes_len: Int = 0 -} - -/// Mirrors `IdentityKeyRestoreFFI` from -/// `rs-platform-wallet-ffi/src/wallet_restore_types.rs`. One entry per -/// public key carried on the load path so the reconstructed -/// `Identity.public_keys` map is populated immediately at cold-start -/// (instead of waiting for the next sync round to refresh it from -/// chain). Field order and types must match bit-for-bit — Rust reads -/// each row as a `#[repr(C)]` struct via `slice::from_raw_parts`. -/// -/// Discriminant conventions match the DPP `repr(u8)` enum layouts and -/// are shared with `IdentityPubkeyFFI` on the registration path: -/// - `key_type`: 0 = ECDSA_SECP256K1, etc. -/// - `purpose`: 0 = AUTHENTICATION, etc. -/// - `security_level`: 0 = MASTER, 1 = CRITICAL, 2 = HIGH, 3 = MEDIUM. -/// -/// `data` is Swift-owned for the duration of the load callback (carries -/// the compressed public-key bytes; 33 for ECDSA_SECP256K1). The -/// matching free callback releases the per-identity arrays plus every -/// `data` byte buffer. -struct IdentityKeyRestoreFFI { - var key_id: UInt32 = 0 - var key_type: UInt8 = 0 - var purpose: UInt8 = 0 - var security_level: UInt8 = 0 - var read_only: Bool = false - var data: UnsafePointer? = nil - var data_len: Int = 0 -} - -/// Mirrors `IdentityRestoreEntryFFI` from -/// `rs-platform-wallet-ffi/src/wallet_restore_types.rs`. Field order -/// and types must match bit-for-bit — Rust reads each entry as a -/// `#[repr(C)]` struct via `slice::from_raw_parts`. -/// -/// Bucket placement is implicit: every identity carried on a wallet -/// entry lands in `wallet_identities[wallet_id][identity_index]`. The -/// previous `is_watched` discriminant is gone — out-of-wallet -/// identities don't ride on this path (no associated wallet). -/// -/// All pointer fields (`dpns_names`, `contested_dpns_names`, `keys`) -/// are Swift-owned during the load-callback window and released by -/// `on_load_wallet_list_free_fn`. `dpns_names` / -/// `contested_dpns_names` are flat `*const *const c_char` arrays of -/// NUL-terminated UTF-8 strings; `keys` is a contiguous -/// `[IdentityKeyRestoreFFI]` carrying the per-identity public keys. -struct IdentityRestoreEntryFFI { - var identity_id: ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - ) = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) - var balance: UInt64 = 0 - var revision: UInt64 = 0 - var identity_index: UInt32 = 0 - var status: UInt8 = 0 - var dpns_names: UnsafePointer?>? = nil - var dpns_names_count: Int = 0 - var contested_dpns_names: UnsafePointer?>? = nil - var contested_dpns_names_count: Int = 0 - var keys: UnsafePointer? = nil - var keys_count: Int = 0 -} - -struct WalletRestoreEntryFFI { - var wallet_id: ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - ) = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) - var network: UInt8 = 0 - var accounts: UnsafePointer? = nil - var accounts_count: Int = 0 - var platform_address_balances: UnsafePointer? = nil - var platform_address_balances_count: Int = 0 - var platform_sync_height: UInt64 = 0 - var platform_sync_timestamp: UInt64 = 0 - var platform_last_known_recent_block: UInt64 = 0 - var identities: UnsafePointer? = nil - var identities_count: Int = 0 -} - -// MARK: - Event Handler Callbacks - -struct EventHandlerCallbacks { - var context: UnsafeMutableRawPointer? = nil - var on_wallet_event_fn: (@convention(c) (UnsafeMutableRawPointer?, UnsafePointer?, Int) -> Void)? = nil - var on_error_fn: (@convention(c) (UnsafeMutableRawPointer?, UnsafePointer?) -> Void)? = nil - var on_platform_address_sync_completed_fn: (@convention(c) ( - UnsafeMutableRawPointer?, - UnsafeRawPointer?, - Int, - UInt64 - ) -> Void)? = nil -} - -// MARK: - Platform Address Types - -struct PlatformAddressFFI { - var address_type: UInt8 - var hash: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8) -} - -struct AddressBalanceEntryFFI { - var address: PlatformAddressFFI - var balance: UInt64 - var nonce: UInt32 - var account_index: UInt32 - var address_index: UInt32 -} - -struct AddressSyncConfigFFI { - var min_privacy_count: UInt64 - var max_concurrent_requests: UInt32 - var max_iterations: UInt32 - var full_rescan_after_time_s: UInt64 -} - -struct PlatformAddressChangeSetFFI { - var updated: UnsafeMutablePointer? - var updated_count: Int -} - -struct PlatformAddressSyncMetricsFFI { - var trunk_queries: UInt32 - var branch_queries: UInt32 - var total_elements_seen: UInt32 - var total_proof_bytes: UInt32 - var iterations: UInt32 - var compacted_queries: UInt32 - var recent_queries: UInt32 - var recent_entries_returned: UInt32 - var compacted_entries_returned: UInt32 -} - -struct PlatformAddressSyncWalletResultFFI { - var wallet_id: ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - ) - var success: Bool - var found_count: Int - var absent_count: Int - var checkpoint_height: UInt64 - var new_sync_height: UInt64 - var new_sync_timestamp: UInt64 - var last_known_recent_block: UInt64 - var metrics: PlatformAddressSyncMetricsFFI - var error_message: UnsafePointer? -} - -// MARK: - SPV Sync Progress - -struct FFISpvSyncProgress { - var overall_state: UInt32 - var overall_percentage: Double - - var has_headers: Bool - var headers_state: UInt32 - var headers_current: UInt32 - var headers_target: UInt32 - var headers_percentage: Double - - var has_filter_headers: Bool - var filter_headers_state: UInt32 - var filter_headers_current: UInt32 - var filter_headers_target: UInt32 - var filter_headers_percentage: Double - - var has_filters: Bool - var filters_state: UInt32 - var filters_current: UInt32 - var filters_target: UInt32 - var filters_percentage: Double - - var has_masternodes: Bool - var masternodes_state: UInt32 - var masternodes_current: UInt32 - var masternodes_target: UInt32 - var masternodes_percentage: Double -} - -// MARK: - SDK Inner Pointer - -@_silgen_name("dash_sdk_get_inner_sdk_ptr") -func dash_sdk_get_inner_sdk_ptr( - _ handle: UnsafeMutablePointer? -) -> UnsafeRawPointer? - -// MARK: - PlatformWalletManager FFI - -@_silgen_name("platform_wallet_manager_create") -func platform_wallet_manager_create( - _ sdk_ptr: UnsafeRawPointer?, - _ persistence: UnsafePointer?, - _ event_handler: UnsafePointer?, - _ out_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_create_wallet_from_mnemonic") -func platform_wallet_manager_create_wallet_from_mnemonic( - _ manager_handle: Handle, - _ mnemonic: UnsafePointer?, - _ network: UInt32, - _ account_options: UInt32, - _ out_wallet_handle: UnsafeMutablePointer, - _ out_wallet_id: UnsafeMutablePointer<(UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_create_wallet_from_seed") -func platform_wallet_manager_create_wallet_from_seed( - _ manager_handle: Handle, - _ network: UInt32, - _ seed_bytes: UnsafePointer?, - _ seed_len: Int, - _ account_options: UInt32, - _ out_wallet_handle: UnsafeMutablePointer, - _ out_wallet_id: UnsafeMutablePointer<(UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// MARK: - PlatformWalletManager SPV FFI - -@_silgen_name("platform_wallet_manager_sync_progress") -func platform_wallet_manager_sync_progress( - _ handle: Handle, - _ out_progress: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_spv_is_running") -func platform_wallet_manager_spv_is_running( - _ handle: Handle, - _ out_running: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_spv_start") -func platform_wallet_manager_spv_start( - _ handle: Handle, - _ data_dir: UnsafePointer?, - _ network: UInt32, - _ user_agent: UnsafePointer?, - _ peers: UnsafePointer?>?, - _ peer_count: Int, - _ restrict_to_configured_peers: Bool, - _ start_from_height: UInt32, - _ masternode_sync_enabled: Bool, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_spv_stop") -func platform_wallet_manager_spv_stop( - _ handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_spv_clear_storage") -func platform_wallet_manager_spv_clear_storage( - _ handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// MARK: - PlatformWalletManager Platform Address Sync FFI - -@_silgen_name("platform_wallet_manager_platform_address_sync_start") -func platform_wallet_manager_platform_address_sync_start( - _ handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_platform_address_sync_stop") -func platform_wallet_manager_platform_address_sync_stop( - _ handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_platform_address_sync_is_running") -func platform_wallet_manager_platform_address_sync_is_running( - _ handle: Handle, - _ out_running: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_platform_address_sync_is_syncing") -func platform_wallet_manager_platform_address_sync_is_syncing( - _ handle: Handle, - _ out_syncing: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_platform_address_sync_last_sync_unix_seconds") -func platform_wallet_manager_platform_address_sync_last_sync_unix_seconds( - _ handle: Handle, - _ out_last_sync_unix: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_platform_address_sync_set_interval") -func platform_wallet_manager_platform_address_sync_set_interval( - _ handle: Handle, - _ interval_seconds: UInt64, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_platform_address_sync_set_config") -func platform_wallet_manager_platform_address_sync_set_config( - _ handle: Handle, - _ config: UnsafePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_platform_address_sync_sync_now") -func platform_wallet_manager_platform_address_sync_sync_now( - _ handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_load_from_persistor") -func platform_wallet_manager_load_from_persistor( - _ manager_handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_get_wallet") -func platform_wallet_manager_get_wallet( - _ manager_handle: Handle, - _ wallet_id: UnsafePointer?, - _ out_wallet_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_manager_destroy") -func platform_wallet_manager_destroy( - _ handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// MARK: - Xpub Rendering - -@_silgen_name("platform_wallet_account_xpub_to_string") -func platform_wallet_account_xpub_to_string( - _ bytes: UnsafePointer?, - _ bytes_len: Int, - _ out_string: UnsafeMutablePointer?>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_free_string") -func platform_wallet_free_string(_ s: UnsafeMutablePointer?) - -// MARK: - PlatformWallet FFI - -@_silgen_name("platform_wallet_get_core") -func platform_wallet_get_core( - _ handle: Handle, - _ out_core_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_get_id") -func platform_wallet_get_id( - _ handle: Handle, - _ out_wallet_id: UnsafeMutablePointer<(UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_get_balance") -func platform_wallet_get_balance( - _ handle: Handle, - _ out_spendable: UnsafeMutablePointer?, - _ out_unconfirmed: UnsafeMutablePointer?, - _ out_immature: UnsafeMutablePointer?, - _ out_locked: UnsafeMutablePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_get_platform") -func platform_wallet_get_platform( - _ handle: Handle, - _ out_platform_handle: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_flush_persist") -func platform_wallet_flush_persist( - _ handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_load_and_apply_persisted") -func platform_wallet_load_and_apply_persisted( - _ handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_destroy") -func platform_wallet_destroy( - _ handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// MARK: - PlatformAddressWallet FFI - -@_silgen_name("platform_address_wallet_total_credits") -func platform_address_wallet_total_credits( - _ handle: Handle, - _ out_credits: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_address_wallet_addresses_with_balances") -func platform_address_wallet_addresses_with_balances( - _ handle: Handle, - _ out_entries: UnsafeMutablePointer?>, - _ out_count: UnsafeMutablePointer, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_address_wallet_destroy") -func platform_address_wallet_destroy( - _ handle: Handle, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// MARK: - Memory Free Functions - -@_silgen_name("platform_address_wallet_free_address_balances") -func platform_address_wallet_free_address_balances( - _ entries: UnsafeMutablePointer?, - _ count: Int -) - -@_silgen_name("platform_address_wallet_free_changeset") -func platform_address_wallet_free_changeset(_ changeset: UnsafePointer?) diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManagerSPV.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManagerSPV.swift index d46965f15b5..5ec3d594374 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManagerSPV.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManagerSPV.swift @@ -149,7 +149,7 @@ extension PlatformWalletManager { ) var error = PlatformWalletFFIError() let result = platform_wallet_manager_sync_progress(handle, &ffi, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } return PlatformSpvSyncProgress(ffi) @@ -160,7 +160,7 @@ extension PlatformWalletManager { var running: Bool = false var error = PlatformWalletFFIError() let result = platform_wallet_manager_spv_is_running(handle, &running, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } return running @@ -191,7 +191,7 @@ extension PlatformWalletManager { config.network.rawValue, userAgentPtr, peersPtr, - peerCStrings.count, + UInt(peerCStrings.count), config.restrictToConfiguredPeers, config.startFromHeight, config.masternodeSyncEnabled, @@ -200,7 +200,7 @@ extension PlatformWalletManager { } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } } @@ -209,7 +209,7 @@ extension PlatformWalletManager { public func stopSpv() throws { var error = PlatformWalletFFIError() let result = platform_wallet_manager_spv_stop(handle, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } } @@ -220,7 +220,7 @@ extension PlatformWalletManager { public func clearSpvStorage() throws { var error = PlatformWalletFFIError() let result = platform_wallet_manager_spv_clear_storage(handle, &error) - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletPersistenceHandler.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletPersistenceHandler.swift index 3db2ae8f607..72e02853280 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletPersistenceHandler.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletPersistenceHandler.swift @@ -179,7 +179,7 @@ public class PlatformWalletPersistenceHandler { // Per-account: transactions, UTXOs, pool state. if cs.accounts_count > 0, let accountsPtr = cs.accounts { - for i in 0.. 0, let txsPtr = acc.transactions { - for i in 0.. 0, let utxosPtr = acc.utxos_added { - for i in 0.. 0, let spentPtr = acc.utxos_spent { - for i in 0.. 0, let ilPtr = acc.utxos_instant_locked { - for i in 0.. 0 { - record.transactionData = Data(bytes: dataPtr, count: tx.tx_data_len) + record.transactionData = Data(bytes: dataPtr, count: Int(tx.tx_data_len)) } record.lastUpdated = Date() } @@ -353,7 +353,7 @@ public class PlatformWalletPersistenceHandler { } else { let script: Data = { guard let p = utxo.script_pubkey, utxo.script_pubkey_len > 0 else { return Data() } - return Data(bytes: p, count: utxo.script_pubkey_len) + return Data(bytes: p, count: Int(utxo.script_pubkey_len)) }() let addressStr = utxo.address.map { String(cString: $0) } ?? "" record = PersistentUtxo( @@ -1172,7 +1172,7 @@ public class PlatformWalletPersistenceHandler { } let xpubBytes: Data if let xpubPtr = spec.account_xpub_bytes, spec.account_xpub_bytes_len > 0 { - xpubBytes = Data(bytes: xpubPtr, count: spec.account_xpub_bytes_len) + xpubBytes = Data(bytes: xpubPtr, count: Int(spec.account_xpub_bytes_len)) } else { xpubBytes = Data() } @@ -1243,7 +1243,7 @@ public class PlatformWalletPersistenceHandler { /// array, wallet id from the top-level struct. /// /// Returns `(nil, 0)` if nothing is restorable. - func loadWalletList() -> (entries: UnsafeRawPointer?, count: Int) { + func loadWalletList() -> (entries: UnsafePointer?, count: Int) { let walletDescriptor = FetchDescriptor() guard let wallets = try? backgroundContext.fetch(walletDescriptor) else { return (nil, 0) @@ -1289,7 +1289,7 @@ public class PlatformWalletPersistenceHandler { copyBytes(acc.userIdentityId, into: &spec.user_identity_id) copyBytes(acc.friendIdentityId, into: &spec.friend_identity_id) spec.account_xpub_bytes = UnsafePointer(xpubBuffer) - spec.account_xpub_bytes_len = xpub.count + spec.account_xpub_bytes_len = UInt(xpub.count) buf[j] = spec } accountsBuffer = buf @@ -1354,14 +1354,14 @@ public class PlatformWalletPersistenceHandler { copyBytes(w.walletId, into: &entry.wallet_id) entry.network = networkTag(for: w.network) entry.accounts = accountsBuffer.map { UnsafePointer($0) } - entry.accounts_count = sortedAccounts.count + entry.accounts_count = UInt(sortedAccounts.count) entry.platform_address_balances = addressBalancesBuffer.map { UnsafePointer($0) } - entry.platform_address_balances_count = cachedBalances.count + entry.platform_address_balances_count = UInt(cachedBalances.count) entry.platform_sync_height = syncState?.syncHeight ?? 0 entry.platform_sync_timestamp = syncState?.syncTimestamp ?? 0 entry.platform_last_known_recent_block = syncState?.lastKnownRecentBlock ?? 0 entry.identities = identitiesBuffer.map { UnsafePointer($0) } - entry.identities_count = sortedIdentities.count + entry.identities_count = UInt(sortedIdentities.count) // Primary-identity selection + gap-limit scan watermark // were dropped from the FFI shape — both moved off the // Rust manager (UI owns selection now, scan resume is @@ -1369,9 +1369,9 @@ public class PlatformWalletPersistenceHandler { entriesPtr[i] = entry } - let opaque = UnsafeRawPointer(entriesPtr) - loadAllocations[opaque] = allocation - return (opaque, restorable.count) + let typed = UnsafePointer(entriesPtr) + loadAllocations[UnsafeRawPointer(typed)] = allocation + return (typed, restorable.count) } /// Allocate a contiguous `[IdentityRestoreEntryFFI]` buffer for @@ -1466,7 +1466,7 @@ public class PlatformWalletPersistenceHandler { let dataBuf = UnsafeMutablePointer.allocate(capacity: len) pk.publicKeyData.copyBytes(to: dataBuf, count: len) row.data = UnsafePointer(dataBuf) - row.data_len = len + row.data_len = UInt(len) allocation.scalarBuffers.append((dataBuf, len)) } else { row.data = nil @@ -1475,7 +1475,7 @@ public class PlatformWalletPersistenceHandler { keyBuf[k] = row } entry.keys = UnsafePointer(keyBuf) - entry.keys_count = sortedKeys.count + entry.keys_count = UInt(sortedKeys.count) allocation.identityKeyArrays.append((keyBuf, sortedKeys.count)) } @@ -1688,12 +1688,12 @@ private func copyBytes(_ src: Data, into dst: inout T) { private func persistAddressBalancesCallback( context: UnsafeMutableRawPointer?, walletIdPtr: UnsafePointer?, - entriesRaw: UnsafeRawPointer?, - count: Int + entriesPtr: UnsafePointer?, + count: UInt ) -> Int32 { guard let context = context, let walletIdPtr = walletIdPtr, - let entriesRaw = entriesRaw, + let entriesPtr = entriesPtr, count > 0 else { return 0 } @@ -1703,12 +1703,11 @@ private func persistAddressBalancesCallback( .takeUnretainedValue() let walletId = Data(bytes: walletIdPtr, count: 32) - let entriesPtr = entriesRaw.assumingMemoryBound(to: AddressBalanceEntryFFI.self) var entries: [(UInt8, Data, UInt64, UInt32, UInt32, UInt32)] = [] - entries.reserveCapacity(count) + entries.reserveCapacity(Int(count)) - for i in 0..?, - changesetRaw: UnsafeRawPointer? + changesetPtr: UnsafePointer? ) -> Int32 { guard let context = context, let walletIdPtr = walletIdPtr, - let changesetRaw = changesetRaw else { + let changesetPtr = changesetPtr else { return 0 } @@ -1741,7 +1740,6 @@ private func persistWalletChangesetCallback( .takeUnretainedValue() let walletId = Data(bytes: walletIdPtr, count: 32) - let changesetPtr = changesetRaw.assumingMemoryBound(to: WalletChangeSetFFI.self) handler.persistWalletChangeset(walletId: walletId, changeset: changesetPtr) return 0 } @@ -1815,26 +1813,25 @@ private func persistSyncStateCallback( private func persistAccountCallback( context: UnsafeMutableRawPointer?, walletIdPtr: UnsafePointer?, - specRaw: UnsafeRawPointer? + specPtr: UnsafePointer? ) -> Int32 { guard let context = context, let walletIdPtr = walletIdPtr, - let specRaw = specRaw else { + let specPtr = specPtr else { return 0 } let handler = Unmanaged .fromOpaque(context) .takeUnretainedValue() let walletId = Data(bytes: walletIdPtr, count: 32) - let spec = specRaw.assumingMemoryBound(to: AccountSpecFFI.self).pointee - handler.persistAccount(walletId: walletId, spec: spec) + handler.persistAccount(walletId: walletId, spec: specPtr.pointee) return 0 } private func loadWalletListCallback( context: UnsafeMutableRawPointer?, - outEntries: UnsafeMutablePointer?, - outCount: UnsafeMutablePointer? + outEntries: UnsafeMutablePointer?>?, + outCount: UnsafeMutablePointer? ) -> Int32 { guard let context = context, let outEntries = outEntries, @@ -1846,33 +1843,32 @@ private func loadWalletListCallback( .takeUnretainedValue() let (entries, count) = handler.loadWalletList() outEntries.pointee = entries - outCount.pointee = count + outCount.pointee = UInt(count) return 0 } private func loadWalletListFreeCallback( context: UnsafeMutableRawPointer?, - entries: UnsafeRawPointer?, - _ count: Int + entries: UnsafePointer?, + _ count: UInt ) { guard let context = context else { return } let handler = Unmanaged .fromOpaque(context) .takeUnretainedValue() - handler.loadWalletListFree(entries: entries) + handler.loadWalletListFree(entries: entries.map(UnsafeRawPointer.init)) } private func persistAccountAddressesCallback( context: UnsafeMutableRawPointer?, walletIdPtr: UnsafePointer?, - specRaw: UnsafeRawPointer?, - addressesRaw: UnsafeRawPointer?, - count: Int + specPtr: UnsafePointer?, + addressesPtr: UnsafePointer?, + count: UInt ) -> Int32 { guard let context = context, let walletIdPtr = walletIdPtr, - let specRaw = specRaw, - count >= 0 else { + let specPtr = specPtr else { return 0 } let handler = Unmanaged @@ -1880,9 +1876,7 @@ private func persistAccountAddressesCallback( .takeUnretainedValue() let walletId = Data(bytes: walletIdPtr, count: 32) - let spec = specRaw.assumingMemoryBound(to: AccountSpecFFI.self).pointee - let addressesPtr: UnsafePointer? = - addressesRaw?.assumingMemoryBound(to: CoreAddressEntryFFI.self) + let spec = specPtr.pointee var userIdentityId = Data(count: 32) withUnsafeBytes(of: spec.user_identity_id) { src in userIdentityId.withUnsafeMutableBytes { dst in dst.copyMemory(from: src) } @@ -1904,9 +1898,9 @@ private func persistAccountAddressesCallback( // Copy every C-string into a Swift String before leaving the // callback — Rust owns the underlying storage only for this window. var snapshots: [PlatformWalletPersistenceHandler.CoreAddressEntrySnapshot] = [] - snapshots.reserveCapacity(count) + snapshots.reserveCapacity(Int(count)) if count > 0, let addressesPtr = addressesPtr { - for i in 0..?, - upsertsRaw: UnsafeRawPointer?, - upsertsCount: Int, - removedRaw: UnsafeRawPointer?, - removedCount: Int + upsertsPtr: UnsafePointer?, + upsertsCount: UInt, + removedPtr: UnsafePointer?, + removedCount: UInt ) -> Int32 { guard let context = context, let walletIdPtr = walletIdPtr else { @@ -1965,10 +1959,9 @@ private func persistIdentitiesCallback( let walletId = Data(bytes: walletIdPtr, count: 32) var upserts: [PlatformWalletPersistenceHandler.IdentityEntrySnapshot] = [] - if upsertsCount > 0, let upsertsRaw = upsertsRaw { - let upsertsPtr = upsertsRaw.assumingMemoryBound(to: IdentityEntryFFI.self) - upserts.reserveCapacity(upsertsCount) - for i in 0.. 0, let upsertsPtr = upsertsPtr { + upserts.reserveCapacity(Int(upsertsCount)) + for i in 0.. 0, let removedRaw = removedRaw { - let removedPtr = removedRaw.assumingMemoryBound(to: FFIByteTuple32.self) - removed.reserveCapacity(removedCount) - for i in 0.. 0, let removedPtr = removedPtr { + removed.reserveCapacity(Int(removedCount)) + for i in 0..?, - upsertsRaw: UnsafeRawPointer?, - upsertsCount: Int, - removedRaw: UnsafeRawPointer?, - removedCount: Int + upsertsPtr: UnsafePointer?, + upsertsCount: UInt, + removedPtr: UnsafePointer?, + removedCount: UInt ) -> Int32 { guard let context = context, let walletIdPtr = walletIdPtr else { @@ -2023,23 +2015,15 @@ private func persistIdentityKeysCallback( .takeUnretainedValue() let walletId = Data(bytes: walletIdPtr, count: 32) - // Fail fast with a clear message if the Rust / Swift struct - // layouts have drifted — a subtle field reorder on either side - // would otherwise crash in `memmove` deep inside - // `Data(bytes:count:)` with garbage pointer bytes, and take - // ages to diagnose. - assertIdentityKeyEntryLayout() - var upserts: [PlatformWalletPersistenceHandler.IdentityKeyEntrySnapshot] = [] - if upsertsCount > 0, let upsertsRaw = upsertsRaw { - let upsertsPtr = upsertsRaw.assumingMemoryBound(to: IdentityKeyEntryFFI.self) - upserts.reserveCapacity(upsertsCount) - for i in 0.. 0, let upsertsPtr = upsertsPtr { + upserts.reserveCapacity(Int(upsertsCount)) + for i in 0.. 0 { - pubKey = Data(bytes: ptr, count: e.public_key_data_len) + pubKey = Data(bytes: ptr, count: Int(e.public_key_data_len)) } else { pubKey = Data() } @@ -2065,10 +2049,9 @@ private func persistIdentityKeysCallback( } var removed: [(identityId: Data, keyId: UInt32)] = [] - if removedCount > 0, let removedRaw = removedRaw { - let removedPtr = removedRaw.assumingMemoryBound(to: IdentityKeyRemovalFFI.self) - removed.reserveCapacity(removedCount) - for i in 0.. 0, let removedPtr = removedPtr { + removed.reserveCapacity(Int(removedCount)) + for i in 0..? - var count: Int -} - extension Identifier { /// Run `body` with a `*const u8` to this identifier's 32-byte - /// payload. Pointer-passing is the ABI-safe replacement for the - /// old `IdentifierBytes`-by-value pattern (see EXC_BAD_ACCESS - /// sweep — Swift's struct ABI ≠ AAPCS64 for >16-byte aggregates - /// across `@_silgen_name`). + /// payload. /// /// Preconditions: `count == 32`. Identifiers on Platform are /// always exactly 32 bytes; a precondition here surfaces the @@ -42,34 +22,6 @@ extension Identifier { typealias NetworkType = UInt32 -typealias PlatformWalletFFIResult = Int32 - -struct PlatformWalletFFIError { - var code: PlatformWalletFFIResult = 0 - var message: UnsafeMutablePointer? = nil -} - -struct FFIBlockTime { - var height: UInt32 - var core_height: UInt32 - var timestamp: UInt64 -} - -// Error result codes (must match Rust PlatformWalletFFIResult enum values) -let Success: PlatformWalletFFIResult = 0 -let ErrorInvalidHandle: PlatformWalletFFIResult = 1 -let ErrorInvalidParameter: PlatformWalletFFIResult = 2 -let ErrorNullPointer: PlatformWalletFFIResult = 3 -let ErrorSerialization: PlatformWalletFFIResult = 4 -let ErrorDeserialization: PlatformWalletFFIResult = 5 -let ErrorWalletOperation: PlatformWalletFFIResult = 6 -let ErrorIdentityNotFound: PlatformWalletFFIResult = 7 -let ErrorContactNotFound: PlatformWalletFFIResult = 8 -let ErrorInvalidNetwork: PlatformWalletFFIResult = 9 -let ErrorInvalidIdentifier: PlatformWalletFFIResult = 10 -let ErrorMemoryAllocation: PlatformWalletFFIResult = 11 -let ErrorUtf8Conversion: PlatformWalletFFIResult = 12 - /// Platform Wallet error types public enum PlatformWalletError: LocalizedError { case nullPointer @@ -121,29 +73,29 @@ public enum PlatformWalletError: LocalizedError { } switch result { - case ErrorInvalidHandle: + case PLATFORM_WALLET_FFI_RESULT_ERROR_INVALID_HANDLE: self = withDetail(.invalidHandle, prefix: "Invalid handle") - case ErrorInvalidParameter: + case PLATFORM_WALLET_FFI_RESULT_ERROR_INVALID_PARAMETER: self = withDetail(.invalidParameter, prefix: "Invalid parameter") - case ErrorNullPointer: + case PLATFORM_WALLET_FFI_RESULT_ERROR_NULL_POINTER: self = withDetail(.nullPointer, prefix: "Null pointer") - case ErrorSerialization: + case PLATFORM_WALLET_FFI_RESULT_ERROR_SERIALIZATION: self = .serialization(rustMessage ?? "Unknown error") - case ErrorDeserialization: + case PLATFORM_WALLET_FFI_RESULT_ERROR_DESERIALIZATION: self = .deserialization(rustMessage ?? "Unknown error") - case ErrorWalletOperation: + case PLATFORM_WALLET_FFI_RESULT_ERROR_WALLET_OPERATION: self = .walletOperation(rustMessage ?? "Unknown error") - case ErrorIdentityNotFound: + case PLATFORM_WALLET_FFI_RESULT_ERROR_IDENTITY_NOT_FOUND: self = withDetail(.identityNotFound, prefix: "Identity not found") - case ErrorContactNotFound: + case PLATFORM_WALLET_FFI_RESULT_ERROR_CONTACT_NOT_FOUND: self = withDetail(.contactNotFound, prefix: "Contact not found") - case ErrorInvalidNetwork: + case PLATFORM_WALLET_FFI_RESULT_ERROR_INVALID_NETWORK: self = withDetail(.invalidNetwork, prefix: "Invalid network") - case ErrorInvalidIdentifier: + case PLATFORM_WALLET_FFI_RESULT_ERROR_INVALID_IDENTIFIER: self = withDetail(.invalidIdentifier, prefix: "Invalid identifier") - case ErrorMemoryAllocation: + case PLATFORM_WALLET_FFI_RESULT_ERROR_MEMORY_ALLOCATION: self = withDetail(.memoryAllocation, prefix: "Memory allocation") - case ErrorUtf8Conversion: + case PLATFORM_WALLET_FFI_RESULT_ERROR_UTF8_CONVERSION: self = withDetail(.utf8Conversion, prefix: "UTF-8 conversion") default: self = .unknown(rustMessage ?? "Unknown error") @@ -163,33 +115,6 @@ public enum PlatformNetwork: UInt32 { } } -/// Block time information -public struct BlockTime { - public let height: UInt32 - public let coreHeight: UInt32 - public let timestamp: UInt64 - - public init(height: UInt32, coreHeight: UInt32, timestamp: UInt64) { - self.height = height - self.coreHeight = coreHeight - self.timestamp = timestamp - } - - init(ffiBlockTime: FFIBlockTime) { - self.height = ffiBlockTime.height - self.coreHeight = ffiBlockTime.core_height - self.timestamp = ffiBlockTime.timestamp - } - - var ffiValue: FFIBlockTime { - FFIBlockTime( - height: self.height, - core_height: self.coreHeight, - timestamp: self.timestamp - ) - } -} - /// Identity lifecycle status as carried on the Rust-side /// `ManagedIdentity.status`. Mirrors `IdentityStatusFFI` / /// `platform_wallet::wallet::identity::state::managed_identity::IdentityStatus`. @@ -226,11 +151,14 @@ func identifierFromFFI(_ ptr: UnsafePointer) -> Identifier { /// Read a row from an `IdentifierArray` returned by Rust. /// /// `array.items` points at a contiguous `[[u8; 32]; count]` buffer; -/// take a `Data` snapshot of the i-th 32-byte row. +/// take a `Data` snapshot of the i-th 32-byte row. Swift imports +/// `uint8_t (*)[32]` as a pointer to a 32-tuple, so we rebind to a +/// flat `UInt8` pointer before indexing. @inline(__always) func identifierFromFFIArray(_ array: IdentifierArray, at index: Int) -> Identifier { - precondition(index >= 0 && index < array.count, "index out of range") - let base = array.items! + precondition(index >= 0 && index < Int(array.count), "index out of range") + let raw = UnsafeRawPointer(array.items!) + let base = raw.assumingMemoryBound(to: UInt8.self) let row = base.advanced(by: index * 32) return Data(bytes: row, count: 32) } @@ -243,7 +171,7 @@ public func generateRandomIdentifier() throws -> Identifier { let result = buf.withUnsafeMutableBufferPointer { bp -> PlatformWalletFFIResult in platform_wallet_generate_random_identifier(bp.baseAddress!, &error) } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/Tokens/TokenActions.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/Tokens/TokenActions.swift index fc761b3ad04..41005ddd9c3 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/Tokens/TokenActions.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/Tokens/TokenActions.swift @@ -1,213 +1,12 @@ import Foundation -// MARK: - FFI declarations -// -// Mirror the C-ABI exports from -// `packages/rs-platform-wallet-ffi/src/tokens/{transfer,burn,mint,claim,freeze,unfreeze,destroy_frozen_funds,pause,resume,set_price,purchase}.rs`. -// `platform-wallet-ffi` is excluded from the umbrella header (see -// `swift-sdk/build_ios.sh::inject_modulemap`), so each entry point -// is named explicitly via `@_silgen_name`. - -@_silgen_name("platform_wallet_token_transfer") -func platform_wallet_token_transfer( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ token_contract_id: UnsafePointer, - _ token_position: UInt16, - _ recipient_id: UnsafePointer, - _ amount: UInt64, - _ public_note: UnsafePointer?, - _ signing_key_id: UInt32, - _ signer_handle: OpaquePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_token_burn") -func platform_wallet_token_burn( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ token_contract_id: UnsafePointer, - _ token_position: UInt16, - _ amount: UInt64, - _ public_note: UnsafePointer?, - _ group_info_kind: UInt8, - _ group_info_position: UInt16, - _ group_info_action_id: UnsafePointer?, - _ group_info_action_is_proposer: Bool, - _ signing_key_id: UInt32, - _ signer_handle: OpaquePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_token_mint") -func platform_wallet_token_mint( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ token_contract_id: UnsafePointer, - _ token_position: UInt16, - _ issued_to_identity_id: UnsafePointer?, - _ amount: UInt64, - _ public_note: UnsafePointer?, - _ group_info_kind: UInt8, - _ group_info_position: UInt16, - _ group_info_action_id: UnsafePointer?, - _ group_info_action_is_proposer: Bool, - _ signing_key_id: UInt32, - _ signer_handle: OpaquePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_token_claim") -func platform_wallet_token_claim( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ token_contract_id: UnsafePointer, - _ token_position: UInt16, - _ distribution_type: UInt8, - _ public_note: UnsafePointer?, - _ signing_key_id: UInt32, - _ signer_handle: OpaquePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_token_freeze") -func platform_wallet_token_freeze( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ token_contract_id: UnsafePointer, - _ token_position: UInt16, - _ frozen_identity_id: UnsafePointer, - _ public_note: UnsafePointer?, - _ group_info_kind: UInt8, - _ group_info_position: UInt16, - _ group_info_action_id: UnsafePointer?, - _ group_info_action_is_proposer: Bool, - _ signing_key_id: UInt32, - _ signer_handle: OpaquePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_token_unfreeze") -func platform_wallet_token_unfreeze( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ token_contract_id: UnsafePointer, - _ token_position: UInt16, - _ frozen_identity_id: UnsafePointer, - _ public_note: UnsafePointer?, - _ group_info_kind: UInt8, - _ group_info_position: UInt16, - _ group_info_action_id: UnsafePointer?, - _ group_info_action_is_proposer: Bool, - _ signing_key_id: UInt32, - _ signer_handle: OpaquePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_token_destroy_frozen_funds") -func platform_wallet_token_destroy_frozen_funds( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ token_contract_id: UnsafePointer, - _ token_position: UInt16, - _ frozen_identity_id: UnsafePointer, - _ public_note: UnsafePointer?, - _ group_info_kind: UInt8, - _ group_info_position: UInt16, - _ group_info_action_id: UnsafePointer?, - _ group_info_action_is_proposer: Bool, - _ signing_key_id: UInt32, - _ signer_handle: OpaquePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_token_pause") -func platform_wallet_token_pause( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ token_contract_id: UnsafePointer, - _ token_position: UInt16, - _ public_note: UnsafePointer?, - _ group_info_kind: UInt8, - _ group_info_position: UInt16, - _ group_info_action_id: UnsafePointer?, - _ group_info_action_is_proposer: Bool, - _ signing_key_id: UInt32, - _ signer_handle: OpaquePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_token_resume") -func platform_wallet_token_resume( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ token_contract_id: UnsafePointer, - _ token_position: UInt16, - _ public_note: UnsafePointer?, - _ group_info_kind: UInt8, - _ group_info_position: UInt16, - _ group_info_action_id: UnsafePointer?, - _ group_info_action_is_proposer: Bool, - _ signing_key_id: UInt32, - _ signer_handle: OpaquePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_token_set_price") -func platform_wallet_token_set_price( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ token_contract_id: UnsafePointer, - _ token_position: UInt16, - _ price_per_token: UInt64, - _ public_note: UnsafePointer?, - _ group_info_kind: UInt8, - _ group_info_position: UInt16, - _ group_info_action_id: UnsafePointer?, - _ group_info_action_is_proposer: Bool, - _ signing_key_id: UInt32, - _ signer_handle: OpaquePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_token_purchase") -func platform_wallet_token_purchase( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ token_contract_id: UnsafePointer, - _ token_position: UInt16, - _ amount: UInt64, - _ expected_total_cost: UInt64, - _ signing_key_id: UInt32, - _ signer_handle: OpaquePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_token_update_config") -func platform_wallet_token_update_config( - _ wallet_handle: Handle, - _ identity_id: UnsafePointer, - _ token_contract_id: UnsafePointer, - _ token_position: UInt16, - _ change_item_tag: UInt8, - _ change_item_payload_json: UnsafePointer?, - _ public_note: UnsafePointer?, - _ group_info_kind: UInt8, - _ group_info_position: UInt16, - _ group_info_action_id: UnsafePointer?, - _ group_info_action_is_proposer: Bool, - _ signing_key_id: UInt32, - _ signer_handle: OpaquePointer?, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - // MARK: - Token distribution type /// Mirrors /// `dpp::data_contract::associated_token::token_distribution_key::TokenDistributionType`. /// The raw values are the FFI discriminants accepted by /// `platform_wallet_token_claim`. -public enum TokenDistributionType: UInt8, Equatable, CaseIterable { +public enum TokenDistributionType: UInt8, Equatable, CaseIterable, Sendable { case preProgrammed = 0 case perpetual = 1 } @@ -319,7 +118,7 @@ extension ManagedPlatformWallet { } } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } }.value @@ -376,7 +175,7 @@ extension ManagedPlatformWallet { } } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } }.value @@ -435,7 +234,7 @@ extension ManagedPlatformWallet { } } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } }.value @@ -481,7 +280,7 @@ extension ManagedPlatformWallet { } } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } }.value @@ -538,7 +337,7 @@ extension ManagedPlatformWallet { } } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } }.value @@ -592,7 +391,7 @@ extension ManagedPlatformWallet { } } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } }.value @@ -647,7 +446,7 @@ extension ManagedPlatformWallet { } } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } }.value @@ -699,7 +498,7 @@ extension ManagedPlatformWallet { } } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } }.value @@ -751,7 +550,7 @@ extension ManagedPlatformWallet { } } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } }.value @@ -810,7 +609,7 @@ extension ManagedPlatformWallet { } } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } }.value @@ -861,7 +660,7 @@ extension ManagedPlatformWallet { ) } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } }.value @@ -924,7 +723,7 @@ extension ManagedPlatformWallet { } } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } }.value diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/Tokens/TokenGroupActionQueries.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/Tokens/TokenGroupActionQueries.swift index f6e02a005a1..c1f718ce1fa 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/Tokens/TokenGroupActionQueries.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/Tokens/TokenGroupActionQueries.swift @@ -1,39 +1,5 @@ import Foundation -// MARK: - FFI declarations -// -// Mirror the C-ABI exports from -// `packages/rs-platform-wallet-ffi/src/tokens/group_queries.rs`. These -// queries are read-only — they list pending (or closed) group-action -// proposals on a token contract, and list which identities have signed -// a specific proposal. - -@_silgen_name("platform_wallet_token_pending_group_actions") -func platform_wallet_token_pending_group_actions( - _ wallet_handle: Handle, - _ token_contract_id: UnsafePointer, - _ group_contract_position: UInt16, - _ status: UInt8, - _ start_at_action_id: UnsafePointer?, - _ limit: UInt16, - _ out_json: UnsafeMutablePointer?>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -@_silgen_name("platform_wallet_token_group_action_signers") -func platform_wallet_token_group_action_signers( - _ wallet_handle: Handle, - _ token_contract_id: UnsafePointer, - _ group_contract_position: UInt16, - _ status: UInt8, - _ action_id: UnsafePointer, - _ out_json: UnsafeMutablePointer?>, - _ out_error: UnsafeMutablePointer -) -> PlatformWalletFFIResult - -// `platform_wallet_free_string` is declared in -// `PlatformWalletManagerFFI.swift` — reuse that symbol. - // MARK: - Public types /// Status of a group-action proposal on Platform. Mirrors @@ -351,7 +317,7 @@ extension ManagedPlatformWallet { ) } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } return try ManagedPlatformWallet.consumeJSONArray(jsonOut) @@ -387,7 +353,7 @@ extension ManagedPlatformWallet { ) } } - guard result == Success else { + guard result == PLATFORM_WALLET_FFI_RESULT_SUCCESS else { throw PlatformWalletError(result: result, error: error) } return try ManagedPlatformWallet.consumeJSONArray(jsonOut) diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/Security/KeychainManager.swift b/packages/swift-sdk/Sources/SwiftDashSDK/Security/KeychainManager.swift index 004517d96df..b096b2d8043 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/Security/KeychainManager.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/Security/KeychainManager.swift @@ -471,7 +471,7 @@ extension KeychainManager { guard let base = raw.bindMemory(to: UInt8.self).baseAddress else { return -1 } return out.withUnsafeMutableBufferPointer { buf -> Int32 in guard let outBase = buf.baseAddress else { return -1 } - return platform_wallet_hash160(base, publicKey.count, outBase) + return platform_wallet_hash160(base, UInt(publicKey.count), outBase) } } guard rc == 0 else { return "" } diff --git a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swift b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swift index 983b7881e3d..bd66ced4f58 100644 --- a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swift +++ b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swift @@ -650,7 +650,7 @@ struct TransitionDetailView: View { from: dppIdentity, toIdentityId: normalizedToIdentityId, amount: amount, - signer: signer.handle + signer: OpaquePointer(signer.handle) ) _ = signer // keepalive @@ -704,7 +704,7 @@ struct TransitionDetailView: View { amount: amount, toAddress: toAddress, coreFeePerByte: coreFeePerByte, - signer: signer.handle + signer: OpaquePointer(signer.handle) ) _ = signer // keepalive @@ -801,7 +801,7 @@ struct TransitionDetailView: View { documentType: documentType, ownerIdentity: dppIdentity, properties: properties, - signer: signer.handle + signer: OpaquePointer(signer.handle) ) _ = signer // keepalive @@ -845,7 +845,7 @@ struct TransitionDetailView: View { documentType: documentType, documentId: documentId, ownerIdentity: dppIdentity, - signer: signer.handle + signer: OpaquePointer(signer.handle) ) _ = signer // keepalive across the await — see KeychainSigner lifetime contract @@ -901,7 +901,7 @@ struct TransitionDetailView: View { documentId: documentId, fromIdentity: fromIdentity, toIdentityId: recipientId, - signer: signer.handle + signer: OpaquePointer(signer.handle) ) _ = signer // keepalive @@ -956,7 +956,7 @@ struct TransitionDetailView: View { documentId: documentId, newPrice: newPrice, ownerIdentity: ownerDPPIdentity, - signer: signer.handle + signer: OpaquePointer(signer.handle) ) _ = signer // keepalive @@ -1014,7 +1014,7 @@ struct TransitionDetailView: View { documentId: documentId, purchaserIdentity: fromIdentity, price: price, - signer: signer.handle + signer: OpaquePointer(signer.handle) ) _ = signer // keepalive @@ -1107,7 +1107,7 @@ struct TransitionDetailView: View { documentId: documentId, ownerIdentity: dppIdentity, properties: properties, - signer: signer.handle + signer: OpaquePointer(signer.handle) ) _ = signer // keepalive @@ -1204,7 +1204,7 @@ struct TransitionDetailView: View { amount: amount, ownerIdentity: dppIdentity, keyId: mintingKey.id, - signer: signer.handle, + signer: OpaquePointer(signer.handle), note: note ) _ = signer // keepalive @@ -1292,7 +1292,7 @@ struct TransitionDetailView: View { amount: amount, ownerIdentity: dppIdentity, keyId: burningKey.id, - signer: signer.handle, + signer: OpaquePointer(signer.handle), note: note ) _ = signer // keepalive @@ -1345,7 +1345,7 @@ struct TransitionDetailView: View { targetIdentityId: targetIdentityId, ownerIdentity: dppIdentity, keyId: freezingKey.id, - signer: signer.handle, + signer: OpaquePointer(signer.handle), note: note ) _ = signer // keepalive @@ -1393,7 +1393,7 @@ struct TransitionDetailView: View { targetIdentityId: targetIdentityId, ownerIdentity: dppIdentity, keyId: unfreezingKey.id, - signer: signer.handle, + signer: OpaquePointer(signer.handle), note: formInputs["note"] ) _ = signer // keepalive @@ -1441,7 +1441,7 @@ struct TransitionDetailView: View { frozenIdentityId: frozenIdentityId, ownerIdentity: dppIdentity, keyId: destroyKey.id, - signer: signer.handle, + signer: OpaquePointer(signer.handle), note: formInputs["note"] ) _ = signer // keepalive @@ -1491,7 +1491,7 @@ struct TransitionDetailView: View { distributionType: distributionType, ownerIdentity: dppIdentity, keyId: claimingKey.id, - signer: signer.handle, + signer: OpaquePointer(signer.handle), note: note ) _ = signer // keepalive @@ -1563,7 +1563,7 @@ struct TransitionDetailView: View { amount: amount, ownerIdentity: dppIdentity, keyId: transferKey.id, - signer: signer.handle, + signer: OpaquePointer(signer.handle), note: note ) _ = signer // keepalive @@ -1617,7 +1617,7 @@ struct TransitionDetailView: View { priceData: priceData, ownerIdentity: dppIdentity, keyId: pricingKey.id, - signer: signer.handle, + signer: OpaquePointer(signer.handle), note: note ) _ = signer // keepalive diff --git a/packages/swift-sdk/build_ios.sh b/packages/swift-sdk/build_ios.sh index 67f5d9e5b3a..5e64d324f4c 100755 --- a/packages/swift-sdk/build_ios.sh +++ b/packages/swift-sdk/build_ios.sh @@ -128,20 +128,11 @@ inject_modulemap() { #ifndef DASHSDKFFI_H #define DASHSDKFFI_H -// dash-network defines FFINetwork (referenced by key-wallet-ffi and -// dash-spv-ffi) so it must come first. #include "dash-network/dash-network.h" #include "key-wallet-ffi/key-wallet-ffi.h" #include "dash-spv-ffi/dash-spv-ffi.h" #include "rs-sdk-ffi/rs-sdk-ffi.h" -// dashcore/dashcore.h is deliberately excluded via the module map — it -// duplicates the FFINetwork enum defined in dash-network/dash-network.h -// with a differently-named (anonymous) underlying enum tag, which -// triggers typedef-redefinition errors when both are visible. -// platform-wallet-ffi is also excluded: Swift declares its own -// platform-wallet symbols via @_silgen_name in PlatformWalletFFI.swift, -// and exposing the generated C header alongside those would produce -// duplicate declarations (see upstream PR #3500 for the migration). +#include "platform-wallet-ffi/platform-wallet-ffi.h" #endif EOF @@ -149,7 +140,6 @@ EOF cat > "$HEADERS_DIR/module.modulemap" << 'EOF' module DashSDKFFI { umbrella header "DashSDKFFI.h" - exclude header "dashcore/dashcore.h" export * } EOF