From 126da4f9f8bf736653855c7b22972ab6b86ff55e Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 19 Feb 2026 08:47:34 +0100 Subject: [PATCH 01/19] fix(swift-sdk): use workspace root target dir for dash-spv-ffi build artifacts rust-dashcore is a Cargo workspace, so `cargo build` inside the dash-spv-ffi member crate outputs to the workspace root's target/ directory, not dash-spv-ffi/target/. The build script was looking for libdash_spv_ffi.a in the wrong location, causing the SPV library merge to be silently skipped and SPV symbols to be missing from the final XCFramework. Co-Authored-By: Claude Opus 4.6 --- packages/rs-sdk-ffi/build_ios.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/rs-sdk-ffi/build_ios.sh b/packages/rs-sdk-ffi/build_ios.sh index 6a01b36ffac..a3dcbdcf56c 100755 --- a/packages/rs-sdk-ffi/build_ios.sh +++ b/packages/rs-sdk-ffi/build_ios.sh @@ -323,6 +323,7 @@ fi # Build dash-spv-ffi from local rust-dashcore for device and simulator RUST_DASHCORE_PATH="$PROJECT_ROOT/../rust-dashcore" SPV_CRATE_PATH="$RUST_DASHCORE_PATH/dash-spv-ffi" +SPV_TARGET_DIR="$RUST_DASHCORE_PATH/target" # workspace root target dir if [ -d "$SPV_CRATE_PATH" ]; then echo -e "${GREEN}Building dash-spv-ffi (local rust-dashcore)${NC}" pushd "$SPV_CRATE_PATH" >/dev/null @@ -377,11 +378,11 @@ if [ "$BUILD_ARCH" != "x86" ]; then mkdir -p "$OUTPUT_DIR/device" cp "$PROJECT_ROOT/target/aarch64-apple-ios/release/librs_sdk_ffi.a" "$OUTPUT_DIR/device/" # Merge with dash-spv-ffi device lib if available - if [ -f "$SPV_CRATE_PATH/target/aarch64-apple-ios/release/libdash_spv_ffi.a" ]; then + if [ -f "$SPV_TARGET_DIR/aarch64-apple-ios/release/libdash_spv_ffi.a" ]; then echo -e "${GREEN}Merging device libs (rs-sdk-ffi + dash-spv-ffi)${NC}" libtool -static -o "$OUTPUT_DIR/device/libDashSDKFFI_combined.a" \ "$OUTPUT_DIR/device/librs_sdk_ffi.a" \ - "$SPV_CRATE_PATH/target/aarch64-apple-ios/release/libdash_spv_ffi.a" + "$SPV_TARGET_DIR/aarch64-apple-ios/release/libdash_spv_ffi.a" COMBINED_DEVICE_LIB=1 fi fi @@ -445,10 +446,10 @@ fi if [ -f "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" ]; then # Try to merge with SPV sim lib if it exists SIM_SPV_LIB="" - if [ -f "$SPV_CRATE_PATH/target/aarch64-apple-ios-sim/release/libdash_spv_ffi.a" ]; then - SIM_SPV_LIB="$SPV_CRATE_PATH/target/aarch64-apple-ios-sim/release/libdash_spv_ffi.a" - elif [ -f "$SPV_CRATE_PATH/target/x86_64-apple-ios/release/libdash_spv_ffi.a" ]; then - SIM_SPV_LIB="$SPV_CRATE_PATH/target/x86_64-apple-ios/release/libdash_spv_ffi.a" + if [ -f "$SPV_TARGET_DIR/aarch64-apple-ios-sim/release/libdash_spv_ffi.a" ]; then + SIM_SPV_LIB="$SPV_TARGET_DIR/aarch64-apple-ios-sim/release/libdash_spv_ffi.a" + elif [ -f "$SPV_TARGET_DIR/x86_64-apple-ios/release/libdash_spv_ffi.a" ]; then + SIM_SPV_LIB="$SPV_TARGET_DIR/x86_64-apple-ios/release/libdash_spv_ffi.a" fi if [ -n "$SIM_SPV_LIB" ]; then echo -e "${GREEN}Merging simulator libs (rs-sdk-ffi + dash-spv-ffi)${NC}" From 6b5c2fdcd7ba4ba835e2173b62c23350946b583f Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 19 Feb 2026 08:52:48 +0100 Subject: [PATCH 02/19] fix(swift-sdk): merge SPV lib into librs_sdk_ffi.a for consistent XCFramework naming The previous approach created libDashSDKFFI_combined.a which changed the library name inside the XCFramework, breaking the symbol verification that expects librs_sdk_ffi.a. Now the merge overwrites librs_sdk_ffi.a via a temp file, keeping a consistent name regardless of whether SPV symbols were merged. Co-Authored-By: Claude Opus 4.6 --- packages/rs-sdk-ffi/build_ios.sh | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/rs-sdk-ffi/build_ios.sh b/packages/rs-sdk-ffi/build_ios.sh index a3dcbdcf56c..de77ab902fb 100755 --- a/packages/rs-sdk-ffi/build_ios.sh +++ b/packages/rs-sdk-ffi/build_ios.sh @@ -377,13 +377,14 @@ fi if [ "$BUILD_ARCH" != "x86" ]; then mkdir -p "$OUTPUT_DIR/device" cp "$PROJECT_ROOT/target/aarch64-apple-ios/release/librs_sdk_ffi.a" "$OUTPUT_DIR/device/" - # Merge with dash-spv-ffi device lib if available + # Merge with dash-spv-ffi device lib if available (overwrite librs_sdk_ffi.a + # so the XCFramework always uses a consistent library name) if [ -f "$SPV_TARGET_DIR/aarch64-apple-ios/release/libdash_spv_ffi.a" ]; then echo -e "${GREEN}Merging device libs (rs-sdk-ffi + dash-spv-ffi)${NC}" - libtool -static -o "$OUTPUT_DIR/device/libDashSDKFFI_combined.a" \ + libtool -static -o "$OUTPUT_DIR/device/librs_sdk_ffi_merged.a" \ "$OUTPUT_DIR/device/librs_sdk_ffi.a" \ "$SPV_TARGET_DIR/aarch64-apple-ios/release/libdash_spv_ffi.a" - COMBINED_DEVICE_LIB=1 + mv "$OUTPUT_DIR/device/librs_sdk_ffi_merged.a" "$OUTPUT_DIR/device/librs_sdk_ffi.a" fi fi @@ -436,11 +437,7 @@ rm -rf "$OUTPUT_DIR/$FRAMEWORK_NAME.xcframework" XCFRAMEWORK_CMD="xcodebuild -create-xcframework" if [ "$BUILD_ARCH" != "x86" ] && [ -f "$OUTPUT_DIR/device/librs_sdk_ffi.a" ]; then - if [ -n "${COMBINED_DEVICE_LIB:-}" ] && [ -f "$OUTPUT_DIR/device/libDashSDKFFI_combined.a" ]; then - XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/device/libDashSDKFFI_combined.a -headers $HEADERS_DIR" - else - XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/device/librs_sdk_ffi.a -headers $HEADERS_DIR" - fi + XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/device/librs_sdk_ffi.a -headers $HEADERS_DIR" fi if [ -f "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" ]; then @@ -453,13 +450,12 @@ if [ -f "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" ]; then fi if [ -n "$SIM_SPV_LIB" ]; then echo -e "${GREEN}Merging simulator libs (rs-sdk-ffi + dash-spv-ffi)${NC}" - libtool -static -o "$OUTPUT_DIR/simulator/libDashSDKFFI_combined.a" \ + libtool -static -o "$OUTPUT_DIR/simulator/librs_sdk_ffi_merged.a" \ "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" \ "$SIM_SPV_LIB" - XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/simulator/libDashSDKFFI_combined.a -headers $HEADERS_DIR" - else - XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/simulator/librs_sdk_ffi.a -headers $HEADERS_DIR" + mv "$OUTPUT_DIR/simulator/librs_sdk_ffi_merged.a" "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" fi + XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/simulator/librs_sdk_ffi.a -headers $HEADERS_DIR" fi XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -output $OUTPUT_DIR/$FRAMEWORK_NAME.xcframework" From ccceb50701e5d515e5dd304edc4a9ae2375c122b Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 19 Feb 2026 08:58:51 +0100 Subject: [PATCH 03/19] chore(swift-sdk): add debug output for SPV symbol investigation Temporary debug logging to diagnose why SPV symbols are missing from the merged library even though the merge step succeeds. Co-Authored-By: Claude Opus 4.6 --- packages/rs-sdk-ffi/build_ios.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/rs-sdk-ffi/build_ios.sh b/packages/rs-sdk-ffi/build_ios.sh index de77ab902fb..fd42d688c6d 100755 --- a/packages/rs-sdk-ffi/build_ios.sh +++ b/packages/rs-sdk-ffi/build_ios.sh @@ -381,6 +381,9 @@ if [ "$BUILD_ARCH" != "x86" ]; then # so the XCFramework always uses a consistent library name) if [ -f "$SPV_TARGET_DIR/aarch64-apple-ios/release/libdash_spv_ffi.a" ]; then echo -e "${GREEN}Merging device libs (rs-sdk-ffi + dash-spv-ffi)${NC}" + # Debug: check SPV symbols in source lib before merge + echo " SPV lib symbols (config_add_peer):" + nm -gU "$SPV_TARGET_DIR/aarch64-apple-ios/release/libdash_spv_ffi.a" 2>/dev/null | grep "dash_spv_ffi_config" || echo " (none found)" libtool -static -o "$OUTPUT_DIR/device/librs_sdk_ffi_merged.a" \ "$OUTPUT_DIR/device/librs_sdk_ffi.a" \ "$SPV_TARGET_DIR/aarch64-apple-ios/release/libdash_spv_ffi.a" @@ -450,18 +453,28 @@ if [ -f "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" ]; then fi if [ -n "$SIM_SPV_LIB" ]; then echo -e "${GREEN}Merging simulator libs (rs-sdk-ffi + dash-spv-ffi)${NC}" + # Debug: check SPV symbols in source lib before merge + echo " SPV sim lib symbols (config):" + nm -gU "$SIM_SPV_LIB" 2>/dev/null | grep "dash_spv_ffi_config" || echo " (none found)" libtool -static -o "$OUTPUT_DIR/simulator/librs_sdk_ffi_merged.a" \ "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" \ "$SIM_SPV_LIB" mv "$OUTPUT_DIR/simulator/librs_sdk_ffi_merged.a" "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" + # Debug: verify symbols in merged lib + echo " Merged sim lib symbols (config):" + nm -gU "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" 2>/dev/null | grep "dash_spv_ffi_config" || echo " (none found in merged lib)" fi XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/simulator/librs_sdk_ffi.a -headers $HEADERS_DIR" fi XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -output $OUTPUT_DIR/$FRAMEWORK_NAME.xcframework" +echo " XCFramework cmd: $XCFRAMEWORK_CMD" if eval $XCFRAMEWORK_CMD > /tmp/xcframework.log 2>&1; then echo -e "${GREEN}✓ XCFramework created successfully${NC}" + # Debug: list XCFramework contents + echo " XCFramework contents:" + find "$OUTPUT_DIR/$FRAMEWORK_NAME.xcframework" -name '*.a' -exec echo " {}" \; else echo -e "${RED}✗ XCFramework creation failed${NC}" cat /tmp/xcframework.log From 43b6d5d8c7338a63e35f5c24583268911fa0c7ca Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 19 Feb 2026 09:04:10 +0100 Subject: [PATCH 04/19] fix(swift-sdk): avoid SIGPIPE in symbol verification under pipefail The nm | rg/grep pipeline was silently failing under `set -euo pipefail` because rg/grep could exit early after finding a match, causing nm to receive SIGPIPE (exit 141). With pipefail, this made the pipeline return non-zero even when the symbol was found. Fix by dumping nm output to a temp file first, then grepping it. This avoids the pipe entirely and eliminates the SIGPIPE race condition. Also removes temporary debug logging from the previous commit. Co-Authored-By: Claude Opus 4.6 --- packages/rs-sdk-ffi/build_ios.sh | 13 ------------- packages/swift-sdk/build_ios.sh | 27 +++++++++++---------------- 2 files changed, 11 insertions(+), 29 deletions(-) diff --git a/packages/rs-sdk-ffi/build_ios.sh b/packages/rs-sdk-ffi/build_ios.sh index fd42d688c6d..de77ab902fb 100755 --- a/packages/rs-sdk-ffi/build_ios.sh +++ b/packages/rs-sdk-ffi/build_ios.sh @@ -381,9 +381,6 @@ if [ "$BUILD_ARCH" != "x86" ]; then # so the XCFramework always uses a consistent library name) if [ -f "$SPV_TARGET_DIR/aarch64-apple-ios/release/libdash_spv_ffi.a" ]; then echo -e "${GREEN}Merging device libs (rs-sdk-ffi + dash-spv-ffi)${NC}" - # Debug: check SPV symbols in source lib before merge - echo " SPV lib symbols (config_add_peer):" - nm -gU "$SPV_TARGET_DIR/aarch64-apple-ios/release/libdash_spv_ffi.a" 2>/dev/null | grep "dash_spv_ffi_config" || echo " (none found)" libtool -static -o "$OUTPUT_DIR/device/librs_sdk_ffi_merged.a" \ "$OUTPUT_DIR/device/librs_sdk_ffi.a" \ "$SPV_TARGET_DIR/aarch64-apple-ios/release/libdash_spv_ffi.a" @@ -453,28 +450,18 @@ if [ -f "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" ]; then fi if [ -n "$SIM_SPV_LIB" ]; then echo -e "${GREEN}Merging simulator libs (rs-sdk-ffi + dash-spv-ffi)${NC}" - # Debug: check SPV symbols in source lib before merge - echo " SPV sim lib symbols (config):" - nm -gU "$SIM_SPV_LIB" 2>/dev/null | grep "dash_spv_ffi_config" || echo " (none found)" libtool -static -o "$OUTPUT_DIR/simulator/librs_sdk_ffi_merged.a" \ "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" \ "$SIM_SPV_LIB" mv "$OUTPUT_DIR/simulator/librs_sdk_ffi_merged.a" "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" - # Debug: verify symbols in merged lib - echo " Merged sim lib symbols (config):" - nm -gU "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" 2>/dev/null | grep "dash_spv_ffi_config" || echo " (none found in merged lib)" fi XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/simulator/librs_sdk_ffi.a -headers $HEADERS_DIR" fi XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -output $OUTPUT_DIR/$FRAMEWORK_NAME.xcframework" -echo " XCFramework cmd: $XCFRAMEWORK_CMD" if eval $XCFRAMEWORK_CMD > /tmp/xcframework.log 2>&1; then echo -e "${GREEN}✓ XCFramework created successfully${NC}" - # Debug: list XCFramework contents - echo " XCFramework contents:" - find "$OUTPUT_DIR/$FRAMEWORK_NAME.xcframework" -name '*.a' -exec echo " {}" \; else echo -e "${RED}✗ XCFramework creation failed${NC}" cat /tmp/xcframework.log diff --git a/packages/swift-sdk/build_ios.sh b/packages/swift-sdk/build_ios.sh index 84454aa8232..0781320e040 100755 --- a/packages/swift-sdk/build_ios.sh +++ b/packages/swift-sdk/build_ios.sh @@ -40,32 +40,27 @@ if [[ ! -f "$LIB_SIM_MAIN" ]]; then exit 1 fi echo " - Verifying required SPV symbols are present in XCFramework libs" -# Prefer ripgrep if available; fall back to grep for portability -# Avoid -q with pipefail, which can cause nm to SIGPIPE and fail the check. -if command -v rg >/dev/null 2>&1; then - SEARCH_CMD=(rg -F) # fixed-string match -else - SEARCH_CMD=(grep -F) # fixed-string match +# Dump symbols to a temp file to avoid SIGPIPE issues with pipefail. +# When piping nm to grep/rg, the search tool may exit early after finding a +# match, causing nm to receive SIGPIPE and return exit code 141. With pipefail +# enabled, this makes the pipeline fail even though the symbol was found. +NM_SYMBOLS=$(mktemp) +nm -gU "$LIB_SIM_MAIN" > "$NM_SYMBOLS" 2>/dev/null || true +if [[ -f "$LIB_SIM_SPV" ]]; then + nm -gU "$LIB_SIM_SPV" >> "$NM_SYMBOLS" 2>/dev/null || true fi CHECK_OK=1 -if nm -gU "$LIB_SIM_MAIN" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_add_peer" >/dev/null; then - : -elif [[ -f "$LIB_SIM_SPV" ]] && nm -gU "$LIB_SIM_SPV" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_add_peer" >/dev/null; then - : -else +if ! grep -qF "_dash_spv_ffi_config_add_peer" "$NM_SYMBOLS"; then echo "❌ Missing symbol: dash_spv_ffi_config_add_peer (in both main and spv libs)" CHECK_OK=0 fi -if nm -gU "$LIB_SIM_MAIN" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_set_restrict_to_configured_peers" >/dev/null; then - : -elif [[ -f "$LIB_SIM_SPV" ]] && nm -gU "$LIB_SIM_SPV" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_set_restrict_to_configured_peers" >/dev/null; then - : -else +if ! grep -qF "_dash_spv_ffi_config_set_restrict_to_configured_peers" "$NM_SYMBOLS"; then echo "❌ Missing symbol: dash_spv_ffi_config_set_restrict_to_configured_peers (in both main and spv libs)" CHECK_OK=0 fi +rm -f "$NM_SYMBOLS" if [[ $CHECK_OK -ne 1 ]]; then echo " Please ensure dash-spv-ffi exports these symbols and is included in the XCFramework." From a4db18d8ef8f0edd8adfff35e47aaa9d5edada11 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 19 Feb 2026 09:27:37 +0100 Subject: [PATCH 05/19] fix(swift-sdk): fix Option type in C header and suppress libtool duplicate warnings cbindgen 0.27 does not resolve Option when the alias is a function pointer type, emitting bare `Option` in the C header which is not a valid C type. Fix by defining Optional* type aliases that include Option in the typedef itself (e.g. `type OptionalHasPendingFn = Option`), which cbindgen correctly translates to nullable C function pointers. Also suppress expected "duplicate member name" warnings from libtool when merging rs-sdk-ffi and dash-spv-ffi static libraries that share common dependency objects. Co-Authored-By: Claude Opus 4.6 --- packages/rs-sdk-ffi/build_ios.sh | 24 +++++++++++++--- .../rs-sdk-ffi/src/address_sync/provider.rs | 28 +++++++++++++------ 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/packages/rs-sdk-ffi/build_ios.sh b/packages/rs-sdk-ffi/build_ios.sh index de77ab902fb..d390d60f2a0 100755 --- a/packages/rs-sdk-ffi/build_ios.sh +++ b/packages/rs-sdk-ffi/build_ios.sh @@ -381,9 +381,17 @@ if [ "$BUILD_ARCH" != "x86" ]; then # so the XCFramework always uses a consistent library name) if [ -f "$SPV_TARGET_DIR/aarch64-apple-ios/release/libdash_spv_ffi.a" ]; then echo -e "${GREEN}Merging device libs (rs-sdk-ffi + dash-spv-ffi)${NC}" - libtool -static -o "$OUTPUT_DIR/device/librs_sdk_ffi_merged.a" \ + LIBTOOL_LOG=$(mktemp) + if ! libtool -static -o "$OUTPUT_DIR/device/librs_sdk_ffi_merged.a" \ "$OUTPUT_DIR/device/librs_sdk_ffi.a" \ - "$SPV_TARGET_DIR/aarch64-apple-ios/release/libdash_spv_ffi.a" + "$SPV_TARGET_DIR/aarch64-apple-ios/release/libdash_spv_ffi.a" 2>"$LIBTOOL_LOG"; then + cat "$LIBTOOL_LOG" >&2 + rm -f "$LIBTOOL_LOG" + exit 1 + fi + # Filter out expected duplicate member warnings (shared deps between the two libs) + grep -v "duplicate member name" "$LIBTOOL_LOG" >&2 || true + rm -f "$LIBTOOL_LOG" mv "$OUTPUT_DIR/device/librs_sdk_ffi_merged.a" "$OUTPUT_DIR/device/librs_sdk_ffi.a" fi fi @@ -450,9 +458,17 @@ if [ -f "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" ]; then fi if [ -n "$SIM_SPV_LIB" ]; then echo -e "${GREEN}Merging simulator libs (rs-sdk-ffi + dash-spv-ffi)${NC}" - libtool -static -o "$OUTPUT_DIR/simulator/librs_sdk_ffi_merged.a" \ + LIBTOOL_LOG=$(mktemp) + if ! libtool -static -o "$OUTPUT_DIR/simulator/librs_sdk_ffi_merged.a" \ "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" \ - "$SIM_SPV_LIB" + "$SIM_SPV_LIB" 2>"$LIBTOOL_LOG"; then + cat "$LIBTOOL_LOG" >&2 + rm -f "$LIBTOOL_LOG" + exit 1 + fi + # Filter out expected duplicate member warnings (shared deps between the two libs) + grep -v "duplicate member name" "$LIBTOOL_LOG" >&2 || true + rm -f "$LIBTOOL_LOG" mv "$OUTPUT_DIR/simulator/librs_sdk_ffi_merged.a" "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" fi XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/simulator/librs_sdk_ffi.a -headers $HEADERS_DIR" diff --git a/packages/rs-sdk-ffi/src/address_sync/provider.rs b/packages/rs-sdk-ffi/src/address_sync/provider.rs index 44f5e3de7e4..9b09b294a6b 100644 --- a/packages/rs-sdk-ffi/src/address_sync/provider.rs +++ b/packages/rs-sdk-ffi/src/address_sync/provider.rs @@ -18,11 +18,19 @@ pub type GetGapLimitFn = unsafe extern "C" fn(context: *mut c_void) -> u32; /// Function pointer type for checking if there are pending addresses pub type HasPendingFn = unsafe extern "C" fn(context: *mut c_void) -> bool; +/// Optional function pointer type for checking if there are pending addresses. +/// Nullable — may be null (cbindgen translates this to a nullable C function pointer). +pub type OptionalHasPendingFn = Option bool>; + /// Function pointer type for getting the highest found index /// /// Returns the highest found index, or u32::MAX if none found pub type GetHighestFoundIndexFn = unsafe extern "C" fn(context: *mut c_void) -> u32; +/// Optional function pointer type for getting the highest found index. +/// Nullable — may be null (cbindgen translates this to a nullable C function pointer). +pub type OptionalGetHighestFoundIndexFn = Option u32>; + /// Function pointer type for handling a found address /// /// Called when an address is found in the tree with a balance and nonce. @@ -44,6 +52,10 @@ pub type OnAddressAbsentFn = /// Optional destructor for cleanup pub type DestroyProviderFn = unsafe extern "C" fn(context: *mut c_void); +/// Optional destructor for cleanup. +/// Nullable — may be null (cbindgen translates this to a nullable C function pointer). +pub type OptionalDestroyProviderFn = Option; + /// VTable for address provider callbacks #[repr(C)] pub struct AddressProviderVTable { @@ -59,16 +71,16 @@ pub struct AddressProviderVTable { /// Called when an address is proven absent pub on_address_absent: OnAddressAbsentFn, - /// Check if there are still pending addresses - /// If null, the default implementation (pending_addresses is non-empty) is used - pub has_pending: Option, + /// Check if there are still pending addresses. + /// May be null; if null the default implementation (pending_addresses is non-empty) is used. + pub has_pending: OptionalHasPendingFn, - /// Get the highest found index - /// If null, returns None - pub highest_found_index: Option, + /// Get the highest found index. + /// May be null; if null returns None. + pub highest_found_index: OptionalGetHighestFoundIndexFn, - /// Optional destructor for cleanup - pub destroy: Option, + /// Optional destructor for cleanup. May be null. + pub destroy: OptionalDestroyProviderFn, } /// FFI-compatible address provider using callbacks From f8c9429a435b957a3bb4d1c03db5edb5152ab90f Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 19 Feb 2026 09:45:22 +0100 Subject: [PATCH 06/19] fix(swift-sdk): update Swift SDK for FFINetworks removal in rust-dashcore The rust-dashcore update removed the FFINetworks bitmap type and replaced it with single FFINetwork enum. Network parameter was removed from ~30 FFI functions (now stored at wallet/manager level). Updated all Swift wrappers to match the new C function signatures. Co-Authored-By: Claude Opus 4.6 --- .../SwiftDashSDK/KeyWallet/Account.swift | 2 +- .../KeyWallet/KeyWalletTypes.swift | 28 +- .../KeyWallet/ManagedWallet.swift | 22 +- .../SwiftDashSDK/KeyWallet/Transaction.swift | 68 ++- .../SwiftDashSDK/KeyWallet/Wallet.swift | 229 +++++------ .../KeyWallet/WalletManager.swift | 386 ++++++------------ 6 files changed, 303 insertions(+), 432 deletions(-) diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Account.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Account.swift index 40fa890a227..49c51242b91 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Account.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Account.swift @@ -30,7 +30,7 @@ public class Account { var error = FFIError() // Derive master extended private key for this account root let masterPtr = masterPath.withCString { pathCStr in - wallet_derive_extended_private_key(wallet.ffiHandle, wallet.network.ffiValue, pathCStr, &error) + wallet_derive_extended_private_key(wallet.ffiHandle, pathCStr, &error) } defer { diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift index 32b0c494394..e6ff58f24c5 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift @@ -3,29 +3,27 @@ import DashSDKFFI // MARK: - Network Types -/// Helper to create FFINetworks bitmap from multiple networks +/// Helper to get the FFI network value from a KeyWalletNetwork +/// +/// Note: The old `FFINetworks` bitmap type was removed from rust-dashcore. +/// The FFI now uses `FFINetwork` (single network enum) everywhere. public struct NetworkSet { public let networks: Set - + public init(_ networks: KeyWalletNetwork...) { self.networks = Set(networks) } - + public init(_ networks: [KeyWalletNetwork]) { self.networks = Set(networks) } - - public var ffiNetworks: FFINetworks { - var bitmap: UInt32 = 0 - for network in networks { - switch network { - case .mainnet: bitmap |= (1 << 0) // DASH_FLAG - case .testnet: bitmap |= (1 << 1) // TESTNET_FLAG - case .regtest: bitmap |= (1 << 2) // REGTEST_FLAG - case .devnet: bitmap |= (1 << 3) // DEVNET_FLAG - } - } - return FFINetworks(rawValue: bitmap) + + /// Returns the FFI network value for the first network in the set. + /// Since the FFI no longer supports multi-network bitmaps, only the + /// first network is used. + public var ffiNetwork: FFINetwork { + let network = networks.first ?? .mainnet + return network.ffiValue } } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift index 6598c01b8f0..49f2c9ea42d 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift @@ -43,7 +43,7 @@ public class ManagedWallet { } let addressPtr = managed_wallet_get_next_bip44_receive_address( - infoHandle, wallet.ffiHandle, network.ffiValue, accountIndex, &error) + infoHandle, wallet.ffiHandle, accountIndex, &error) defer { if error.message != nil { @@ -74,7 +74,7 @@ public class ManagedWallet { } let addressPtr = managed_wallet_get_next_bip44_change_address( - infoHandle, wallet.ffiHandle, network.ffiValue, accountIndex, &error) + infoHandle, wallet.ffiHandle, accountIndex, &error) defer { if error.message != nil { @@ -114,7 +114,7 @@ public class ManagedWallet { } let success = managed_wallet_get_bip_44_external_address_range( - infoHandle, wallet.ffiHandle, network.ffiValue, accountIndex, + infoHandle, wallet.ffiHandle, accountIndex, startIndex, endIndex, &addressesPtr, &count, &error) defer { @@ -162,7 +162,7 @@ public class ManagedWallet { } let success = managed_wallet_get_bip_44_internal_address_range( - infoHandle, wallet.ffiHandle, network.ffiValue, accountIndex, + infoHandle, wallet.ffiHandle, accountIndex, startIndex, endIndex, &addressesPtr, &count, &error) defer { @@ -202,7 +202,7 @@ public class ManagedWallet { var ffiInfo = FFIAddressPoolInfo() let success = managed_wallet_get_address_pool_info( - handle, network.ffiValue, accountType.ffiValue, accountIndex, + handle, accountType.ffiValue, accountIndex, poolType.ffiValue, &ffiInfo, &error) defer { @@ -229,7 +229,7 @@ public class ManagedWallet { var error = FFIError() let success = managed_wallet_set_gap_limit( - handle, network.ffiValue, accountType.ffiValue, accountIndex, + handle, accountType.ffiValue, accountIndex, poolType.ffiValue, gapLimit, &error) defer { @@ -257,7 +257,7 @@ public class ManagedWallet { var error = FFIError() let success = managed_wallet_generate_addresses_to_index( - handle, wallet.ffiHandle, network.ffiValue, accountType.ffiValue, + handle, wallet.ffiHandle, accountType.ffiValue, accountIndex, poolType.ffiValue, targetIndex, &error) defer { @@ -277,7 +277,7 @@ public class ManagedWallet { var error = FFIError() let success = address.withCString { addressCStr in - managed_wallet_mark_address_used(handle, network.ffiValue, addressCStr, &error) + managed_wallet_mark_address_used(handle, addressCStr, &error) } defer { @@ -320,14 +320,14 @@ public class ManagedWallet { let hashPtr = hashBytes.bindMemory(to: UInt8.self).baseAddress return managed_wallet_check_transaction( - handle, wallet.ffiHandle, network.ffiValue, + handle, wallet.ffiHandle, txPtr, transactionData.count, context.ffiValue, blockHeight, hashPtr, UInt64(timestamp), updateState, &result, &error) } } else { return managed_wallet_check_transaction( - handle, wallet.ffiHandle, network.ffiValue, + handle, wallet.ffiHandle, txPtr, transactionData.count, context.ffiValue, blockHeight, nil, UInt64(timestamp), updateState, &result, &error) @@ -396,7 +396,7 @@ public class ManagedWallet { var count: size_t = 0 let success = managed_wallet_get_utxos( - infoHandle, network.ffiValue, &utxosPtr, &count, &error) + infoHandle, &utxosPtr, &count, &error) defer { if error.message != nil { diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Transaction.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Transaction.swift index dea3b136737..8c5ae8a9fd2 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Transaction.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Transaction.swift @@ -3,24 +3,24 @@ import DashSDKFFI /// Transaction utilities for wallet operations public class Transaction { - + /// Transaction output for building transactions public struct Output { public let address: String public let amount: UInt64 - + public init(address: String, amount: UInt64) { self.address = address self.amount = amount } - + func toFFI() -> FFITxOutput { return address.withCString { addressCStr in FFITxOutput(address: addressCStr, amount: amount) } } } - + /// Build a transaction /// - Parameters: /// - wallet: The wallet to build from @@ -35,18 +35,17 @@ public class Transaction { guard !outputs.isEmpty else { throw KeyWalletError.invalidInput("Transaction must have at least one output") } - + var error = FFIError() var txBytesPtr: UnsafeMutablePointer? var txLen: size_t = 0 - + // Convert outputs to FFI format let ffiOutputs = outputs.map { $0.toFFI() } - + let success = ffiOutputs.withUnsafeBufferPointer { outputsPtr in wallet_build_transaction( wallet.ffiHandle, - NetworkSet(wallet.network).ffiNetworks, accountIndex, outputsPtr.baseAddress, outputs.count, @@ -55,7 +54,7 @@ public class Transaction { &txLen, &error) } - + defer { if error.message != nil { error_message_free(error.message) @@ -64,17 +63,17 @@ public class Transaction { transaction_bytes_free(ptr) } } - + guard success, let ptr = txBytesPtr else { throw KeyWalletError(ffiError: error) } - + // Copy the transaction data before freeing let txData = Data(bytes: ptr, count: txLen) - + return txData } - + /// Sign a transaction /// - Parameters: /// - wallet: The wallet to sign with @@ -84,20 +83,19 @@ public class Transaction { guard !wallet.isWatchOnly else { throw KeyWalletError.invalidState("Cannot sign with watch-only wallet") } - + var error = FFIError() var signedTxPtr: UnsafeMutablePointer? var signedLen: size_t = 0 - + let success = transactionData.withUnsafeBytes { txBytes in let txPtr = txBytes.bindMemory(to: UInt8.self).baseAddress return wallet_sign_transaction( wallet.ffiHandle, - NetworkSet(wallet.network).ffiNetworks, txPtr, transactionData.count, &signedTxPtr, &signedLen, &error) } - + defer { if error.message != nil { error_message_free(error.message) @@ -106,17 +104,17 @@ public class Transaction { transaction_bytes_free(ptr) } } - + guard success, let ptr = signedTxPtr else { throw KeyWalletError(ffiError: error) } - + // Copy the signed transaction data before freeing let signedData = Data(bytes: ptr, count: signedLen) - + return signedData } - + /// Check if a transaction belongs to a wallet /// - Parameters: /// - wallet: The wallet to check against @@ -136,17 +134,16 @@ public class Transaction { updateState: Bool = true) throws -> TransactionCheckResult { var error = FFIError() var result = FFITransactionCheckResult() - + let success = transactionData.withUnsafeBytes { txBytes in let txPtr = txBytes.bindMemory(to: UInt8.self).baseAddress - + if let hash = blockHash { return hash.withUnsafeBytes { hashBytes in let hashPtr = hashBytes.bindMemory(to: UInt8.self).baseAddress - + return wallet_check_transaction( wallet.ffiHandle, - wallet.network.ffiValue, txPtr, transactionData.count, context.ffiValue, blockHeight, hashPtr, timestamp, updateState, &result, &error) @@ -154,51 +151,50 @@ public class Transaction { } else { return wallet_check_transaction( wallet.ffiHandle, - wallet.network.ffiValue, txPtr, transactionData.count, context.ffiValue, blockHeight, nil, timestamp, updateState, &result, &error) } } - + defer { if error.message != nil { error_message_free(error.message) } transaction_check_result_free(&result) } - + guard success else { throw KeyWalletError(ffiError: error) } - + return TransactionCheckResult(ffiResult: result) } - + /// Classify a transaction for routing /// - Parameter transactionData: The transaction bytes /// - Returns: A string describing the transaction type public static func classify(_ transactionData: Data) throws -> String { var error = FFIError() - + let classificationPtr = transactionData.withUnsafeBytes { txBytes in let txPtr = txBytes.bindMemory(to: UInt8.self).baseAddress return transaction_classify(txPtr, transactionData.count, &error) } - + defer { if error.message != nil { error_message_free(error.message) } } - + guard let ptr = classificationPtr else { throw KeyWalletError(ffiError: error) } - + let classification = String(cString: ptr) string_free(ptr) - + return classification } -} \ No newline at end of file +} diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift index b79500dbd09..e93c2c6fa05 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift @@ -6,14 +6,14 @@ public class Wallet { private let handle: UnsafeMutablePointer internal let network: KeyWalletNetwork private let ownsHandle: Bool - + // MARK: - Static Methods - + /// Initialize the key wallet library (call once at app startup) public static func initialize() -> Bool { return key_wallet_ffi_initialize() } - + /// Get library version public static var version: String { guard let versionPtr = key_wallet_ffi_version() else { @@ -21,36 +21,33 @@ public class Wallet { } return String(cString: versionPtr) } - + // MARK: - Initialization - + /// Create a wallet from a mnemonic phrase /// - Parameters: /// - mnemonic: The mnemonic phrase /// - passphrase: Optional BIP39 passphrase /// - network: The network type /// - accountOptions: Account creation options - public init(mnemonic: String, passphrase: String? = nil, + public init(mnemonic: String, passphrase: String? = nil, network: KeyWalletNetwork = .mainnet, accountOptions: AccountCreationOption = .default) throws { self.network = network - + var error = FFIError() let walletPtr: UnsafeMutablePointer? - + if case .specificAccounts = accountOptions { - // Use the with_options variant for specific accounts var options = accountOptions.toFFIOptions() - - // Note: For production, we'd need to properly manage the memory for the arrays - // This is a simplified version + walletPtr = mnemonic.withCString { mnemonicCStr in if let passphrase = passphrase { return passphrase.withCString { passphraseCStr in wallet_create_from_mnemonic_with_options( mnemonicCStr, passphraseCStr, - NetworkSet(network).ffiNetworks, + network.ffiValue, &options, &error ) @@ -59,21 +56,20 @@ public class Wallet { return wallet_create_from_mnemonic_with_options( mnemonicCStr, nil, - NetworkSet(network).ffiNetworks, + network.ffiValue, &options, &error ) } } } else { - // Use simpler variant for default options walletPtr = mnemonic.withCString { mnemonicCStr in if let passphrase = passphrase { return passphrase.withCString { passphraseCStr in wallet_create_from_mnemonic( mnemonicCStr, passphraseCStr, - NetworkSet(network).ffiNetworks, + network.ffiValue, &error ) } @@ -81,27 +77,27 @@ public class Wallet { return wallet_create_from_mnemonic( mnemonicCStr, nil, - NetworkSet(network).ffiNetworks, + network.ffiValue, &error ) } } } - + defer { if error.message != nil { error_message_free(error.message) } } - + guard let handle = walletPtr else { throw KeyWalletError(ffiError: error) } - + self.handle = handle self.ownsHandle = true } - + /// Create a wallet from seed bytes /// - Parameters: /// - seed: The seed bytes (typically 64 bytes) @@ -111,17 +107,17 @@ public class Wallet { accountOptions: AccountCreationOption = .default) throws { self.network = network self.ownsHandle = true - + var error = FFIError() let walletPtr: UnsafeMutablePointer? = seed.withUnsafeBytes { seedBytes in let seedPtr = seedBytes.bindMemory(to: UInt8.self).baseAddress - + if case .specificAccounts = accountOptions { var options = accountOptions.toFFIOptions() return wallet_create_from_seed_with_options( seedPtr, seed.count, - NetworkSet(network).ffiNetworks, + network.ffiValue, &options, &error ) @@ -129,49 +125,49 @@ public class Wallet { return wallet_create_from_seed( seedPtr, seed.count, - NetworkSet(network).ffiNetworks, + network.ffiValue, &error ) } } - + defer { if error.message != nil { error_message_free(error.message) } } - + guard let handle = walletPtr else { throw KeyWalletError(ffiError: error) } - + self.handle = handle } - + /// Create a watch-only wallet from extended public key /// - Parameters: /// - xpub: The extended public key string /// - network: The network type public init(xpub: String, network: KeyWalletNetwork = .mainnet) throws { self.network = network - + // Create an empty wallet first (no accounts) var error = FFIError() var options = AccountCreationOption.noAccounts.toFFIOptions() - + // Create a random wallet with no accounts - let walletPtr = wallet_create_random_with_options(NetworkSet(network).ffiNetworks, &options, &error) - + let walletPtr = wallet_create_random_with_options(network.ffiValue, &options, &error) + defer { if error.message != nil { error_message_free(error.message) } } - + guard let handle = walletPtr else { throw KeyWalletError(ffiError: error) } - + self.handle = handle self.ownsHandle = true @@ -184,7 +180,7 @@ public class Wallet { throw error } } - + /// Create a new random wallet /// - Parameters: /// - network: The network type @@ -193,108 +189,108 @@ public class Wallet { accountOptions: AccountCreationOption = .default) throws -> Wallet { var error = FFIError() let walletPtr: UnsafeMutablePointer? - + if case .specificAccounts = accountOptions { var options = accountOptions.toFFIOptions() - walletPtr = wallet_create_random_with_options(NetworkSet(network).ffiNetworks, &options, &error) + walletPtr = wallet_create_random_with_options(network.ffiValue, &options, &error) } else { - walletPtr = wallet_create_random(NetworkSet(network).ffiNetworks, &error) + walletPtr = wallet_create_random(network.ffiValue, &error) } - + defer { if error.message != nil { error_message_free(error.message) } } - + guard let ptr = walletPtr else { throw KeyWalletError(ffiError: error) } - + // Create a wrapper that takes ownership let wallet = Wallet(handle: ptr, network: network) return wallet } - + /// Private initializer for internal use (takes ownership) private init(handle: UnsafeMutablePointer, network: KeyWalletNetwork) { self.handle = handle self.network = network self.ownsHandle = true } - + // MARK: - Wallet Properties - + /// Get the wallet ID (32-byte hash) public var id: Data { get throws { var id = Data(count: 32) var error = FFIError() - + let success = id.withUnsafeMutableBytes { idBytes in let idPtr = idBytes.bindMemory(to: UInt8.self).baseAddress return wallet_get_id(handle, idPtr, &error) } - + defer { if error.message != nil { error_message_free(error.message) } } - + guard success else { throw KeyWalletError(ffiError: error) } - + return id } } - + /// Check if wallet has a mnemonic public var hasMnemonic: Bool { var error = FFIError() let result = wallet_has_mnemonic(handle, &error) - + defer { if error.message != nil { error_message_free(error.message) } } - + return result } - + /// Check if wallet is watch-only public var isWatchOnly: Bool { var error = FFIError() let result = wallet_is_watch_only(handle, &error) - + defer { if error.message != nil { error_message_free(error.message) } } - + return result } - + // MARK: - Account Management - + /// Get an account by type and index /// - Parameters: /// - type: The account type /// - index: The account index /// - Returns: An account handle public func getAccount(type: AccountType, index: UInt32 = 0) throws -> Account { - let result = wallet_get_account(handle, network.ffiValue, index, type.ffiValue) - + let result = wallet_get_account(handle, index, type.ffiValue) + defer { if result.error_message != nil { var mutableResult = result account_result_free_error(&mutableResult) } } - + guard let accountHandle = result.account else { var error = FFIError() error.code = FFIErrorCode(rawValue: UInt32(result.error_code)) @@ -303,24 +299,24 @@ public class Wallet { } throw KeyWalletError(ffiError: error) } - + return Account(handle: accountHandle, wallet: self) } - + /// Get an identity top-up account with a specific registration index /// - Parameter registrationIndex: The identity registration index /// - Returns: An account handle public func getTopUpAccount(registrationIndex: UInt32) throws -> Account { let result = wallet_get_top_up_account_with_registration_index( - handle, network.ffiValue, registrationIndex) - + handle, registrationIndex) + defer { if result.error_message != nil { var mutableResult = result account_result_free_error(&mutableResult) } } - + guard let accountHandle = result.account else { var error = FFIError() error.code = FFIErrorCode(rawValue: UInt32(result.error_code)) @@ -329,10 +325,10 @@ public class Wallet { } throw KeyWalletError(ffiError: error) } - + return Account(handle: accountHandle, wallet: self) } - + /// Add an account to the wallet /// - Parameters: /// - type: The account type @@ -341,24 +337,24 @@ public class Wallet { /// - Returns: The newly added account public func addAccount(type: AccountType, index: UInt32, xpub: String? = nil) throws -> Account { let result: FFIAccountResult - + if let xpub = xpub { result = xpub.withCString { xpubCStr in wallet_add_account_with_string_xpub( - handle, network.ffiValue, type.ffiValue, index, xpubCStr) + handle, type.ffiValue, index, xpubCStr) } } else { result = wallet_add_account( - handle, network.ffiValue, type.ffiValue, index) + handle, type.ffiValue, index) } - + defer { if result.error_message != nil { var mutableResult = result account_result_free_error(&mutableResult) } } - + guard let accountHandle = result.account else { var error = FFIError() error.code = FFIErrorCode(rawValue: UInt32(result.error_code)) @@ -367,32 +363,32 @@ public class Wallet { } throw KeyWalletError(ffiError: error) } - + return Account(handle: accountHandle, wallet: self) } - + /// Get the number of accounts in the wallet public var accountCount: UInt32 { var error = FFIError() - let count = wallet_get_account_count(handle, network.ffiValue, &error) - + let count = wallet_get_account_count(handle, &error) + defer { if error.message != nil { error_message_free(error.message) } } - + return count } - + // MARK: - Balance - + /// Get the wallet's total balance public func getBalance() throws -> Balance { // TODO: wallet_get_balance function no longer exists in FFI throw KeyWalletError.notSupported("wallet_get_balance is not available in current FFI") } - + /// Get balance for a specific account /// - Parameter accountIndex: The account index /// - Returns: The account balance @@ -400,32 +396,32 @@ public class Wallet { // TODO: wallet_get_account_balance function no longer exists in FFI throw KeyWalletError.notSupported("wallet_get_account_balance is not available in current FFI") } - + // MARK: - Key Derivation - + /// Get the extended public key for an account /// - Parameter accountIndex: The account index /// - Returns: The extended public key string public func getAccountXpub(accountIndex: UInt32) throws -> String { var error = FFIError() - let xpubPtr = wallet_get_account_xpub(handle, network.ffiValue, accountIndex, &error) - + let xpubPtr = wallet_get_account_xpub(handle, accountIndex, &error) + defer { if error.message != nil { error_message_free(error.message) } } - + guard let ptr = xpubPtr else { throw KeyWalletError(ffiError: error) } - + let xpub = String(cString: ptr) string_free(ptr) - + return xpub } - + /// Get the extended private key for an account (only for non-watch-only wallets) /// - Parameter accountIndex: The account index /// - Returns: The extended private key string @@ -433,26 +429,26 @@ public class Wallet { guard !isWatchOnly else { throw KeyWalletError.invalidState("Cannot get private key from watch-only wallet") } - + var error = FFIError() - let xprivPtr = wallet_get_account_xpriv(handle, network.ffiValue, accountIndex, &error) - + let xprivPtr = wallet_get_account_xpriv(handle, accountIndex, &error) + defer { if error.message != nil { error_message_free(error.message) } } - + guard let ptr = xprivPtr else { throw KeyWalletError(ffiError: error) } - + let xpriv = String(cString: ptr) string_free(ptr) - + return xpriv } - + /// Derive a private key at a specific path /// - Parameter derivationPath: The BIP32 derivation path /// - Returns: The private key in WIF format @@ -460,66 +456,61 @@ public class Wallet { guard !isWatchOnly else { throw KeyWalletError.invalidState("Cannot derive private key from watch-only wallet") } - + var error = FFIError() let wifPtr = path.withCString { pathCStr in - wallet_derive_private_key_as_wif(handle, network.ffiValue, pathCStr, &error) + wallet_derive_private_key_as_wif(handle, pathCStr, &error) } - + defer { if error.message != nil { error_message_free(error.message) } } - + guard let ptr = wifPtr else { throw KeyWalletError(ffiError: error) } - + let wif = String(cString: ptr) string_free(ptr) - + return wif } - + /// Derive a public key at a specific path /// - Parameter derivationPath: The BIP32 derivation path /// - Returns: The public key as hex string public func derivePublicKey(path: String) throws -> String { var error = FFIError() let hexPtr = path.withCString { pathCStr in - wallet_derive_public_key_as_hex(handle, network.ffiValue, pathCStr, &error) + wallet_derive_public_key_as_hex(handle, pathCStr, &error) } - + defer { if error.message != nil { error_message_free(error.message) } } - + guard let ptr = hexPtr else { throw KeyWalletError(ffiError: error) } - + let hex = String(cString: ptr) string_free(ptr) - + return hex } - - // MARK: - Internal - - /// Get the raw FFI handle (for internal use) + // MARK: - Account Collection - + /// Get a collection of all accounts in this wallet - /// - Parameter network: The network type /// - Returns: The account collection - public func getAccountCollection(network: KeyWalletNetwork? = nil) throws -> AccountCollection { - let targetNetwork = network ?? self.network + public func getAccountCollection() throws -> AccountCollection { var error = FFIError() - - guard let collectionHandle = wallet_get_account_collection(handle, targetNetwork.ffiValue, &error) else { + + guard let collectionHandle = wallet_get_account_collection(handle, &error) else { defer { if error.message != nil { error_message_free(error.message) @@ -527,10 +518,10 @@ public class Wallet { } throw KeyWalletError(ffiError: error) } - + return AccountCollection(handle: collectionHandle, wallet: self) } - + internal var ffiHandle: UnsafeMutablePointer { handle } // Non-owning initializer for wallets obtained from WalletManager diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift index 34aa3b1a367..11e590dd2eb 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift @@ -5,12 +5,13 @@ import DashSDKFFI public class WalletManager { private let handle: UnsafeMutablePointer private let ownsHandle: Bool - + /// Create a new standalone wallet manager + /// - Parameter network: The network type (the manager is tied to a single network) /// Note: Consider using init(fromSPVClient:) instead if you have an SPV client - public init() throws { + public init(network: KeyWalletNetwork = .mainnet) throws { var error = FFIError() - guard let managerHandle = wallet_manager_create(&error) else { + guard let managerHandle = wallet_manager_create(network.ffiValue, &error) else { defer { if error.message != nil { error_message_free(error.message) @@ -18,42 +19,42 @@ public class WalletManager { } throw KeyWalletError(ffiError: error) } - + self.handle = managerHandle self.ownsHandle = true } - + /// Create a wallet manager from an SPV client /// - Parameter spvClient: The FFI SPV client handle to get the wallet manager from public init(fromSPVClient spvClient: UnsafeMutablePointer) throws { guard let managerHandle = dash_spv_ffi_client_get_wallet_manager(spvClient) else { throw KeyWalletError.walletError("Failed to get wallet manager from SPV client") } - + self.handle = managerHandle self.ownsHandle = true } - + /// Create a wallet manager wrapper from an existing handle (does not own the handle) /// - Parameter handle: The FFI wallet manager handle internal init(handle: UnsafeMutablePointer) { self.handle = handle self.ownsHandle = false } - + deinit { if ownsHandle { dash_spv_ffi_wallet_manager_free(handle) } } - + // MARK: - Wallet Management - + /// Add a wallet from mnemonic /// - Parameters: /// - mnemonic: The mnemonic phrase /// - passphrase: Optional BIP39 passphrase - /// - network: The network type + /// - network: The network type (ignored; manager network is used) /// - accountOptions: Account creation options /// - Returns: The wallet ID @discardableResult @@ -61,116 +62,76 @@ public class WalletManager { network: KeyWalletNetwork = .mainnet, accountOptions: AccountCreationOption = .default) throws -> Data { var error = FFIError() - + let success = mnemonic.withCString { mnemonicCStr in if case .specificAccounts = accountOptions { var options = accountOptions.toFFIOptions() - + if let passphrase = passphrase { return passphrase.withCString { passphraseCStr in wallet_manager_add_wallet_from_mnemonic_with_options( handle, mnemonicCStr, passphraseCStr, - NetworkSet(network).ffiNetworks, &options, &error) + &options, &error) } } else { return wallet_manager_add_wallet_from_mnemonic_with_options( handle, mnemonicCStr, nil, - NetworkSet(network).ffiNetworks, &options, &error) + &options, &error) } } else { if let passphrase = passphrase { return passphrase.withCString { passphraseCStr in wallet_manager_add_wallet_from_mnemonic( handle, mnemonicCStr, passphraseCStr, - NetworkSet(network).ffiNetworks, &error) + &error) } } else { return wallet_manager_add_wallet_from_mnemonic( handle, mnemonicCStr, nil, - NetworkSet(network).ffiNetworks, &error) - } + &error) + } } } - + defer { if error.message != nil { error_message_free(error.message) } } - + guard success else { throw KeyWalletError(ffiError: error) } - + // Get the wallet IDs to return the newly added wallet ID return try getWalletIds().last ?? Data() } - /// Add a wallet from mnemonic for multiple networks (bitfield) + /// Add a wallet from mnemonic for multiple networks /// - Parameters: /// - mnemonic: The mnemonic phrase /// - passphrase: Optional BIP39 passphrase - /// - networks: Networks to enable for this wallet + /// - networks: Networks to enable for this wallet (only the first is used; the FFI no longer supports multi-network) /// - accountOptions: Account creation options /// - Returns: The wallet ID @discardableResult public func addWallet(mnemonic: String, passphrase: String? = nil, networks: [KeyWalletNetwork], accountOptions: AccountCreationOption = .default) throws -> Data { - var error = FFIError() - let networkSet = NetworkSet(networks) - - let success = mnemonic.withCString { mnemonicCStr in - if case .specificAccounts = accountOptions { - var options = accountOptions.toFFIOptions() - if let passphrase = passphrase { - return passphrase.withCString { passphraseCStr in - wallet_manager_add_wallet_from_mnemonic_with_options( - handle, mnemonicCStr, passphraseCStr, - networkSet.ffiNetworks, &options, &error) - } - } else { - return wallet_manager_add_wallet_from_mnemonic_with_options( - handle, mnemonicCStr, nil, - networkSet.ffiNetworks, &options, &error) - } - } else { - if let passphrase = passphrase { - return passphrase.withCString { passphraseCStr in - wallet_manager_add_wallet_from_mnemonic( - handle, mnemonicCStr, passphraseCStr, - networkSet.ffiNetworks, &error) - } - } else { - return wallet_manager_add_wallet_from_mnemonic( - handle, mnemonicCStr, nil, - networkSet.ffiNetworks, &error) - } - } - } - - defer { - if error.message != nil { - error_message_free(error.message) - } - } - - guard success else { - throw KeyWalletError(ffiError: error) - } - - return try getWalletIds().last ?? Data() + let network = networks.first ?? .mainnet + return try addWallet(mnemonic: mnemonic, passphrase: passphrase, + network: network, accountOptions: accountOptions) } - + /// Get all wallet IDs /// - Returns: Array of wallet IDs (32-byte Data objects) public func getWalletIds() throws -> [Data] { var error = FFIError() var walletIdsPtr: UnsafeMutablePointer? var count: size_t = 0 - + let success = wallet_manager_get_wallet_ids(handle, &walletIdsPtr, &count, &error) - + defer { if error.message != nil { error_message_free(error.message) @@ -179,21 +140,21 @@ public class WalletManager { wallet_manager_free_wallet_ids(ptr, count) } } - + guard success, let ptr = walletIdsPtr else { throw KeyWalletError(ffiError: error) } - + var walletIds: [Data] = [] for i in 0.. Bool { var error = FFIError() var ffiContext = contextDetails.toFFI() - + let success = transactionData.withUnsafeBytes { txBytes in let txPtr = txBytes.bindMemory(to: UInt8.self).baseAddress return wallet_manager_process_transaction( handle, txPtr, transactionData.count, - network.ffiValue, &ffiContext, + &ffiContext, updateStateIfFound, &error) } - + defer { if error.message != nil { error_message_free(error.message) } } - + guard success else { throw KeyWalletError(ffiError: error) } - + return success } - + // MARK: - Block Height Management - - /// Update the current block height for a network - /// - Parameters: - /// - height: The new block height - /// - network: The network type - public func updateHeight(_ height: UInt32, network: KeyWalletNetwork = .mainnet) throws { - var error = FFIError() - - let success = wallet_manager_update_height(handle, network.ffiValue, height, &error) - - defer { - if error.message != nil { - error_message_free(error.message) - } - } - - guard success else { - throw KeyWalletError(ffiError: error) - } - } - - /// Get the current block height for a network - /// - Parameter network: The network type + + /// Get the current block height /// - Returns: The current block height - public func currentHeight(network: KeyWalletNetwork = .mainnet) throws -> UInt32 { + public func currentHeight() throws -> UInt32 { var error = FFIError() - - let height = wallet_manager_current_height(handle, network.ffiValue, &error) - + + let height = wallet_manager_current_height(handle, &error) + defer { if error.message != nil { error_message_free(error.message) } } - + // Check if there was an error if error.code != FFIErrorCode(rawValue: 0) { throw KeyWalletError(ffiError: error) } - + return height } - + // MARK: - Managed Accounts - + /// Get a managed account from a wallet /// - Parameters: /// - walletId: The wallet ID - /// - network: The network type + /// - network: The network type (ignored; manager network is used) /// - accountIndex: The account index /// - accountType: The type of account to get /// - Returns: The managed account @@ -503,31 +443,31 @@ public class WalletManager { guard walletId.count == 32 else { throw KeyWalletError.invalidInput("Wallet ID must be exactly 32 bytes") } - + var result = walletId.withUnsafeBytes { idBytes in let idPtr = idBytes.bindMemory(to: UInt8.self).baseAddress - return managed_wallet_get_account(handle, idPtr, network.ffiValue, + return managed_wallet_get_account(handle, idPtr, accountIndex, accountType.ffiValue) } - + defer { if result.error_message != nil { managed_account_result_free_error(&result) } } - + guard let accountHandle = result.account else { let errorMessage = result.error_message != nil ? String(cString: result.error_message!) : "Unknown error" throw KeyWalletError.walletError(errorMessage) } - + return ManagedAccount(handle: accountHandle, manager: self) } - + /// Get a managed top-up account with a specific registration index /// - Parameters: /// - walletId: The wallet ID - /// - network: The network type + /// - network: The network type (ignored; manager network is used) /// - registrationIndex: The registration index /// - Returns: The managed account public func getManagedTopUpAccount(walletId: Data, network: KeyWalletNetwork = .mainnet, @@ -535,66 +475,66 @@ public class WalletManager { guard walletId.count == 32 else { throw KeyWalletError.invalidInput("Wallet ID must be exactly 32 bytes") } - + var result = walletId.withUnsafeBytes { idBytes in let idPtr = idBytes.bindMemory(to: UInt8.self).baseAddress return managed_wallet_get_top_up_account_with_registration_index( - handle, idPtr, network.ffiValue, registrationIndex) + handle, idPtr, registrationIndex) } - + defer { if result.error_message != nil { managed_account_result_free_error(&result) } } - + guard let accountHandle = result.account else { let errorMessage = result.error_message != nil ? String(cString: result.error_message!) : "Unknown error" throw KeyWalletError.walletError(errorMessage) } - + return ManagedAccount(handle: accountHandle, manager: self) } - + /// Get a collection of all managed accounts for a wallet /// - Parameters: /// - walletId: The wallet ID - /// - network: The network type + /// - network: The network type (ignored; manager network is used) /// - Returns: The managed account collection public func getManagedAccountCollection(walletId: Data, network: KeyWalletNetwork = .mainnet) throws -> ManagedAccountCollection { guard walletId.count == 32 else { throw KeyWalletError.invalidInput("Wallet ID must be exactly 32 bytes") } - + var error = FFIError() - + let collectionHandle = walletId.withUnsafeBytes { idBytes in let idPtr = idBytes.bindMemory(to: UInt8.self).baseAddress - return managed_wallet_get_account_collection(handle, idPtr, network.ffiValue, &error) + return managed_wallet_get_account_collection(handle, idPtr, &error) } - + defer { if error.message != nil { error_message_free(error.message) } } - + guard let collection = collectionHandle else { throw KeyWalletError(ffiError: error) } - + return ManagedAccountCollection(handle: collection, manager: self) } - + internal var ffiHandle: UnsafeMutablePointer { handle } - + // MARK: - Serialization - + /// Add a wallet from mnemonic and return serialized wallet bytes /// - Parameters: /// - mnemonic: The mnemonic phrase /// - passphrase: Optional BIP39 passphrase - /// - network: The network type + /// - network: The network type (ignored; manager network is used) /// - birthHeight: Optional birth height for wallet /// - accountOptions: Account creation options /// - downgradeToPublicKeyWallet: If true, creates a watch-only or externally signable wallet @@ -613,17 +553,16 @@ public class WalletManager { var walletBytesPtr: UnsafeMutablePointer? var walletBytesLen: size_t = 0 var walletId = [UInt8](repeating: 0, count: 32) - + let success = mnemonic.withCString { mnemonicCStr in var options = accountOptions.toFFIOptions() - + if let passphrase = passphrase { return passphrase.withCString { passphraseCStr in wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( handle, mnemonicCStr, passphraseCStr, - NetworkSet(network).ffiNetworks, birthHeight, &options, downgradeToPublicKeyWallet, @@ -639,7 +578,6 @@ public class WalletManager { handle, mnemonicCStr, nil, - NetworkSet(network).ffiNetworks, birthHeight, &options, downgradeToPublicKeyWallet, @@ -651,7 +589,7 @@ public class WalletManager { ) } } - + defer { if error.message != nil { error_message_free(error.message) @@ -661,15 +599,15 @@ public class WalletManager { wallet_manager_free_wallet_bytes(ptr, walletBytesLen) } } - + guard success, let bytesPtr = walletBytesPtr else { throw KeyWalletError(ffiError: error) } - + // Copy the data before freeing (which happens in defer) let serializedData = Data(bytes: bytesPtr, count: Int(walletBytesLen)) let walletIdData = Data(walletId) - + return (walletId: walletIdData, serializedWallet: serializedData) } @@ -677,7 +615,7 @@ public class WalletManager { /// - Parameters: /// - mnemonic: The mnemonic phrase /// - passphrase: Optional BIP39 passphrase - /// - networks: Networks to enable for this wallet + /// - networks: Networks (only the first is used; the FFI no longer supports multi-network) /// - birthHeight: Optional birth height for wallet /// - accountOptions: Account creation options /// - downgradeToPublicKeyWallet: If true, creates a watch-only or externally signable wallet @@ -692,70 +630,18 @@ public class WalletManager { downgradeToPublicKeyWallet: Bool = false, allowExternalSigning: Bool = false ) throws -> (walletId: Data, serializedWallet: Data) { - var error = FFIError() - var walletBytesPtr: UnsafeMutablePointer? - var walletBytesLen: size_t = 0 - var walletId = [UInt8](repeating: 0, count: 32) - - let networkSet = NetworkSet(networks) - - let success = mnemonic.withCString { mnemonicCStr in - var options = accountOptions.toFFIOptions() - - if let passphrase = passphrase { - return passphrase.withCString { passphraseCStr in - wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( - handle, - mnemonicCStr, - passphraseCStr, - networkSet.ffiNetworks, - birthHeight, - &options, - downgradeToPublicKeyWallet, - allowExternalSigning, - &walletBytesPtr, - &walletBytesLen, - &walletId, - &error - ) - } - } else { - return wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( - handle, - mnemonicCStr, - nil, - networkSet.ffiNetworks, - birthHeight, - &options, - downgradeToPublicKeyWallet, - allowExternalSigning, - &walletBytesPtr, - &walletBytesLen, - &walletId, - &error - ) - } - } - - defer { - if error.message != nil { - error_message_free(error.message) - } - if let ptr = walletBytesPtr { - wallet_manager_free_wallet_bytes(ptr, walletBytesLen) - } - } - - guard success, let bytesPtr = walletBytesPtr else { - throw KeyWalletError(ffiError: error) - } - - let serializedData = Data(bytes: bytesPtr, count: Int(walletBytesLen)) - let walletIdData = Data(walletId) - - return (walletId: walletIdData, serializedWallet: serializedData) + let network = networks.first ?? .mainnet + return try addWalletAndSerialize( + mnemonic: mnemonic, + passphrase: passphrase, + network: network, + birthHeight: birthHeight, + accountOptions: accountOptions, + downgradeToPublicKeyWallet: downgradeToPublicKeyWallet, + allowExternalSigning: allowExternalSigning + ) } - + /// Import a wallet from serialized bytes /// - Parameters: /// - walletBytes: The serialized wallet data @@ -764,10 +650,10 @@ public class WalletManager { guard !walletBytes.isEmpty else { throw KeyWalletError.invalidInput("Wallet bytes cannot be empty") } - + var error = FFIError() var walletId = [UInt8](repeating: 0, count: 32) - + let success = walletBytes.withUnsafeBytes { bytes in wallet_manager_import_wallet_from_bytes( handle, @@ -777,17 +663,17 @@ public class WalletManager { &error ) } - + defer { if error.message != nil { error_message_free(error.message) } } - + guard success else { throw KeyWalletError(ffiError: error) } - + return Data(walletId) } } From 96b3af6fbb10e117ac205fe3d0e3eb4ed6f5f913 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 19 Feb 2026 09:50:20 +0100 Subject: [PATCH 07/19] fix(swift-sdk): update SPVClient for new dash_spv_ffi_init_logging signature - dash_spv_ffi_init_logging now takes 4 params (level, enable_console, log_dir, max_files) instead of 1 - dash_spv_ffi_client_clear_sync_state was removed; clearSyncState() now delegates to clearStorage() Co-Authored-By: Claude Opus 4.6 --- .../Sources/SwiftDashSDK/SPV/SPVClient.swift | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/SPV/SPVClient.swift b/packages/swift-sdk/Sources/SwiftDashSDK/SPV/SPVClient.swift index 8e20b232758..2afb45cc0cc 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/SPV/SPVClient.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/SPV/SPVClient.swift @@ -19,7 +19,7 @@ extension SPVClient { @MainActor public static func initializeLogging(_ level: SPVLogLevel) { level.rawValue.withCString { cstr in - _ = dash_spv_ffi_init_logging(cstr) + _ = dash_spv_ffi_init_logging(cstr, true, nil, 0) } LogInitState.manualInitialized = true } @@ -283,7 +283,7 @@ public class SPVClient: ObservableObject { if !LogInitState.manualInitialized { let level = (ProcessInfo.processInfo.environment["SPV_LOG"] ?? "off") _ = level.withCString { cstr in - dash_spv_ffi_init_logging(cstr) + dash_spv_ffi_init_logging(cstr, true, nil, 0) } } if swiftLoggingEnabled { @@ -487,21 +487,9 @@ public class SPVClient: ObservableObject { } /// Clear only the persisted sync-state snapshot while keeping headers/filters. + /// Note: Uses clearStorage() as the granular clear_sync_state FFI was removed. public func clearSyncState() throws { - guard let client = client else { throw SPVError.notInitialized } - - let rc = dash_spv_ffi_client_clear_sync_state(client) - if rc != 0 { - if let errorMsg = dash_spv_ffi_get_last_error() { - let message = String(cString: errorMsg) - throw SPVError.storageOperationFailed(message) - } else { - throw SPVError.storageOperationFailed("Failed to clear sync state (code \(rc))") - } - } - - self.syncProgress = nil - self.lastError = nil + try clearStorage() } private func destroyClient() { From c426f6533e3d1171878700d233d0407de4922e77 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 19 Feb 2026 10:50:36 +0100 Subject: [PATCH 08/19] chore(swift-sdk): upgrade cbindgen from 0.27 to 0.29.2 Align rs-sdk-ffi with the same cbindgen version already used by rust-dashcore dependencies, removing the duplicate 0.27.0 entry from Cargo.lock. Regenerated C headers with cbindgen 0.29.2. Co-Authored-By: Claude Opus 4.6 --- Cargo.lock | 61 +- packages/rs-sdk-ffi/Cargo.toml | 2 +- packages/rs-sdk-ffi/include/dash_sdk_ffi.h | 1962 ++++++++++++----- packages/rs-sdk-ffi/test_header.h | 1871 ++++++++++++++-- .../Sources/SwiftDashSDKMock/SwiftDashSDK.h | 2 +- 5 files changed, 3077 insertions(+), 821 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index caf4aa42fe8..44d3b3ea12b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -110,7 +110,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -121,7 +121,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -775,25 +775,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" -[[package]] -name = "cbindgen" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb" -dependencies = [ - "clap", - "heck 0.4.1", - "indexmap 2.12.1", - "log", - "proc-macro2", - "quote", - "serde", - "serde_json", - "syn 2.0.111", - "tempfile", - "toml 0.8.23", -] - [[package]] name = "cbindgen" version = "0.29.2" @@ -801,7 +782,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "befbfd072a8e81c02f8c507aefce431fe5e7d051f83d48a23ffc9b9fe5a11799" dependencies = [ "clap", - "heck 0.5.0", + "heck", "indexmap 2.12.1", "log", "proc-macro2", @@ -965,7 +946,7 @@ version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.111", @@ -1409,7 +1390,7 @@ dependencies = [ name = "dash-platform-macros" version = "3.1.0-dev.1" dependencies = [ - "heck 0.5.0", + "heck", "quote", "syn 2.0.111", ] @@ -1492,7 +1473,7 @@ name = "dash-spv-ffi" version = "0.41.0" source = "git+https://github.com/dashpay/rust-dashcore?rev=53d699c9b551ac7d3644e11ca46dc3819277ff87#53d699c9b551ac7d3644e11ca46dc3819277ff87" dependencies = [ - "cbindgen 0.29.2", + "cbindgen", "clap", "dash-spv", "dashcore", @@ -2034,7 +2015,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.111", @@ -2118,7 +2099,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -2711,12 +2692,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -3226,7 +3201,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -3426,7 +3401,7 @@ name = "key-wallet-ffi" version = "0.41.0" source = "git+https://github.com/dashpay/rust-dashcore?rev=53d699c9b551ac7d3644e11ca46dc3819277ff87#53d699c9b551ac7d3644e11ca46dc3819277ff87" dependencies = [ - "cbindgen 0.29.2", + "cbindgen", "dash-network", "dashcore", "hex", @@ -3866,7 +3841,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -4524,7 +4499,7 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac6c3320f9abac597dcbc668774ef006702672474aad53c6d596b62e487b40b1" dependencies = [ - "heck 0.5.0", + "heck", "itertools 0.14.0", "log", "multimap", @@ -5184,7 +5159,7 @@ version = "3.1.0-dev.1" dependencies = [ "bincode", "bs58", - "cbindgen 0.27.0", + "cbindgen", "dash-sdk", "dash-spv-ffi", "dotenvy", @@ -5317,7 +5292,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -6014,7 +5989,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "rustversion", @@ -6027,7 +6002,7 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.111", @@ -6133,7 +6108,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix 1.1.3", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -7442,7 +7417,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.48.0", ] [[package]] diff --git a/packages/rs-sdk-ffi/Cargo.toml b/packages/rs-sdk-ffi/Cargo.toml index cb40a563c48..586ea29f541 100644 --- a/packages/rs-sdk-ffi/Cargo.toml +++ b/packages/rs-sdk-ffi/Cargo.toml @@ -56,7 +56,7 @@ once_cell = "1.20" reqwest = { version = "0.12", features = ["json", "rustls-tls-native-roots"] } [build-dependencies] -cbindgen = "0.27" +cbindgen = "0.29.2" [profile.release] lto = "fat" # Enable cross-crate optimization diff --git a/packages/rs-sdk-ffi/include/dash_sdk_ffi.h b/packages/rs-sdk-ffi/include/dash_sdk_ffi.h index cdf0856fa80..44bb71e89e4 100644 --- a/packages/rs-sdk-ffi/include/dash_sdk_ffi.h +++ b/packages/rs-sdk-ffi/include/dash_sdk_ffi.h @@ -3,7 +3,7 @@ #pragma once -/* Generated with cbindgen:0.29.0 */ +/* Generated with cbindgen:0.29.2 */ /* This file is auto-generated. Do not modify manually. */ @@ -15,19 +15,25 @@ #include #include "dash_spv_ffi.h" -// Authorized action takers for token operations -typedef enum DashSDKAuthorizedActionTakers { - // No one can perform the action - DashSDKAuthorizedActionTakers_NoOne = 0, - // Only the contract owner can perform the action - DashSDKAuthorizedActionTakers_AuthorizedContractOwner = 1, - // Main group can perform the action - DashSDKAuthorizedActionTakers_MainGroup = 2, - // A specific identity (requires identity_id to be set) - DashSDKAuthorizedActionTakers_Identity = 3, - // A specific group (requires group_position to be set) - DashSDKAuthorizedActionTakers_Group = 4, -} DashSDKAuthorizedActionTakers; +// Result data type indicator for iOS +typedef enum DashSDKResultDataType { + // No data (void/null) + DashSDKResultDataType_NoData = 0, + // C string (char*) + DashSDKResultDataType_String = 1, + // Binary data with length + DashSDKResultDataType_BinaryData = 2, + // Identity handle + DashSDKResultDataType_ResultIdentityHandle = 3, + // Document handle + DashSDKResultDataType_ResultDocumentHandle = 4, + // Data contract handle + DashSDKResultDataType_ResultDataContractHandle = 5, + // Map of identity IDs to balances + DashSDKResultDataType_IdentityBalanceMap = 6, + // Public key handle + DashSDKResultDataType_ResultPublicKeyHandle = 7, +} DashSDKResultDataType; // Error codes returned by FFI functions typedef enum DashSDKErrorCode { @@ -65,6 +71,29 @@ typedef enum DashSDKGasFeesPaidBy { DashSDKGasFeesPaidBy_GasFeesPreferContractOwner = 2, } DashSDKGasFeesPaidBy; +// Document field value types +typedef enum DashSDKDocumentFieldType { + DashSDKDocumentFieldType_FieldString = 0, + DashSDKDocumentFieldType_FieldInteger = 1, + DashSDKDocumentFieldType_FieldFloat = 2, + DashSDKDocumentFieldType_FieldBoolean = 3, + DashSDKDocumentFieldType_FieldBytes = 4, + DashSDKDocumentFieldType_FieldArray = 5, + DashSDKDocumentFieldType_FieldObject = 6, + DashSDKDocumentFieldType_FieldNull = 7, +} DashSDKDocumentFieldType; + +// State transition type for key selection +typedef enum StateTransitionType { + StateTransitionType_IdentityUpdate = 0, + StateTransitionType_IdentityTopUp = 1, + StateTransitionType_IdentityCreditTransfer = 2, + StateTransitionType_IdentityCreditWithdrawal = 3, + StateTransitionType_DocumentsBatch = 4, + StateTransitionType_DataContractCreate = 5, + StateTransitionType_DataContractUpdate = 6, +} StateTransitionType; + // Network type for SDK configuration typedef enum DashSDKNetwork { // Mainnet @@ -79,25 +108,13 @@ typedef enum DashSDKNetwork { DashSDKNetwork_SDKLocal = 4, } DashSDKNetwork; -// Result data type indicator for iOS -typedef enum DashSDKResultDataType { - // No data (void/null) - DashSDKResultDataType_None = 0, - // C string (char*) - DashSDKResultDataType_String = 1, - // Binary data with length - DashSDKResultDataType_BinaryData = 2, - // Identity handle - DashSDKResultDataType_ResultIdentityHandle = 3, - // Document handle - DashSDKResultDataType_ResultDocumentHandle = 4, - // Data contract handle - DashSDKResultDataType_ResultDataContractHandle = 5, - // Map of identity IDs to balances - DashSDKResultDataType_IdentityBalanceMap = 6, - // Public key handle - DashSDKResultDataType_ResultPublicKeyHandle = 7, -} DashSDKResultDataType; +// Token distribution type for claim operations +typedef enum DashSDKTokenDistributionType { + // Pre-programmed distribution + DashSDKTokenDistributionType_PreProgrammed = 0, + // Perpetual distribution + DashSDKTokenDistributionType_Perpetual = 1, +} DashSDKTokenDistributionType; // Token configuration update type typedef enum DashSDKTokenConfigUpdateType { @@ -121,13 +138,19 @@ typedef enum DashSDKTokenConfigUpdateType { DashSDKTokenConfigUpdateType_MainControlGroup = 8, } DashSDKTokenConfigUpdateType; -// Token distribution type for claim operations -typedef enum DashSDKTokenDistributionType { - // Pre-programmed distribution - DashSDKTokenDistributionType_PreProgrammed = 0, - // Perpetual distribution - DashSDKTokenDistributionType_Perpetual = 1, -} DashSDKTokenDistributionType; +// Authorized action takers for token operations +typedef enum DashSDKAuthorizedActionTakers { + // No one can perform the action + DashSDKAuthorizedActionTakers_NoOne = 0, + // Only the contract owner can perform the action + DashSDKAuthorizedActionTakers_AuthorizedContractOwner = 1, + // Main group can perform the action + DashSDKAuthorizedActionTakers_MainGroup = 2, + // A specific identity (requires identity_id to be set) + DashSDKAuthorizedActionTakers_Identity = 3, + // A specific group (requires group_position to be set) + DashSDKAuthorizedActionTakers_Group = 4, +} DashSDKAuthorizedActionTakers; // Token emergency action type typedef enum DashSDKTokenEmergencyAction { @@ -145,43 +168,12 @@ typedef enum DashSDKTokenPricingType { DashSDKTokenPricingType_SetPrices = 1, } DashSDKTokenPricingType; -// FFI-compatible network enum for key wallet operations -typedef enum FFIKeyNetwork { - FFIKeyNetwork_KeyMainnet = 0, - FFIKeyNetwork_KeyTestnet = 1, - FFIKeyNetwork_KeyRegtest = 2, - FFIKeyNetwork_KeyDevnet = 3, -} FFIKeyNetwork; - -// State transition type for key selection -typedef enum StateTransitionType { - StateTransitionType_IdentityUpdate = 0, - StateTransitionType_IdentityTopUp = 1, - StateTransitionType_IdentityCreditTransfer = 2, - StateTransitionType_IdentityCreditWithdrawal = 3, - StateTransitionType_DocumentsBatch = 4, - StateTransitionType_DataContractCreate = 5, - StateTransitionType_DataContractUpdate = 6, -} StateTransitionType; - // Opaque handle to a DataContract typedef struct DataContractHandle DataContractHandle; // Opaque handle to a Document typedef struct DocumentHandle DocumentHandle; -// Opaque handle for an extended private key -typedef struct FFIExtendedPrivKey FFIExtendedPrivKey; - -// Opaque handle for an extended public key -typedef struct FFIExtendedPubKey FFIExtendedPubKey; - -// Opaque handle for a BIP39 mnemonic -typedef struct FFIMnemonic FFIMnemonic; - -// Opaque handle for a transaction -typedef struct FFITransaction FFITransaction; - // Opaque handle to an Identity typedef struct IdentityHandle IdentityHandle; @@ -194,6 +186,170 @@ typedef struct dash_sdk_handle_t dash_sdk_handle_t; // Opaque handle to a Signer typedef struct SignerHandle SignerHandle; +// A found address with its balance (FFI-compatible) +typedef struct DashSDKFoundAddress { + // The derivation index for this address + uint32_t index; + // Pointer to the address key bytes + uint8_t *key; + // Length of the key in bytes + uintptr_t key_len; + // Nonce associated with this address + uint32_t nonce; + // Balance in credits at this address + uint64_t balance; +} DashSDKFoundAddress; + +// An address proven absent from the tree (FFI-compatible) +typedef struct DashSDKAbsentAddress { + // The derivation index for this address + uint32_t index; + // Pointer to the address key bytes + uint8_t *key; + // Length of the key in bytes + uintptr_t key_len; +} DashSDKAbsentAddress; + +// Metrics about the synchronization process (FFI-compatible) +typedef struct DashSDKAddressSyncMetrics { + // Number of trunk queries (always 1 for a successful sync) + uint32_t trunk_queries; + // Number of branch queries + uint32_t branch_queries; + // Total elements seen across all proofs. + // + // This gives an indication of the "anonymity set" - how many addresses + // were potentially being queried from the server's perspective. + uint32_t total_elements_seen; + // Total proof bytes received + uint32_t total_proof_bytes; + // Number of iterations (0 = trunk only, 1+ = trunk plus branch rounds) + uint32_t iterations; +} DashSDKAddressSyncMetrics; + +// Result of address synchronization (FFI-compatible) +typedef struct DashSDKAddressSyncResult { + // Array of found addresses with balances + struct DashSDKFoundAddress *found; + // Number of found addresses + uintptr_t found_count; + // Array of addresses proven absent + struct DashSDKAbsentAddress *absent; + // Number of absent addresses + uintptr_t absent_count; + // Highest found index (for HD wallets) + // Only valid if has_highest_found_index is true + uint32_t highest_found_index; + // Whether highest_found_index is valid + bool has_highest_found_index; + // Metrics about the sync process + struct DashSDKAddressSyncMetrics metrics; +} DashSDKAddressSyncResult; + +// Function pointer type for getting the gap limit +typedef uint32_t (*GetGapLimitFn)(void *context); + +// A pending address entry for the provider callback +typedef struct DashSDKPendingAddress { + // The derivation index for this address + uint32_t index; + // Pointer to the address key bytes (32 bytes) + const uint8_t *key; + // Length of the key in bytes + uintptr_t key_len; +} DashSDKPendingAddress; + +// List of pending addresses returned by the provider callback +typedef struct DashSDKPendingAddressList { + // Array of pending addresses + struct DashSDKPendingAddress *addresses; + // Number of addresses + uintptr_t count; +} DashSDKPendingAddressList; + +// Function pointer type for getting pending addresses +// +// Returns a list of pending addresses that need to be synchronized. +// The returned list must remain valid until the next call to this function +// or until the sync operation completes. +typedef struct DashSDKPendingAddressList (*GetPendingAddressesFn)(void *context); + +// Function pointer type for handling a found address +// +// Called when an address is found in the tree with a balance and nonce. +typedef void (*OnAddressFoundFn)(void *context, uint32_t index, const uint8_t *key, uintptr_t key_len, uint32_t nonce, uint64_t balance); + +// Function pointer type for handling an absent address +// +// Called when an address is proven absent from the tree. +typedef void (*OnAddressAbsentFn)(void *context, uint32_t index, const uint8_t *key, uintptr_t key_len); + +// Optional function pointer type for checking if there are pending addresses. +// Nullable — may be null (cbindgen translates this to a nullable C function pointer). +typedef bool (*OptionalHasPendingFn)(void *context); + +// Optional function pointer type for getting the highest found index. +// Nullable — may be null (cbindgen translates this to a nullable C function pointer). +typedef uint32_t (*OptionalGetHighestFoundIndexFn)(void *context); + +// Optional destructor for cleanup. +// Nullable — may be null (cbindgen translates this to a nullable C function pointer). +typedef void (*OptionalDestroyProviderFn)(void *context); + +// VTable for address provider callbacks +typedef struct AddressProviderVTable { + // Get the gap limit for this provider + GetGapLimitFn gap_limit; + // Get currently pending addresses to synchronize + GetPendingAddressesFn pending_addresses; + // Called when an address is found with a balance + OnAddressFoundFn on_address_found; + // Called when an address is proven absent + OnAddressAbsentFn on_address_absent; + // Check if there are still pending addresses. + // May be null; if null the default implementation (pending_addresses is non-empty) is used. + OptionalHasPendingFn has_pending; + // Get the highest found index. + // May be null; if null returns None. + OptionalGetHighestFoundIndexFn highest_found_index; + // Optional destructor for cleanup. May be null. + OptionalDestroyProviderFn destroy; +} AddressProviderVTable; + +// FFI-compatible address provider using callbacks +typedef struct AddressProviderFFI { + // Opaque context pointer passed to all callbacks + void *context; + // Pointer to the vtable containing callback functions + const struct AddressProviderVTable *vtable; +} AddressProviderFFI; + +// Configuration for address synchronization (FFI-compatible) +typedef struct DashSDKAddressSyncConfig { + // Minimum privacy count - subtrees smaller than this will be expanded + // to include ancestor subtrees for better privacy. + // + // Higher values provide better privacy but may increase the number of + // elements returned per query. + // + // Default: 32 + uint64_t min_privacy_count; + // Maximum concurrent branch queries. + // + // Higher values can speed up synchronization but increase memory usage + // and network load. + // + // Default: 10 + uint32_t max_concurrent_requests; + // Maximum number of iterations (safety limit). + // + // The sync process iterates until all addresses are resolved. This limit + // prevents infinite loops in case of unexpected behavior. + // + // Default: 50 + uint32_t max_iterations; +} DashSDKAddressSyncConfig; + // Error structure returned by FFI functions typedef struct DashSDKError { // Error code @@ -218,16 +374,6 @@ typedef struct ContextProviderHandle { uint8_t private_[0]; } ContextProviderHandle; -typedef struct FFIDashSpvClient { - uint8_t opaque[0]; -} FFIDashSpvClient; - -// Handle for Core SDK that can be passed to Platform SDK -// This matches the definition from dash_spv_ffi.h -typedef struct CoreSDKHandle { - struct FFIDashSpvClient *client; -} CoreSDKHandle; - // Result type for FFI callbacks typedef struct CallbackResult { bool success; @@ -251,18 +397,56 @@ typedef struct ContextProviderCallbacks { GetQuorumPublicKeyFn get_quorum_public_key; } ContextProviderCallbacks; +// Result structure for data contract fetch with serialization +typedef struct DashSDKDataContractFetchResult { + // Handle to the data contract (null on error or if not requested) + struct DataContractHandle *contract_handle; + // JSON representation of the contract (null on error or if not requested) + char *json_string; + // Serialized contract bytes (null on error or if not requested) + uint8_t *serialized_data; + // Length of serialized data + uintptr_t serialized_data_len; + // Error information (null on success) + struct DashSDKError *error; +} DashSDKDataContractFetchResult; + // Document creation parameters typedef struct DashSDKDocumentCreateParams { - // Data contract handle - const struct DataContractHandle *data_contract_handle; + // Data contract ID (base58 encoded) + const char *data_contract_id; // Document type name const char *document_type; - // Owner identity handle - const struct IdentityHandle *owner_identity_handle; + // Owner identity ID (base58 encoded) + const char *owner_identity_id; // JSON string of document properties const char *properties_json; } DashSDKDocumentCreateParams; +// Document creation result containing handle and entropy +typedef struct DashSDKDocumentCreateResult { + // Handle to the created document + struct DocumentHandle *document_handle; + // Entropy used for document ID generation (32 bytes) + uint8_t entropy[32]; +} DashSDKDocumentCreateResult; + +// Document handle creation parameters +typedef struct DashSDKDocumentHandleParams { + // Document ID (base58 encoded) + const char *id; + // Data contract ID (base58 encoded) + const char *data_contract_id; + // Document type name + const char *document_type; + // Owner identity ID (base58 encoded) + const char *owner_identity_id; + // JSON string of document properties + const char *properties_json; + // Optional revision number (0 means no revision) + uint64_t revision; +} DashSDKDocumentHandleParams; + // Token payment information for transactions typedef struct DashSDKTokenPaymentInfo { // Payment token contract ID (32 bytes), null for same contract @@ -313,6 +497,23 @@ typedef struct DashSDKStateTransitionCreationOptions { uint16_t base_feature_version; } DashSDKStateTransitionCreationOptions; +// Document field value +typedef struct DashSDKDocumentField { + // Field name (null-terminated) + char *name; + // Field type + enum DashSDKDocumentFieldType field_type; + // Field value as string representation (null-terminated) + // For complex types, this will be JSON-encoded + char *value; + // Raw integer value (for Integer type) + int64_t int_value; + // Raw float value (for Float type) + double float_value; + // Raw boolean value (for Boolean type) + bool bool_value; +} DashSDKDocumentField; + // Document information typedef struct DashSDKDocumentInfo { // Document ID as hex string (null-terminated) @@ -329,6 +530,10 @@ typedef struct DashSDKDocumentInfo { int64_t created_at; // Updated at timestamp (milliseconds since epoch) int64_t updated_at; + // Number of data fields + uintptr_t data_fields_count; + // Array of data fields + struct DashSDKDocumentField *data_fields; } DashSDKDocumentInfo; // Document search parameters @@ -347,6 +552,72 @@ typedef struct DashSDKDocumentSearchParams { uint32_t start_at; } DashSDKDocumentSearchParams; +// Represents a simple name to timestamp mapping +typedef struct DashSDKNameTimestamp { + // The name + char *name; + // End timestamp in milliseconds + uint64_t end_time; +} DashSDKNameTimestamp; + +// Represents a list of name-timestamp pairs +typedef struct DashSDKNameTimestampList { + // Array of name-timestamp pairs + struct DashSDKNameTimestamp *entries; + // Number of entries + uintptr_t count; +} DashSDKNameTimestampList; + +// Represents a contender in a contested DPNS name +typedef struct DashSDKContender { + // Identity ID of the contender (base58 string) + char *identity_id; + // Vote count for this contender + uint32_t vote_count; +} DashSDKContender; + +// Represents contest information for a DPNS name +typedef struct DashSDKContestInfo { + // Array of contenders + struct DashSDKContender *contenders; + // Number of contenders + uintptr_t contender_count; + // Abstain vote tally (0 if none) + uint32_t abstain_votes; + // Lock vote tally (0 if none) + uint32_t lock_votes; + // End time in milliseconds since epoch + uint64_t end_time; + // Whether there is a winner + bool has_winner; +} DashSDKContestInfo; + +// Represents a contested DPNS name entry +typedef struct DashSDKContestedName { + // The contested name + char *name; + // Contest information + struct DashSDKContestInfo contest_info; +} DashSDKContestedName; + +// Represents a list of contested names +typedef struct DashSDKContestedNamesList { + // Array of contested names + struct DashSDKContestedName *names; + // Number of names + uintptr_t count; +} DashSDKContestedNamesList; + +// Result structure for DPNS registration +typedef struct DpnsRegistrationResult { + // JSON representation of the preorder document + char *preorder_document_json; + // JSON representation of the domain document + char *domain_document_json; + // The full domain name (e.g., "alice.dash") + char *full_domain_name; +} DpnsRegistrationResult; + // Public key data for creating identity typedef struct DashSDKPublicKeyData { // Key ID (0-255) @@ -402,6 +673,12 @@ typedef struct DashSDKConfig { uint64_t request_timeout_ms; } DashSDKConfig; +// Handle for Core SDK that can be passed to Platform SDK +// This matches the definition from dash_spv_ffi.h +typedef struct CoreSDKHandle { + void *client; +} CoreSDKHandle; + // Extended SDK configuration with context provider support typedef struct DashSDKConfigExtended { // Base SDK configuration @@ -412,13 +689,17 @@ typedef struct DashSDKConfigExtended { struct CoreSDKHandle *core_sdk_handle; } DashSDKConfigExtended; -// Function pointer type for iOS signing callback +// Function pointer type for signing callback from iOS/external code // Returns pointer to allocated byte array (caller must free with dash_sdk_bytes_free) // Returns null on error -typedef uint8_t *(*IOSSignCallback)(const uint8_t *identity_public_key_bytes, uintptr_t identity_public_key_len, const uint8_t *data, uintptr_t data_len, uintptr_t *result_len); +typedef uint8_t *(*SignCallback)(const void *signer, const uint8_t *identity_public_key_bytes, uintptr_t identity_public_key_len, const uint8_t *data, uintptr_t data_len, uintptr_t *result_len); + +// Function pointer type for can_sign_with callback from iOS/external code +typedef bool (*CanSignCallback)(const void *signer, const uint8_t *identity_public_key_bytes, uintptr_t identity_public_key_len); -// Function pointer type for iOS can_sign_with callback -typedef bool (*IOSCanSignCallback)(const uint8_t *identity_public_key_bytes, uintptr_t identity_public_key_len); +// Function pointer type for destructor callback +// This is an Option to allow for NULL pointers from C +typedef void (*DestroyCallback)(void *signer); // Signature result structure typedef struct DashSDKSignature { @@ -618,30 +899,6 @@ typedef struct DashSDKTokenSetPriceParams { const char *public_note; } DashSDKTokenSetPriceParams; -// FFI-compatible transaction input -typedef struct FFITxIn { - // Transaction ID (32 bytes) - uint8_t txid[32]; - // Output index - uint32_t vout; - // Script signature length - uint32_t script_sig_len; - // Script signature data pointer - const uint8_t *script_sig; - // Sequence number - uint32_t sequence; -} FFITxIn; - -// FFI-compatible transaction output -typedef struct FFITxOut { - // Amount in satoshis - uint64_t amount; - // Script pubkey length - uint32_t script_pubkey_len; - // Script pubkey data pointer - const uint8_t *script_pubkey; -} FFITxOut; - // Binary data container for results typedef struct DashSDKBinaryData { // Pointer to the data @@ -668,7 +925,7 @@ typedef struct DashSDKIdentityBalanceMap { // Unified SDK handle containing both Core and Platform SDKs typedef struct UnifiedSDKHandle { - struct FFIDashSpvClient *core_client; + FFIDashSpvClient *core_client; struct dash_sdk_handle_t *platform_sdk; bool integration_enabled; } UnifiedSDKHandle; @@ -691,9 +948,88 @@ extern "C" { // This should be called once at app startup before using any other functions. void dash_sdk_init(void) ; +// Enable logging with the specified level +// Level values: 0 = Error, 1 = Warn, 2 = Info, 3 = Debug, 4 = Trace + void dash_sdk_enable_logging(uint8_t level) ; + // Get the version of the Dash SDK FFI library const char *dash_sdk_version(void) ; +// Synchronize address balances using trunk/branch chunk queries. +// +// This function discovers address balances for addresses supplied by the provider, +// using privacy-preserving chunk queries. It supports HD wallet gap limit behavior +// where finding a used address extends the search range. +// +// # Safety +// - `sdk_handle` must be a valid SDK handle created by this SDK +// - `provider` must be a valid pointer to an AddressProviderFFI structure +// - `config` may be null (uses defaults) or a valid pointer to DashSDKAddressSyncConfig +// - The returned result must be freed with `dash_sdk_address_sync_result_free` + struct DashSDKAddressSyncResult *dash_sdk_sync_address_balances(const struct dash_sdk_handle_t *sdk_handle, struct AddressProviderFFI *provider, const struct DashSDKAddressSyncConfig *config) ; + +// Synchronize address balances and return result with error information. +// +// This is an alternative version that returns a DashSDKResult for better error handling. +// +// # Safety +// - `sdk_handle` must be a valid SDK handle created by this SDK +// - `provider` must be a valid pointer to an AddressProviderFFI structure +// - `config` may be null (uses defaults) or a valid pointer to DashSDKAddressSyncConfig + struct DashSDKResult dash_sdk_sync_address_balances_with_result(const struct dash_sdk_handle_t *sdk_handle, struct AddressProviderFFI *provider, const struct DashSDKAddressSyncConfig *config) ; + +// Free an address sync result +// +// # Safety +// - `result` must be a valid pointer returned by `dash_sdk_sync_address_balances` +// or null (no-op) +// - After this call, the result must not be used again + void dash_sdk_address_sync_result_free(struct DashSDKAddressSyncResult *result) ; + +// Create an address provider with callbacks +// +// This creates an FFI-compatible address provider that uses callbacks +// for all operations. +// +// # Safety +// - `vtable` must be a valid pointer to an AddressProviderVTable structure +// - `context` is an opaque pointer that will be passed to all callbacks +// - The returned provider must be freed with `dash_sdk_address_provider_free` + struct AddressProviderFFI *dash_sdk_address_provider_create(const struct AddressProviderVTable *vtable, void *context) ; + +// Free an address provider +// +// # Safety +// - `provider` must be a valid pointer returned by `dash_sdk_address_provider_create` +// or null (no-op) +// - After this call, the provider must not be used again + void dash_sdk_address_provider_free(struct AddressProviderFFI *provider) ; + +// Get the total balance from a sync result +// +// # Safety +// - `result` must be a valid pointer to a DashSDKAddressSyncResult + uint64_t dash_sdk_address_sync_result_total_balance(const struct DashSDKAddressSyncResult *result) ; + +// Get the count of addresses with non-zero balance +// +// # Safety +// - `result` must be a valid pointer to a DashSDKAddressSyncResult + uintptr_t dash_sdk_address_sync_result_non_zero_count(const struct DashSDKAddressSyncResult *result) ; + +// Free a pending address list +// +// This should be called to clean up memory after the sync operation is complete +// if the caller allocated the list dynamically. +// +// Note: This only frees the list structure, not the key data which should be +// managed by the caller. +// +// # Safety +// - `list` must be a valid pointer to a DashSDKPendingAddressList +// or null (no-op) + void dash_sdk_pending_address_list_free(struct DashSDKPendingAddressList *list) ; + // Register Core SDK handle and setup callback bridge with Platform SDK // // This function implements the core pattern from dash-unified-ffi-old: @@ -732,7 +1068,12 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `identity_id` must be a valid, non-null pointer to a NUL-terminated C string that remains valid during the call. +// - `limit`, `offset`, and `order_ascending` are passed by value; no references are retained. +// - On success, the returned `DashSDKResult` may contain a heap-allocated C string; the caller must free +// it using the SDK's free routine. The result can also contain no data (null pointer). +// - All pointers provided to this function must be readable and valid. struct DashSDKResult dash_sdk_contested_resource_get_identity_votes(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, uint32_t limit, uint32_t offset, bool order_ascending) ; // Fetches contested resources @@ -752,7 +1093,14 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - All C string pointers (`contract_id`, `document_type_name`, `index_name`, +// `start_index_values_json`, `end_index_values_json`) must be either null (when documented as optional) +// or valid pointers to NUL-terminated strings that remain valid for the duration of the call. +// - The function reads the `count` and `order_ascending` by value and does not retain references. +// - On success, the returned `DashSDKResult` may contain a heap-allocated C string; the caller must +// free it using the SDK-provided free routine. The result can also contain no data (null pointer). +// - All pointers passed in must point to readable memory; behavior is undefined if they are dangling. struct DashSDKResult dash_sdk_contested_resource_get_resources(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, const char *document_type_name, const char *index_name, const char *start_index_values_json, const char *end_index_values_json, uint32_t count, bool order_ascending) ; // Fetches contested resource vote state @@ -772,7 +1120,13 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - All C string pointers (`contract_id`, `document_type_name`, `index_name`, `index_values_json`) +// must be valid, non-null pointers to NUL-terminated strings that remain valid for the duration of the call. +// - `result_type` and `allow_include_locked_and_abstaining_vote_tally` are passed by value. +// - The returned result may contain a heap-allocated C string which must be freed by the caller using +// the SDK's free routine. It may also contain no data (null pointer) on success. +// - All pointers must point to readable memory; passing invalid or dangling pointers results in undefined behavior. struct DashSDKResult dash_sdk_contested_resource_get_vote_state(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, const char *document_type_name, const char *index_name, const char *index_values_json, uint8_t result_type, bool allow_include_locked_and_abstaining_vote_tally, uint32_t count) ; // Fetches voters for a contested resource identity @@ -792,18 +1146,15 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - All C string pointers (`contract_id`, `document_type_name`, `index_name`, `index_values_json`, `contestant_id`) +// must be valid, non-null pointers to NUL-terminated strings that remain valid for the duration of the call. +// - The function reads `count` and `order_ascending` by value and does not retain references. +// - On success, the returned `DashSDKResult` may contain a heap-allocated C string; the caller must +// free it using the SDK-provided free routine. The result can also contain no data (null pointer). +// - All pointers must reference readable memory; passing invalid pointers leads to undefined behavior. struct DashSDKResult dash_sdk_contested_resource_get_voters_for_identity(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, const char *document_type_name, const char *index_name, const char *index_values_json, const char *contestant_id, uint32_t count, bool order_ascending) ; -// Create a context provider from a Core SDK handle (DEPRECATED) -// -// This function is deprecated. Use dash_sdk_context_provider_from_callbacks instead. -// -// # Safety -// - `core_handle` must be a valid Core SDK handle -// - String parameters must be valid UTF-8 C strings or null - struct ContextProviderHandle *dash_sdk_context_provider_from_core(struct CoreSDKHandle *core_handle, const char *core_rpc_url, const char *core_rpc_user, const char *core_rpc_password) ; - // Create a context provider from callbacks // // # Safety @@ -816,149 +1167,90 @@ extern "C" { // - `handle` must be a valid context provider handle or null void dash_sdk_context_provider_destroy(struct ContextProviderHandle *handle) ; -// Initialize the Core SDK -// Returns 0 on success, error code on failure - int32_t dash_core_sdk_init(void) ; - -// Create a Core SDK client with testnet config -// -// # Safety -// - Returns null on failure - struct FFIDashSpvClient *dash_core_sdk_create_client_testnet(void) ; - -// Create a Core SDK client with mainnet config -// -// # Safety -// - Returns null on failure - struct FFIDashSpvClient *dash_core_sdk_create_client_mainnet(void) ; - -// Create a Core SDK client with custom config -// -// # Safety -// - `config` must be a valid CoreSDKConfig pointer -// - Returns null on failure - struct FFIDashSpvClient *dash_core_sdk_create_client(const FFIClientConfig *config) ; - -// Destroy a Core SDK client -// -// # Safety -// - `client` must be a valid Core SDK client handle or null - void dash_core_sdk_destroy_client(struct FFIDashSpvClient *client) ; - -// Start the Core SDK client (begin sync) -// -// # Safety -// - `client` must be a valid Core SDK client handle - int32_t dash_core_sdk_start(struct FFIDashSpvClient *client) ; - -// Stop the Core SDK client +// Validate that a private key corresponds to a public key using DPP's public_key_data_from_private_key_data // // # Safety -// - `client` must be a valid Core SDK client handle - int32_t dash_core_sdk_stop(struct FFIDashSpvClient *client) ; +// - `private_key_hex` and `public_key_hex` must be valid, non-null pointers to NUL-terminated C strings that +// remain valid for the duration of the call. +// - `key_type` and `is_testnet` are passed by value; no references are retained. +// - On success, the returned `DashSDKResult` contains a heap-allocated C string pointer which must be freed using +// the SDK's free routine. It may also return no data (null pointer) to indicate success without payload. +// - Passing invalid or dangling pointers results in undefined behavior. + struct DashSDKResult dash_sdk_validate_private_key_for_public_key(const char *private_key_hex, const char *public_key_hex, uint8_t key_type, bool is_testnet) ; -// Sync Core SDK client to tip +// Convert private key to WIF format // // # Safety -// - `client` must be a valid Core SDK client handle - int32_t dash_core_sdk_sync_to_tip(struct FFIDashSpvClient *client) ; +// - `private_key_hex` must be a valid, non-null pointer to a NUL-terminated C string representing a 32-byte hex key +// and remain valid for the duration of the call. +// - `is_testnet` is passed by value. +// - On success, the returned `DashSDKResult` contains a heap-allocated C string pointer which must be freed using +// the SDK's free routine. + struct DashSDKResult dash_sdk_private_key_to_wif(const char *private_key_hex, bool is_testnet) ; -// Get the current sync progress +// Get public key data from private key data // // # Safety -// - `client` must be a valid Core SDK client handle -// - Returns pointer to FFISyncProgress structure (caller must free it) - FFISyncProgress *dash_core_sdk_get_sync_progress(struct FFIDashSpvClient *client) ; +// - `private_key_hex` must be a valid, non-null pointer to a NUL-terminated C string representing a 32-byte hex key +// and remain valid for the duration of the call. +// - `key_type` and `is_testnet` are passed by value; no references are retained. +// - On success, the returned `DashSDKResult` contains a heap-allocated C string pointer which must be freed using +// the SDK's free routine. + struct DashSDKResult dash_sdk_public_key_data_from_private_key_data(const char *private_key_hex, uint8_t key_type, bool is_testnet) ; -// Get Core SDK statistics -// -// # Safety -// - `client` must be a valid Core SDK client handle -// - Returns pointer to FFISpvStats structure (caller must free it) - FFISpvStats *dash_core_sdk_get_stats(struct FFIDashSpvClient *client) ; - -// Get the current block height -// -// # Safety -// - `client` must be a valid Core SDK client handle -// - `height` must point to a valid u32 - int32_t dash_core_sdk_get_block_height(struct FFIDashSpvClient *client, uint32_t *height) ; - -// Add an address to watch -// -// # Safety -// - `client` must be a valid Core SDK client handle -// - `address` must be a valid null-terminated C string - int32_t dash_core_sdk_watch_address(struct FFIDashSpvClient *client, const char *address) ; - -// Remove an address from watching -// -// # Safety -// - `client` must be a valid Core SDK client handle -// - `address` must be a valid null-terminated C string - int32_t dash_core_sdk_unwatch_address(struct FFIDashSpvClient *client, const char *address) ; - -// Get balance for all watched addresses -// -// # Safety -// - `client` must be a valid Core SDK client handle -// - Returns pointer to FFIBalance structure (caller must free it) - FFIBalance *dash_core_sdk_get_total_balance(struct FFIDashSpvClient *client) ; - -// Get platform activation height -// -// # Safety -// - `client` must be a valid Core SDK client handle -// - `height` must point to a valid u32 - int32_t dash_core_sdk_get_platform_activation_height(struct FFIDashSpvClient *client, uint32_t *height) ; - -// Get quorum public key -// -// # Safety -// - `client` must be a valid Core SDK client handle -// - `quorum_hash` must point to a valid 32-byte buffer -// - `public_key` must point to a valid 48-byte buffer - int32_t dash_core_sdk_get_quorum_public_key(struct FFIDashSpvClient *client, uint32_t quorum_type, const uint8_t *quorum_hash, uint32_t core_chain_locked_height, uint8_t *public_key, uintptr_t public_key_size) ; - -// Get Core SDK handle for platform integration -// -// # Safety -// - `client` must be a valid Core SDK client handle - void *dash_core_sdk_get_core_handle(struct FFIDashSpvClient *client) ; - -// Broadcast a transaction +// Create a new data contract // // # Safety -// - `client` must be a valid Core SDK client handle -// - `transaction_hex` must be a valid null-terminated C string - int32_t dash_core_sdk_broadcast_transaction(struct FFIDashSpvClient *client, const char *transaction_hex) ; - -// Check if Core SDK feature is enabled at runtime - bool dash_core_sdk_is_enabled(void) ; - -// Get Core SDK version - const char *dash_core_sdk_version(void) ; - -// Create a new data contract +// - `sdk_handle`, `owner_identity_handle`, and `documents_schema_json` must be valid, non-null pointers. +// - `documents_schema_json` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. struct DashSDKResult dash_sdk_data_contract_create(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *owner_identity_handle, const char *documents_schema_json) ; // Destroy a data contract handle +// +// # Safety +// - `handle` must be a pointer previously returned by this SDK or null (no-op). +// - After this call, `handle` becomes invalid and must not be used again. void dash_sdk_data_contract_destroy(struct DataContractHandle *handle) ; // Put data contract to platform (broadcast state transition) +// +// # Safety +// - `sdk_handle`, `data_contract_handle`, `identity_public_key_handle`, and `signer_handle` must be valid, non-null pointers. +// - On success, returns serialized data; any heap memory inside the result must be freed using SDK routines. struct DashSDKResult dash_sdk_data_contract_put_to_platform(struct dash_sdk_handle_t *sdk_handle, const struct DataContractHandle *data_contract_handle, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle) ; // Put data contract to platform and wait for confirmation (broadcast state transition and wait for response) +// +// # Safety +// - Same requirements as `dash_sdk_data_contract_put_to_platform`. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. struct DashSDKResult dash_sdk_data_contract_put_to_platform_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DataContractHandle *data_contract_handle, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle) ; // Fetch a data contract by ID +// +// # Safety +// - `sdk_handle` and `contract_id` must be valid, non-null pointers. +// - `contract_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. struct DashSDKResult dash_sdk_data_contract_fetch(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id) ; // Fetch a data contract by ID and return as JSON +// +// # Safety +// - `sdk_handle` and `contract_id` must be valid, non-null pointers. +// - `contract_id` must point to a NUL-terminated C string that remains valid for the duration of the call. +// - On success, returns a heap-allocated C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_data_contract_fetch_json(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id) ; // Fetch multiple data contracts by their IDs // +// # Safety +// - `sdk_handle` and `contract_ids` must be valid, non-null pointers. +// - `contract_ids` must point to a NUL-terminated C string containing either a JSON array of Base58 IDs or a comma-separated list; it must remain valid for the duration of the call. +// - On success, returns a heap-allocated C string pointer inside `DashSDKResult`; caller must free it using SDK routines. +// // # Parameters // - `sdk_handle`: SDK handle // - `contract_ids`: Comma-separated list of Base58-encoded contract IDs @@ -967,6 +1259,22 @@ extern "C" { // JSON string containing contract IDs mapped to their data contracts struct DashSDKResult dash_sdk_data_contracts_fetch_many(const struct dash_sdk_handle_t *sdk_handle, const char *contract_ids) ; +// Fetch a data contract by ID with serialization +// +// # Safety +// - `sdk_handle` and `contract_id` must be valid, non-null pointers. +// - `contract_id` must point to a NUL-terminated C string valid for the duration of the call. +// - The returned result contains heap-allocated buffers/handles depending on flags; caller must free them using +// `dash_sdk_data_contract_fetch_result_free`. + struct DashSDKDataContractFetchResult dash_sdk_data_contract_fetch_with_serialization(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, bool return_json, bool return_serialized) ; + +// Free the memory allocated for a data contract fetch result +// +// # Safety +// - `result` must be a pointer previously returned by this SDK or null (no-op). +// - After this call, `result` and all contained pointers become invalid and must not be used again. + void dash_sdk_data_contract_fetch_result_free(struct DashSDKDataContractFetchResult *result) ; + // Fetch data contract history // // # Parameters @@ -978,52 +1286,169 @@ extern "C" { // // # Returns // JSON string containing the data contract history +// +// # Safety +// - `sdk_handle` and `contract_id` must be valid, non-null pointers. +// - `contract_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a heap-allocated C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_data_contract_fetch_history(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, unsigned int limit, unsigned int offset, uint64_t start_at_ms) ; // Get schema for a specific document type +// +// # Safety +// - `contract_handle` and `document_type` must be valid, non-null pointers. +// - `document_type` must point to a NUL-terminated C string valid for the duration of the call. +// - Returns a heap-allocated C string pointer on success; caller must free it using SDK routines. char *dash_sdk_data_contract_get_schema(const struct DataContractHandle *contract_handle, const char *document_type) ; // Create a new document +// +// # Safety +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `params` must be a valid, non-null pointer to a `DashSDKDocumentCreateParams` structure. +// - All C string fields inside `params` (`data_contract_id`, `document_type`, `owner_identity_id`, `properties_json`) +// must be valid pointers to NUL-terminated strings and remain valid for the duration of the call. +// - On success, the returned `DashSDKResult` contains a heap-allocated handle which must be freed by the caller +// using the appropriate SDK destroy function. +// - Passing dangling or invalid pointers results in undefined behavior. struct DashSDKResult dash_sdk_document_create(struct dash_sdk_handle_t *sdk_handle, const struct DashSDKDocumentCreateParams *params) ; +// Free a document creation result +// +// # Safety +// - `result` must be either null (no-op) or a pointer previously returned by this SDK. +// - After this call, `result` becomes invalid and must not be used again. + void dash_sdk_document_create_result_free(struct DashSDKDocumentCreateResult *result) ; + +// Create a document handle from parameters +// This creates a Document object directly without broadcasting to the network +// +// # Safety +// - `params` must be a valid, non-null pointer to a `DashSDKDocumentHandleParams` structure. +// - All C string fields inside `params` must be valid pointers to NUL-terminated strings and remain valid +// for the duration of the call. +// - On success, the returned `DashSDKResult` contains a heap-allocated `DocumentHandle` which must be freed by the caller +// using the appropriate SDK destroy function. +// - Passing dangling or invalid pointers results in undefined behavior. + struct DashSDKResult dash_sdk_document_make_handle(const struct DashSDKDocumentHandleParams *params) ; + // Delete a document from the platform - struct DashSDKResult dash_sdk_document_delete(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `document_id`, `owner_id`, `data_contract_id`, and `document_type_name` must be valid, non-null pointers to +// NUL-terminated C strings that remain valid for the duration of the call. +// - `identity_public_key_handle` and `signer_handle` must be valid, non-null pointers to initialized structures. +// - Optional pointers (`token_payment_info`, `put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_delete(struct dash_sdk_handle_t *sdk_handle, const char *document_id, const char *owner_id, const char *data_contract_id, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Delete a document from the platform and wait for confirmation - struct DashSDKResult dash_sdk_document_delete_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - Same requirements as `dash_sdk_document_delete` regarding pointer validity and lifetimes. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_delete_and_wait(struct dash_sdk_handle_t *sdk_handle, const char *document_id, const char *owner_id, const char *data_contract_id, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Update document price (broadcast state transition) - struct DashSDKResult dash_sdk_document_update_price_of_document(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, uint64_t price, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; - +// +// # Safety +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `document_handle`, `data_contract_id`, `document_type_name`, `identity_public_key_handle`, and `signer_handle` +// must be valid, non-null pointers. `data_contract_id` and `document_type_name` must point to NUL-terminated C strings. +// - Optional pointers (`token_payment_info`, `put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_update_price_of_document(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, uint64_t price, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; + // Update document price and wait for confirmation (broadcast state transition and wait for response) - struct DashSDKResult dash_sdk_document_update_price_of_document_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, uint64_t price, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - Same requirements as `dash_sdk_document_update_price_of_document` regarding pointer validity and lifetimes. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_update_price_of_document_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, uint64_t price, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Purchase document (broadcast state transition) - struct DashSDKResult dash_sdk_document_purchase(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, uint64_t price, const char *purchaser_id, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `document_handle`, `data_contract_id`, `document_type_name`, `purchaser_id`, `identity_public_key_handle`, and `signer_handle` +// must be valid, non-null pointers. All C string pointers must point to NUL-terminated strings. +// - Optional pointers (`token_payment_info`, `put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_purchase(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, uint64_t price, const char *purchaser_id, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Purchase document and wait for confirmation (broadcast state transition and wait for response) - struct DashSDKResult dash_sdk_document_purchase_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, uint64_t price, const char *purchaser_id, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - Same requirements as `dash_sdk_document_purchase` regarding pointer validity and lifetimes. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_purchase_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, uint64_t price, const char *purchaser_id, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Put document to platform (broadcast state transition) - struct DashSDKResult dash_sdk_document_put_to_platform(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const uint8_t (*entropy)[32], const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `document_handle`, `data_contract_id`, `document_type_name`, `entropy`, `identity_public_key_handle`, and `signer_handle` +// must be valid, non-null pointers. `data_contract_id` and `document_type_name` must point to NUL-terminated C strings. +// - Optional pointers (`token_payment_info`, `put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. +// - All pointers must reference readable memory for the duration of the call. + struct DashSDKResult dash_sdk_document_put_to_platform(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, const uint8_t (*entropy)[32], const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Put document to platform and wait for confirmation (broadcast state transition and wait for response) - struct DashSDKResult dash_sdk_document_put_to_platform_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const uint8_t (*entropy)[32], const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - Same requirements as `dash_sdk_document_put_to_platform` regarding pointer validity and lifetimes. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_put_to_platform_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, const uint8_t (*entropy)[32], const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; + +// Fetch a document by ID using contract ID (gets contract from trusted provider) + struct DashSDKResult dash_sdk_document_fetch_by_contract_id(struct dash_sdk_handle_t *sdk_handle, const char *contract_id, const char *document_type, const char *document_id) ; -// Fetch a document by ID +// Fetch a document by ID (legacy - requires data contract handle) +// +// # Safety +// - `sdk_handle`, `data_contract_handle`, `document_type`, and `document_id` must be valid, non-null pointers. +// - `document_type` and `document_id` must point to NUL-terminated C strings valid for the duration of the call. +// - On success, returns a handle or no data; any heap memory must be freed using SDK routines. struct DashSDKResult dash_sdk_document_fetch(const struct dash_sdk_handle_t *sdk_handle, const struct DataContractHandle *data_contract_handle, const char *document_type, const char *document_id) ; // Get document information +// +// # Safety +// - `document_handle` must be a valid, non-null pointer to a `DocumentHandle` that remains valid for the duration of the call. +// - Returns a heap-allocated `DashSDKDocumentInfo` pointer on success; caller must free it using the SDK-provided free function. struct DashSDKDocumentInfo *dash_sdk_document_get_info(const struct DocumentHandle *document_handle) ; // Search for documents +// +// # Safety +// - `sdk_handle` and `params` must be valid, non-null pointers. +// - All C string pointers inside `params` must point to NUL-terminated strings and remain valid for the duration of the call; optional strings may be null. +// - On success, returns a heap-allocated C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_document_search(const struct dash_sdk_handle_t *sdk_handle, const struct DashSDKDocumentSearchParams *params) ; // Replace document on platform (broadcast state transition) - struct DashSDKResult dash_sdk_document_replace_on_platform(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `document_handle`, `data_contract_id`, `document_type_name`, `identity_public_key_handle`, and `signer_handle` +// must be valid, non-null pointers. `data_contract_id` and `document_type_name` must point to NUL-terminated C strings. +// - Optional pointers (`token_payment_info`, `put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_replace_on_platform(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Replace document on platform and wait for confirmation (broadcast state transition and wait for response) - struct DashSDKResult dash_sdk_document_replace_on_platform_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - Same requirements as `dash_sdk_document_replace_on_platform` regarding pointer validity and lifetimes. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_replace_on_platform_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Transfer document to another identity // @@ -1039,7 +1464,13 @@ extern "C" { // // # Returns // Serialized state transition on success - struct DashSDKResult dash_sdk_document_transfer_to_identity(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *recipient_id, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - `sdk_handle`, `document_handle`, `recipient_id`, `data_contract_id`, `document_type_name`, `identity_public_key_handle`, and `signer_handle` must be valid, non-null pointers. +// - All C string pointers must point to NUL-terminated strings valid for the duration of the call. +// - Optional pointers (`token_payment_info`, `put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - On success, any heap memory in the result must be freed using SDK routines. + struct DashSDKResult dash_sdk_document_transfer_to_identity(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *recipient_id, const char *data_contract_id, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Transfer document to another identity and wait for confirmation // @@ -1055,31 +1486,87 @@ extern "C" { // // # Returns // Handle to the transferred document on success - struct DashSDKResult dash_sdk_document_transfer_to_identity_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *recipient_id, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - Same requirements as `dash_sdk_document_transfer_to_identity` regarding pointer validity and lifetimes. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_transfer_to_identity_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *recipient_id, const char *data_contract_id, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Destroy a document +// +// # Safety +// - `sdk_handle` and `document_handle` must be valid, non-null pointers. +// - Returns a pointer to an error structure on failure; caller must free with `dash_sdk_error_free`. struct DashSDKError *dash_sdk_document_destroy(struct dash_sdk_handle_t *sdk_handle, struct DocumentHandle *document_handle) ; // Destroy a document handle +// +// # Safety +// - `handle` must be a pointer previously returned by this SDK or null (no-op). +// - After this call, `handle` becomes invalid and must not be used again. void dash_sdk_document_handle_destroy(struct DocumentHandle *handle) ; -// Get DPNS usernames owned by an identity +// Free a document handle (alias for destroy) // -// This function returns all DPNS usernames associated with a given identity ID. -// It checks for domains where the identity is: -// - The owner of the domain document -// - Listed in records.dashUniqueIdentityId -// - Listed in records.dashAliasIdentityId +// # Safety +// - Same as `dash_sdk_document_handle_destroy`. + void dash_sdk_document_free(struct DocumentHandle *handle) ; + +// Set document properties from JSON // -// # Arguments -// * `sdk_handle` - Handle to the SDK instance -// * `identity_id` - The identity ID to search for (base58 string) -// * `limit` - Maximum number of results to return (0 for default of 10) +// # Safety +// - `document_handle` and `properties_json` must be valid, non-null pointers. +// - `properties_json` must point to a NUL-terminated C string valid for the duration of the call. +// - Returns an error pointer on failure; caller must free with `dash_sdk_error_free`. + struct DashSDKError *dash_sdk_document_set_properties(struct DocumentHandle *document_handle, const char *properties_json) ; + +// Convert a string to homograph-safe characters by replacing 'o', 'i', and 'l' +// with '0', '1', and '1' respectively to prevent homograph attacks +// +// # Safety +// - `name` must be a valid null-terminated C string + struct DashSDKResult dash_sdk_dpns_normalize_username(const char *name) ; + +// Check if a username is valid according to DPNS rules +// +// A username is valid if: +// - It's between 3 and 63 characters long +// - It starts and ends with alphanumeric characters (a-zA-Z0-9) +// - It contains only alphanumeric characters and hyphens +// - It doesn't have consecutive hyphens +// +// # Safety +// - `name` must be a valid null-terminated C string // // # Returns -// * On success: A JSON array of username objects -// * On error: An error result - struct DashSDKResult dash_sdk_dpns_get_usernames(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, uint32_t limit) ; +// - 1 if the username is valid +// - 0 if the username is invalid +// - -1 if there's an error + int32_t dash_sdk_dpns_is_valid_username(const char *name) ; + +// Check if a username is contested (requires masternode voting) +// +// A username is contested if its normalized label: +// - Is between 3 and 19 characters long (inclusive) +// - Contains only lowercase letters a-z, digits 0-1, and hyphens +// +// # Safety +// - `name` must be a valid null-terminated C string +// +// # Returns +// - 1 if the username is contested +// - 0 if the username is not contested +// - -1 if there's an error + int32_t dash_sdk_dpns_is_contested_username(const char *name) ; + +// Get a validation message for a username +// +// Returns a descriptive message about why a username is invalid, or "valid" if it's valid. +// +// # Safety +// - `name` must be a valid null-terminated C string + struct DashSDKResult dash_sdk_dpns_get_validation_message(const char *name) ; // Check if a DPNS username is available // @@ -1093,8 +1580,87 @@ extern "C" { // # Returns // * On success: A JSON object with availability information // * On error: An error result +// +// # Safety +// - `sdk_handle` and `label` must be valid, non-null pointers. +// - `label` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_dpns_check_availability(const struct dash_sdk_handle_t *sdk_handle, const char *label) ; +// Get all contested DPNS usernames where an identity is a contender +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. + struct DashSDKResult dash_sdk_dpns_get_contested_usernames_by_identity(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, uint32_t limit) ; + +// Get the vote state for a contested DPNS username +// +// # Safety +// This function is unsafe because it operates on raw pointers + struct DashSDKResult dash_sdk_dpns_get_contested_vote_state(const struct dash_sdk_handle_t *sdk_handle, const char *label, uint32_t limit) ; + +// Get all contested DPNS usernames +// +// # Safety +// This function is unsafe because it operates on raw pointers + struct DashSDKResult dash_sdk_dpns_get_all_contested_usernames(const struct dash_sdk_handle_t *sdk_handle, uint32_t limit, const char *start_after) ; + +// Get current DPNS contests (active vote polls) +// +// Returns a list of contested DPNS names with their end times. +// The caller is responsible for freeing the result with `dash_sdk_name_timestamp_list_free`. +// +// # Safety +// This function is unsafe because it operates on raw pointers + struct DashSDKNameTimestampList *dash_sdk_dpns_get_current_contests(const struct dash_sdk_handle_t *sdk_handle, uint64_t start_time, uint64_t end_time, uint16_t limit) ; + +// Get all contested DPNS usernames that an identity has voted on +// +// # Safety +// This function is unsafe because it operates on raw pointers + struct DashSDKResult dash_sdk_dpns_get_identity_votes(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, uint32_t limit, uint16_t offset) ; + +// Get non-resolved DPNS contests for a specific identity +// +// Returns a list of contested but unresolved DPNS usernames where the identity is a contender. +// The caller is responsible for freeing the result with `dash_sdk_contested_names_list_free`. +// +// # Safety +// This function is unsafe because it operates on raw pointers + struct DashSDKContestedNamesList *dash_sdk_dpns_get_non_resolved_contests_for_identity(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, uint32_t limit) ; + +// Get contested DPNS usernames that are not yet resolved +// +// Returns a list of contested but unresolved DPNS usernames with their contest information. +// The caller is responsible for freeing the result with `dash_sdk_contested_names_list_free`. +// +// # Safety +// This function is unsafe because it operates on raw pointers + struct DashSDKContestedNamesList *dash_sdk_dpns_get_contested_non_resolved_usernames(const struct dash_sdk_handle_t *sdk_handle, uint32_t limit) ; + +// Resolve a DPNS name to an identity ID +// +// This function resolves a DPNS username to its associated identity ID. +// The name can be either: +// - A full domain name (e.g., "alice.dash") +// - Just the label (e.g., "alice") +// +// # Arguments +// * `sdk_handle` - Handle to the SDK instance +// * `name` - The DPNS name to resolve +// +// # Returns +// * On success: A JSON object with the identity ID, or null if not found +// * On error: An error result +// +// # Safety +// - `sdk_handle` and `name` must be valid, non-null pointers. +// - `name` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. + struct DashSDKResult dash_sdk_dpns_resolve(const struct dash_sdk_handle_t *sdk_handle, const char *name) ; + // Search for DPNS names that start with a given prefix // // This function searches for DPNS usernames that start with the given prefix. @@ -1107,25 +1673,61 @@ extern "C" { // # Returns // * On success: A JSON array of username objects // * On error: An error result +// +// # Safety +// - `sdk_handle` and `prefix` must be valid, non-null pointers. +// - `prefix` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_dpns_search(const struct dash_sdk_handle_t *sdk_handle, const char *prefix, uint32_t limit) ; -// Resolve a DPNS name to an identity ID +// Get DPNS usernames owned by an identity // -// This function resolves a DPNS username to its associated identity ID. -// The name can be either: -// - A full domain name (e.g., "alice.dash") -// - Just the label (e.g., "alice") +// This function returns all DPNS usernames associated with a given identity ID. +// It checks for domains where the identity is: +// - The owner of the domain document +// - Listed in records.dashUniqueIdentityId +// - Listed in records.dashAliasIdentityId // // # Arguments // * `sdk_handle` - Handle to the SDK instance -// * `name` - The DPNS name to resolve +// * `identity_id` - The identity ID to search for (base58 string) +// * `limit` - Maximum number of results to return (0 for default of 10) // // # Returns -// * On success: A JSON object with the identity ID, or null if not found +// * On success: A JSON array of username objects // * On error: An error result - struct DashSDKResult dash_sdk_dpns_resolve(const struct dash_sdk_handle_t *sdk_handle, const char *name) ; +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. + struct DashSDKResult dash_sdk_dpns_get_usernames(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, uint32_t limit) ; + +// Register a DPNS username in a single operation +// +// This method handles both the preorder and domain registration steps automatically. +// It generates the necessary entropy, creates both documents, and submits them in order. +// +// # Safety +// - `handle` must be a valid, non-null SDK handle pointer. +// - `label` must be a valid pointer to a NUL-terminated C string that remains valid for the duration of the call. +// - `identity`, `identity_public_key`, and `signer` must be valid handles (as raw pointers) obtained from this SDK and not previously freed; they are not consumed by this call. +// +// # Returns +// Returns a DpnsRegistrationResult containing both created documents and the full domain name + struct DashSDKResult dash_sdk_dpns_register_name(const struct dash_sdk_handle_t *handle, const char *label, const void *identity, const void *identity_public_key, const void *signer) ; + +// Free a DPNS registration result +// +// # Safety +// - `result` must be a valid DpnsRegistrationResult pointer created by dash_sdk_dpns_register_name + void dash_sdk_dpns_registration_result_free(struct DpnsRegistrationResult *result) ; // Free an error message +// +// # Safety +// - `error` must be a pointer previously returned by this SDK or null (no-op). +// - After this call, `error` becomes invalid and must not be used again. void dash_sdk_error_free(struct DashSDKError *error) ; // Fetches proposed epoch blocks by evonode IDs @@ -1140,7 +1742,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` and `ids_json` must be valid pointers; `ids_json` must point to a NUL-terminated C string with a JSON array of hex IDs. +// - Pointers must remain valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_evonode_get_proposed_epoch_blocks_by_ids(const struct dash_sdk_handle_t *sdk_handle, uint32_t epoch, const char *ids_json) ; // Fetches proposed epoch blocks by range @@ -1157,7 +1761,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer. +// - `start_after` and `start_at` may be null; when non-null they must point to NUL-terminated C strings with hex-encoded 32-byte hashes. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_evonode_get_proposed_epoch_blocks_by_range(const struct dash_sdk_handle_t *sdk_handle, uint32_t epoch, uint32_t limit, const char *start_after, const char *start_at) ; // Fetches group action signers @@ -1174,7 +1780,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle`, `contract_id`, and `action_id` must be valid, non-null pointers. +// - `contract_id` and `action_id` must point to NUL-terminated C strings valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_group_get_action_signers(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, uint16_t group_contract_position, uint8_t status, const char *action_id) ; // Fetches group actions @@ -1192,7 +1800,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` and `contract_id` must be valid, non-null pointers. +// - `contract_id` must point to a NUL-terminated C string; `start_at_action_id` may be null, otherwise must be a valid NUL-terminated C string. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_group_get_actions(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, uint16_t group_contract_position, uint8_t status, const char *start_at_action_id, uint16_t limit) ; // Fetches information about a group @@ -1207,7 +1817,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` and `contract_id` must be valid, non-null pointers. +// - `contract_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_group_get_info(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, uint16_t group_contract_position) ; // Fetches information about multiple groups @@ -1222,10 +1834,18 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer. +// - `start_at_position` may be null; when non-null it must point to a NUL-terminated C string representing a number. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_group_get_infos(const struct dash_sdk_handle_t *sdk_handle, const char *start_at_position, uint32_t limit) ; // Create a new identity +// +// # Safety +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - On success, the returned `DashSDKResult` contains a heap-allocated handle that must be freed using the +// appropriate SDK destroy function. +// - Passing a dangling or invalid pointer results in undefined behavior. struct DashSDKResult dash_sdk_identity_create(struct dash_sdk_handle_t *sdk_handle) ; // Create an identity handle from components @@ -1243,6 +1863,13 @@ extern "C" { // # Returns // - Handle to the created identity on success // - Error if creation fails +// +// # Safety +// - `identity_id` must be a valid pointer to 32 readable bytes. +// - If `public_keys_count > 0`, `public_keys` must be a valid pointer to an array of `DashSDKPublicKeyData` +// structures of length `public_keys_count`; each `data` field in the array must point to at least `data_len` readable bytes. +// - All pointers must remain valid for the duration of the call. +// - On success, returns a heap-allocated handle; caller must destroy it using the SDK's destroy function. struct DashSDKResult dash_sdk_identity_create_from_components(const uint8_t *identity_id, const struct DashSDKPublicKeyData *public_keys, uintptr_t public_keys_count, uint64_t balance, uint64_t revision) ; // Get a public key from an identity by its ID @@ -1254,12 +1881,27 @@ extern "C" { // # Returns // - Handle to the public key on success // - Error if key not found or invalid parameters +// +// # Safety +// - `identity` must be a valid, non-null pointer to an `IdentityHandle` that remains valid for the duration of the call. +// - On success, the returned `DashSDKResult` contains a heap-allocated handle which must be destroyed with the SDK's +// corresponding destroy function. +// - Passing invalid or dangling pointers results in undefined behavior. struct DashSDKResult dash_sdk_identity_get_public_key_by_id(const struct IdentityHandle *identity, uint8_t key_id) ; // Get identity information +// +// # Safety +// - `identity_handle` must be a valid, non-null pointer to an `IdentityHandle` that remains valid for the duration of the call. +// - Returns a heap-allocated `DashSDKIdentityInfo` pointer; caller must free it using the SDK-provided destroy function. +// - Passing invalid or dangling pointers results in undefined behavior. struct DashSDKIdentityInfo *dash_sdk_identity_get_info(const struct IdentityHandle *identity_handle) ; // Destroy an identity handle +// +// # Safety +// - `handle` must be a pointer previously returned by this SDK or null (no-op). +// - After this call, `handle` becomes invalid and must not be used again. void dash_sdk_identity_destroy(struct IdentityHandle *handle) ; // Get the appropriate signing key for a state transition @@ -1274,6 +1916,12 @@ extern "C" { // # Returns // - Handle to the identity public key on success // - Error if no suitable key is found +// +// # Safety +// - `identity_handle` must be a valid, non-null pointer to an `IdentityHandle` that remains valid for the duration of the call. +// - On success, the returned `DashSDKResult` contains a heap-allocated handle which must be destroyed with the SDK's +// corresponding destroy function. +// - Passing invalid or dangling pointers results in undefined behavior. struct DashSDKResult dash_sdk_identity_get_signing_key_for_transition(const struct IdentityHandle *identity_handle, enum StateTransitionType transition_type) ; // Get the private key data for a transfer key @@ -1289,15 +1937,68 @@ extern "C" { // # Returns // - 32-byte private key data on success // - Error if key not found or not accessible +// +// # Safety +// - `identity_handle` must be a valid, non-null pointer to an `IdentityHandle`. +// - This function returns its result inside `DashSDKResult`; any heap pointers within must be freed using SDK routines. +// - Passing invalid or dangling pointers results in undefined behavior. struct DashSDKResult dash_sdk_identity_get_transfer_private_key(const struct IdentityHandle *identity_handle, uint32_t key_index) ; // Get the key ID from an identity public key +// +// # Safety +// - `key_handle` must be a valid, non-null pointer to an `IdentityPublicKeyHandle`. +// - Returns 0 if the pointer is null. uint32_t dash_sdk_identity_public_key_get_id(const struct IdentityPublicKeyHandle *key_handle) ; +// Create an identity public key handle from key data +// +// This function creates an identity public key handle from the raw key data +// without needing to fetch the identity from the network. +// +// # Parameters +// - `key_id`: The key ID +// - `key_type`: The key type (0 = ECDSA_SECP256K1, 1 = BLS12_381, 2 = ECDSA_HASH160, 3 = BIP13_SCRIPT_HASH, 4 = ED25519_HASH160) +// - `purpose`: The key purpose (0 = Authentication, 1 = Encryption, 2 = Decryption, 3 = Transfer, 4 = SystemTransfer, 5 = Voting) +// - `security_level`: The security level (0 = Master, 1 = Critical, 2 = High, 3 = Medium) +// - `public_key_data`: The public key data +// - `public_key_data_len`: Length of the public key data +// - `read_only`: Whether the key is read-only +// - `disabled_at`: Optional timestamp when the key was disabled (0 if not disabled) +// +// # Returns +// - Handle to the identity public key on success +// - Error if parameters are invalid +// +// # Safety +// - `public_key_data` must be a valid, non-null pointer to a buffer of `public_key_data_len` readable bytes. +// - All scalar parameters are passed by value. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. +// - Passing invalid or dangling pointers results in undefined behavior. + struct DashSDKResult dash_sdk_identity_public_key_create_from_data(uint32_t key_id, uint8_t key_type, uint8_t purpose, uint8_t security_level, const uint8_t *public_key_data, uintptr_t public_key_data_len, bool read_only, uint64_t disabled_at) ; + +// Serialize an identity public key to bytes +// Returns the serialized bytes and their length +// +// # Safety +// - `key_handle` must be a valid, non-null pointer to an `IdentityPublicKeyHandle`. +// - `out_bytes` and `out_len` must be valid, non-null pointers to writable memory. +// - Caller must free the returned buffer with the appropriate SDK-provided free function. + struct DashSDKResult dash_sdk_identity_public_key_to_bytes(const struct IdentityPublicKeyHandle *key_handle, uint8_t **out_bytes, uintptr_t *out_len) ; + // Free an identity public key handle +// +// # Safety +// - `handle` must be a pointer previously returned by this SDK or null (no-op). +// - After this call, `handle` becomes invalid and must not be used again. void dash_sdk_identity_public_key_destroy(struct IdentityPublicKeyHandle *handle) ; // Register a name for an identity +// +// # Safety +// - `_sdk_handle` and `_identity_handle` must be valid pointers when used; currently this stub ignores them. +// - `_name` must be a valid pointer to a NUL-terminated C string if used in the future. +// - Returns a heap-allocated error pointer; caller must free it using `dash_sdk_error_free`. struct DashSDKError *dash_sdk_identity_register_name(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *identity_handle, const char *name) ; // Parse an identity from JSON string to handle @@ -1312,10 +2013,21 @@ extern "C" { // # Returns // - Handle to the parsed identity on success // - Error if JSON parsing fails +// +// # Safety +// - `json_str` must be a valid, non-null pointer to a NUL-terminated C string and remain valid for the duration of the call. +// - On success, the returned `DashSDKResult` contains a heap-allocated handle which must be freed using the +// appropriate SDK destroy function to avoid leaks. struct DashSDKResult dash_sdk_identity_parse_json(const char *json_str) ; // Put identity to platform with instant lock proof // +// # Safety +// - `sdk_handle`, `identity_handle`, `instant_lock_bytes`, `transaction_bytes`, `private_key`, and `signer_handle` +// must be valid, non-null pointers. Buffer pointers must reference at least the specified lengths. +// - `put_settings` may be null; if non-null it must be valid for the duration of the call. +// - On success, returns serialized data; any heap memory inside the result must be freed using SDK routines. +// // # Parameters // - `instant_lock_bytes`: Serialized InstantLock data // - `transaction_bytes`: Serialized Transaction data @@ -1326,6 +2038,11 @@ extern "C" { // Put identity to platform with instant lock proof and wait for confirmation // +// # Safety +// - Same requirements as `dash_sdk_identity_put_to_platform_with_instant_lock`. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. +// // # Parameters // - `instant_lock_bytes`: Serialized InstantLock data // - `transaction_bytes`: Serialized Transaction data @@ -1339,6 +2056,12 @@ extern "C" { // Put identity to platform with chain lock proof // +// # Safety +// - `sdk_handle`, `identity_handle`, `out_point`, `private_key`, and `signer_handle` must be valid, non-null pointers. +// - `out_point` must reference 36 readable bytes; `private_key` must reference 32 readable bytes. +// - `put_settings` may be null; if non-null it must be valid for the duration of the call. +// - On success, returns serialized data; any heap memory inside the result must be freed using SDK routines. +// // # Parameters // - `core_chain_locked_height`: Core height at which the transaction was chain locked // - `out_point`: 36-byte OutPoint (32-byte txid + 4-byte vout) @@ -1348,6 +2071,11 @@ extern "C" { // Put identity to platform with chain lock proof and wait for confirmation // +// # Safety +// - Same requirements as `dash_sdk_identity_put_to_platform_with_chain_lock`. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. +// // # Parameters // - `core_chain_locked_height`: Core height at which the transaction was chain locked // - `out_point`: 36-byte OutPoint (32-byte txid + 4-byte vout) @@ -1366,6 +2094,11 @@ extern "C" { // // # Returns // The balance of the identity as a string +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_identity_fetch_balance(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id) ; // Fetch identity balance and revision @@ -1376,6 +2109,11 @@ extern "C" { // // # Returns // JSON string containing the balance and revision information +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_identity_fetch_balance_and_revision(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id) ; // Fetch identity by non-unique public key hash with optional pagination @@ -1387,10 +2125,21 @@ extern "C" { // // # Returns // JSON string containing the identity information, or null if not found +// +// # Safety +// - `sdk_handle` and `public_key_hash` must be valid, non-null pointers. +// - `public_key_hash` must point to a NUL-terminated C string. `start_after` may be null; if non-null it must be a valid +// pointer to a NUL-terminated C string. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_identity_fetch_by_non_unique_public_key_hash(const struct dash_sdk_handle_t *sdk_handle, const char *public_key_hash, const char *start_after) ; // Fetch identity by public key hash // +// # Safety +// - `sdk_handle` and `public_key_hash` must be valid, non-null pointers. +// - `public_key_hash` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a handle or no data; any heap memory must be freed using SDK routines. +// // # Parameters // - `sdk_handle`: SDK handle // - `public_key_hash`: Hex-encoded 20-byte public key hash @@ -1408,9 +2157,19 @@ extern "C" { // // # Returns // The contract nonce of the identity as a string +// +// # Safety +// - `sdk_handle`, `identity_id`, and `contract_id` must be valid, non-null pointers. +// - `identity_id` and `contract_id` must point to NUL-terminated C strings valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_identity_fetch_contract_nonce(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, const char *contract_id) ; // Fetch an identity by ID +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string. +// - On success, returns a handle or no data; any heap memory must be freed using SDK routines. struct DashSDKResult dash_sdk_identity_fetch(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id) ; // Fetch an identity by ID and return a handle @@ -1425,10 +2184,20 @@ extern "C" { // # Returns // - Handle to the fetched identity on success // - Error if fetch fails or identity not found +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. struct DashSDKResult dash_sdk_identity_fetch_handle(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id) ; // Fetch balances for multiple identities // +// # Safety +// - `sdk_handle` and `identity_ids` must be valid, non-null pointers. +// - `identity_ids` must point to an array of `[u8; 32]` of length `identity_ids_len` and remain valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. +// // # Parameters // - `sdk_handle`: SDK handle // - `identity_ids`: Array of identity IDs (32-byte arrays) @@ -1449,6 +2218,11 @@ extern "C" { // // # Returns // JSON string containing identity IDs mapped to their contract keys by purpose +// +// # Safety +// - `sdk_handle`, `identity_ids`, `contract_id`, and `purposes` must be valid, non-null pointers. +// - `identity_ids`, `contract_id`, `document_type_name` (when non-null), and `purposes` must point to NUL-terminated C strings valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_identities_fetch_contract_keys(const struct dash_sdk_handle_t *sdk_handle, const char *identity_ids, const char *contract_id, const char *document_type_name, const char *purposes) ; // Fetch identity nonce @@ -1459,10 +2233,20 @@ extern "C" { // // # Returns // The nonce of the identity as a string +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_identity_fetch_nonce(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id) ; // Fetch identity public keys // +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. +// // # Parameters // - `sdk_handle`: SDK handle // - `identity_id`: Base58-encoded identity ID @@ -1483,12 +2267,36 @@ extern "C" { // # Returns // * On success: A result containing the resolved identity ID // * On error: An error result +// +// # Safety +// - `sdk_handle` and `name` must be valid, non-null pointers. +// - `name` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, any heap memory in the result must be freed using SDK routines. struct DashSDKResult dash_sdk_identity_resolve_name(const struct dash_sdk_handle_t *sdk_handle, const char *name) ; +// Test function to diagnose the transfer crash +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, any heap memory in the result must be freed using SDK routines. + struct DashSDKResult dash_sdk_test_identity_transfer_crash(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id) ; + // Top up an identity with credits using instant lock proof +// +// # Safety +// - `sdk_handle`, `identity_handle`, `instant_lock_bytes`, `transaction_bytes`, and `private_key` must be valid, non-null pointers. +// - Buffer pointers must reference at least the specified lengths. +// - `put_settings` may be null; if non-null it must be valid for the duration of the call. +// - On success, returns serialized data; any heap memory inside the result must be freed using SDK routines. struct DashSDKResult dash_sdk_identity_topup_with_instant_lock(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *identity_handle, const uint8_t *instant_lock_bytes, uintptr_t instant_lock_len, const uint8_t *transaction_bytes, uintptr_t transaction_len, uint32_t output_index, const uint8_t (*private_key)[32], const struct DashSDKPutSettings *put_settings) ; // Top up an identity with credits using instant lock proof and wait for confirmation +// +// # Safety +// - Same requirements as `dash_sdk_identity_topup_with_instant_lock`. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. struct DashSDKResult dash_sdk_identity_topup_with_instant_lock_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *identity_handle, const uint8_t *instant_lock_bytes, uintptr_t instant_lock_len, const uint8_t *transaction_bytes, uintptr_t transaction_len, uint32_t output_index, const uint8_t (*private_key)[32], const struct DashSDKPutSettings *put_settings) ; // Transfer credits from one identity to another @@ -1503,9 +2311,19 @@ extern "C" { // // # Returns // DashSDKTransferCreditsResult with sender and receiver final balances on success +// +// # Safety +// - `sdk_handle`, `from_identity_handle`, `to_identity_id`, and `signer_handle` must be valid, non-null pointers. +// - `to_identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - `put_settings` may be null; if non-null it must be valid for the duration of the call. +// - On success, any heap memory included in the result must be freed using SDK routines. struct DashSDKResult dash_sdk_identity_transfer_credits(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *from_identity_handle, const char *to_identity_id, uint64_t amount, uint32_t public_key_id, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings) ; // Free a transfer credits result structure +// +// # Safety +// - `result` must be a pointer previously returned by this SDK or null (no-op). +// - After this call, `result` becomes invalid and must not be used again. void dash_sdk_transfer_credits_result_free(struct DashSDKTransferCreditsResult *result) ; // Withdraw credits from identity to a Dash address @@ -1521,149 +2339,13 @@ extern "C" { // // # Returns // The new balance of the identity after withdrawal - struct DashSDKResult dash_sdk_identity_withdraw(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *identity_handle, const char *address, uint64_t amount, uint32_t core_fee_per_byte, uint32_t public_key_id, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings) ; - -// Test function to diagnose the transfer crash - struct DashSDKResult dash_sdk_test_identity_transfer_crash(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id) ; - -// Generate a new BIP39 mnemonic -// -// # Parameters -// - `word_count`: Number of words (12, 15, 18, 21, or 24) -// -// # Returns -// - Pointer to FFIMnemonic on success -// - NULL on error (check dash_get_last_error) - struct FFIMnemonic *dash_key_mnemonic_generate(uint8_t word_count) ; - -// Create a mnemonic from a phrase -// -// # Parameters -// - `phrase`: The mnemonic phrase as a C string -// -// # Returns -// - Pointer to FFIMnemonic on success -// - NULL on error - struct FFIMnemonic *dash_key_mnemonic_from_phrase(const char *phrase) ; - -// Get the phrase from a mnemonic -// -// # Parameters -// - `mnemonic`: The mnemonic handle -// -// # Returns -// - C string containing the phrase (caller must free with dash_string_free) -// - NULL on error - char *dash_key_mnemonic_phrase(const struct FFIMnemonic *mnemonic) ; - -// Convert mnemonic to seed -// -// # Parameters -// - `mnemonic`: The mnemonic handle -// - `passphrase`: Optional passphrase (can be NULL) -// - `seed_out`: Buffer to write seed (must be 64 bytes) -// -// # Returns -// - 0 on success -// - -1 on error - int32_t dash_key_mnemonic_to_seed(const struct FFIMnemonic *mnemonic, const char *passphrase, uint8_t *seed_out) ; - -// Destroy a mnemonic - void dash_key_mnemonic_destroy(struct FFIMnemonic *mnemonic) ; - -// Create an extended private key from seed -// -// # Parameters -// - `seed`: The seed bytes (must be 64 bytes) -// - `network`: The network type -// -// # Returns -// - Pointer to FFIExtendedPrivKey on success -// - NULL on error - struct FFIExtendedPrivKey *dash_key_xprv_from_seed(const uint8_t *seed, enum FFIKeyNetwork network) ; - -// Derive a child key from extended private key -// -// # Parameters -// - `xprv`: The parent extended private key -// - `index`: The child index -// - `hardened`: Whether to use hardened derivation -// -// # Returns -// - Pointer to derived FFIExtendedPrivKey on success -// - NULL on error - struct FFIExtendedPrivKey *dash_key_xprv_derive_child(const struct FFIExtendedPrivKey *xprv, uint32_t index, bool hardened) ; - -// Derive key at BIP32 path -// -// # Parameters -// - `xprv`: The root extended private key -// - `path`: The derivation path (e.g., "m/44'/5'/0'/0/0") -// -// # Returns -// - Pointer to derived FFIExtendedPrivKey on success -// - NULL on error - struct FFIExtendedPrivKey *dash_key_xprv_derive_path(const struct FFIExtendedPrivKey *xprv, const char *path) ; - -// Get extended public key from extended private key -// -// # Parameters -// - `xprv`: The extended private key -// -// # Returns -// - Pointer to FFIExtendedPubKey on success -// - NULL on error - struct FFIExtendedPubKey *dash_key_xprv_to_xpub(const struct FFIExtendedPrivKey *xprv) ; - -// Get private key bytes -// -// # Parameters -// - `xprv`: The extended private key -// - `key_out`: Buffer to write key (must be 32 bytes) -// -// # Returns -// - 0 on success -// - -1 on error - int32_t dash_key_xprv_private_key(const struct FFIExtendedPrivKey *xprv, uint8_t *key_out) ; - -// Destroy an extended private key - void dash_key_xprv_destroy(struct FFIExtendedPrivKey *xprv) ; - -// Get public key bytes from extended public key -// -// # Parameters -// - `xpub`: The extended public key -// - `key_out`: Buffer to write key (must be 33 bytes for compressed) -// -// # Returns -// - 0 on success -// - -1 on error - int32_t dash_key_xpub_public_key(const struct FFIExtendedPubKey *xpub, uint8_t *key_out) ; - -// Destroy an extended public key - void dash_key_xpub_destroy(struct FFIExtendedPubKey *xpub) ; - -// Generate a P2PKH address from public key // -// # Parameters -// - `pubkey`: The public key bytes (33 bytes compressed) -// - `network`: The network type -// -// # Returns -// - C string containing the address (caller must free) -// - NULL on error - char *dash_key_address_from_pubkey(const uint8_t *pubkey, enum FFIKeyNetwork network) ; - -// Validate an address string -// -// # Parameters -// - `address`: The address string -// - `network`: The expected network -// -// # Returns -// - 1 if valid -// - 0 if invalid - int32_t dash_key_address_validate(const char *address, enum FFIKeyNetwork network) ; +// # Safety +// - `sdk_handle`, `identity_handle`, `address`, and `signer_handle` must be valid, non-null pointers. +// - `address` must point to a NUL-terminated C string valid for the duration of the call. +// - `put_settings` may be null; if non-null it must be valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. + struct DashSDKResult dash_sdk_identity_withdraw(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *identity_handle, const char *address, uint64_t amount, uint32_t core_fee_per_byte, uint32_t public_key_id, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings) ; // Fetches protocol version upgrade state // @@ -1675,7 +2357,11 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - The function does not retain references to the input pointer beyond the duration of the call. +// - On success, the returned `DashSDKResult` may contain a heap-allocated C string; the caller must +// free it using the SDK's free routine to avoid leaks. It may also return no data (null pointer). +// - Passing a dangling or invalid pointer for `sdk_handle` results in undefined behavior. struct DashSDKResult dash_sdk_protocol_version_get_upgrade_state(const struct dash_sdk_handle_t *sdk_handle) ; // Fetches protocol version upgrade vote status @@ -1690,13 +2376,28 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `start_pro_tx_hash` may be null (meaning no start); when non-null it must be a valid pointer to a +// NUL-terminated C string containing a hex-encoded 32-byte hash and remain valid for the duration of the call. +// - `count` is passed by value; no references are retained. +// - On success, the returned `DashSDKResult` may contain a heap-allocated C string which the caller must free +// using the SDK's free routine. It may also contain no data (null pointer). +// - All pointers must reference readable memory; invalid pointers result in undefined behavior. struct DashSDKResult dash_sdk_protocol_version_get_upgrade_vote_status(const struct dash_sdk_handle_t *sdk_handle, const char *start_pro_tx_hash, uint32_t count) ; // Create a new SDK instance +// +// # Safety +// - `config` must be a valid pointer to a DashSDKConfig structure for the duration of the call. +// - The returned handle inside `DashSDKResult` must be destroyed using the SDK destroy function to avoid leaks. struct DashSDKResult dash_sdk_create(const struct DashSDKConfig *config) ; // Create a new SDK instance with extended configuration including context provider +// +// # Safety +// - `config` must be a valid pointer to a DashSDKConfigExtended structure for the duration of the call. +// - Any embedded pointers (context_provider/core_sdk_handle) must be valid when non-null. +// - The returned handle inside `DashSDKResult` must be destroyed using the SDK destroy function to avoid leaks. struct DashSDKResult dash_sdk_create_extended(const struct DashSDKConfigExtended *config) ; // Create a new SDK instance with trusted setup @@ -1706,9 +2407,15 @@ extern "C" { // // # Safety // - `config` must be a valid pointer to a DashSDKConfig structure +// # Safety +// - `config` must be a valid pointer to a DashSDKConfig structure for the duration of the call. +// - The returned handle inside `DashSDKResult` must be destroyed using the SDK destroy function to avoid leaks. struct DashSDKResult dash_sdk_create_trusted(const struct DashSDKConfig *config) ; // Destroy an SDK instance +// # Safety +// - `handle` must be a valid pointer previously returned by this SDK and not yet destroyed. +// - It may be null (no-op). After this call the handle must not be used again. void dash_sdk_destroy(struct dash_sdk_handle_t *handle) ; // Register global context provider callbacks @@ -1730,27 +2437,78 @@ extern "C" { struct DashSDKResult dash_sdk_create_with_callbacks(const struct DashSDKConfig *config, const struct ContextProviderCallbacks *callbacks) ; // Get the current network the SDK is connected to +// +// # Safety +// - `handle` must be a valid pointer to an SDKHandle (or null, in which case a default is returned). enum DashSDKNetwork dash_sdk_get_network(const struct dash_sdk_handle_t *handle) ; +// Add known contracts to the SDK's trusted context provider +// +// This allows pre-loading data contracts into the trusted provider's cache, +// avoiding network calls for these contracts. +// +// # Safety +// - `handle` must be a valid SDK handle created with dash_sdk_create_trusted +// - `contract_ids` must be a valid comma-separated list of contract IDs +// - `serialized_contracts` must be a valid pointer to an array of serialized contract data +// - `contract_lengths` must be a valid pointer to an array of contract data lengths +// - `contract_count` must match the actual number of contracts provided + struct DashSDKResult dash_sdk_add_known_contracts(const struct dash_sdk_handle_t *handle, const char *contract_ids, const uint8_t *const *serialized_contracts, const uintptr_t *contract_lengths, uintptr_t contract_count) ; + // Create a mock SDK instance with a dump directory (for offline testing) +// +// # Safety +// - `dump_dir` must be either null (no dumps) or a valid pointer to a NUL-terminated C string readable for the duration of the call. +// - The returned handle must be destroyed using the SDK destroy function to avoid leaks. struct dash_sdk_handle_t *dash_sdk_create_handle_with_mock(const char *dump_dir) ; -// Create a new iOS signer - struct SignerHandle *dash_sdk_signer_create(IOSSignCallback sign_callback, IOSCanSignCallback can_sign_callback) ; +// Create a new signer with callbacks from iOS/external code +// +// This creates a VTableSigner that can be used for all state transitions. +// The callbacks should handle the actual signing logic. +// +// # Parameters +// - `sign_callback`: Function to sign data +// - `can_sign_callback`: Function to check if can sign with a key +// - `destroy_callback`: Optional destructor (can be NULL) +// # Safety +// - Callback function pointers must be valid and follow the required ABI and lifetime for the duration of use. +// - The returned `SignerHandle` must be destroyed with `dash_sdk_signer_destroy` to avoid leaks. + struct SignerHandle *dash_sdk_signer_create(SignCallback sign_callback, CanSignCallback can_sign_callback, DestroyCallback destroy_callback) ; -// Destroy an iOS signer +// Destroy a signer +// # Safety +// - `handle` must be a valid pointer previously returned by this SDK and not yet destroyed. +// - It may be null (no-op). After this call the handle must not be used again. void dash_sdk_signer_destroy(struct SignerHandle *handle) ; -// Free bytes allocated by iOS callbacks +// Free bytes allocated by callbacks +// # Safety +// - `bytes` must be a pointer to a buffer allocated by the corresponding FFI and compatible with `libc::free`. +// - It may be null (no-op). After this call the pointer must not be used again. void dash_sdk_bytes_free(uint8_t *bytes) ; // Create a signer from a private key +// +// # Safety +// - `private_key` must be a valid pointer to at least 32 readable bytes. +// - The function reads exactly `private_key_len` bytes; it must be 32. +// - The returned handle inside DashSDKResult must be freed using the appropriate SDK destroy function. struct DashSDKResult dash_sdk_signer_create_from_private_key(const uint8_t *private_key, uintptr_t private_key_len) ; // Sign data with a signer +// +// # Safety +// - `signer_handle` must be a valid pointer obtained from this SDK and not previously destroyed. +// - `data` must be a valid pointer to `data_len` readable bytes. +// - The returned signature pointer inside DashSDKResult must be freed with `dash_sdk_signature_free`. struct DashSDKResult dash_sdk_signer_sign(struct SignerHandle *signer_handle, const uint8_t *data, uintptr_t data_len) ; // Free a signature +// +// # Safety +// - `signature` must be a valid pointer returned by this SDK, or null for no-op. +// - After this call the pointer must not be used again. void dash_sdk_signature_free(struct DashSDKSignature *signature) ; // Fetches information about current quorums @@ -1763,7 +2521,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - The function does not retain references to inputs beyond the call. +// - On success, returns a heap-allocated C string pointer; caller must free it using SDK routines. struct DashSDKResult dash_sdk_system_get_current_quorums_info(const struct dash_sdk_handle_t *sdk_handle) ; // Fetches information about multiple epochs @@ -1779,7 +2539,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `start_epoch` may be null (no explicit start); when non-null it must be a valid pointer to a NUL-terminated C string. +// - On success, returns a heap-allocated C string pointer; caller must free it using SDK routines. struct DashSDKResult dash_sdk_system_get_epochs_info(const struct dash_sdk_handle_t *sdk_handle, const char *start_epoch, uint32_t count, bool ascending) ; // Fetches path elements @@ -1794,10 +2556,15 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `path_json` and `keys_json` must be valid, non-null pointers to NUL-terminated C strings that remain valid for the duration of the call. +// - On success, returns a heap-allocated C string pointer; caller must free it using SDK routines. struct DashSDKResult dash_sdk_system_get_path_elements(const struct dash_sdk_handle_t *sdk_handle, const char *path_json, const char *keys_json) ; // Get platform status including block heights +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - The returned C string pointer (on success) must be freed by the caller using the SDK's free routine. struct DashSDKResult dash_sdk_get_platform_status(const struct dash_sdk_handle_t *sdk_handle) ; // Fetches a prefunded specialized balance @@ -1811,7 +2578,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `id` must be a valid, non-null pointer to a NUL-terminated C string that remains valid for the duration of the call. +// - On success, returns a heap-allocated C string pointer; caller must free it using SDK routines. struct DashSDKResult dash_sdk_system_get_prefunded_specialized_balance(const struct dash_sdk_handle_t *sdk_handle, const char *id) ; // Fetches the total credits in the platform @@ -1824,43 +2593,127 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - The function does not retain references to inputs beyond the call. +// - On success, returns a heap-allocated C string pointer; caller must free it using SDK routines. struct DashSDKResult dash_sdk_system_get_total_credits_in_platform(const struct dash_sdk_handle_t *sdk_handle) ; // Get SDK status including mode and quorum count +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - The returned C string pointer inside DashSDKResult (on success) must be freed by the caller +// using the SDK's free routine to avoid memory leaks. struct DashSDKResult dash_sdk_get_status(const struct dash_sdk_handle_t *sdk_handle) ; // Burn tokens from an identity and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory from the result using SDK free routines. struct DashSDKResult dash_sdk_token_burn(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenBurnParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Claim tokens from a distribution and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, and `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory in the result using SDK free routines. struct DashSDKResult dash_sdk_token_claim(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenClaimParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Mint tokens to an identity and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, and `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory in the result using SDK free routines. struct DashSDKResult dash_sdk_token_mint(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenMintParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Token transfer to another identity and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory in the result using SDK free routines. struct DashSDKResult dash_sdk_token_transfer(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenTransferParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Update token configuration and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory in the result using SDK free routines. struct DashSDKResult dash_sdk_token_update_contract_token_configuration(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenConfigUpdateParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Destroy frozen token funds and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - The function may allocate and return heap memory via the DashSDKResult; caller must free it using SDK free routines. struct DashSDKResult dash_sdk_token_destroy_frozen_funds(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenDestroyFrozenFundsParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Perform emergency action on token and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, `signer_handle` must be valid, non-null pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Returned pointers embedded in DashSDKResult must be freed by the caller using SDK free routines. struct DashSDKResult dash_sdk_token_emergency_action(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenEmergencyActionParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Freeze a token for an identity and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Any returned heap memory in the result must be freed by the caller using SDK free routines. struct DashSDKResult dash_sdk_token_freeze(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenFreezeParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Unfreeze a token for an identity and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, and `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory from the result using SDK free routines. struct DashSDKResult dash_sdk_token_unfreeze(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenFreezeParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Purchase tokens directly and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, and `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory in the result using SDK-provided free routines. struct DashSDKResult dash_sdk_token_purchase(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenPurchaseParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Set token price for direct purchase and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory in the result using SDK free routines. struct DashSDKResult dash_sdk_token_set_price(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenSetPriceParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Get identity token balances @@ -1874,6 +2727,10 @@ extern "C" { // // # Returns // JSON string containing token IDs mapped to their balances +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `identity_id` and `token_ids` must be valid pointers to NUL-terminated C strings and readable during the call. +// - The returned pointer (on success) must be freed using the SDK's free routine to avoid memory leaks. struct DashSDKResult dash_sdk_token_get_identity_balances(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, const char *token_ids) ; // Get token contract info @@ -1884,6 +2741,10 @@ extern "C" { // // # Returns // JSON string containing the contract ID and token position, or null if not found +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `token_id` must be a valid pointer to a NUL-terminated C string and readable during the call. +// - The returned C string pointer (on success) must be freed with the SDK's string-free function by the caller. struct DashSDKResult dash_sdk_token_get_contract_info(const struct dash_sdk_handle_t *sdk_handle, const char *token_id) ; // Get token direct purchase prices @@ -1894,17 +2755,25 @@ extern "C" { // // # Returns // JSON string containing token IDs mapped to their pricing information +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `token_ids` must be a valid pointer to a NUL-terminated C string and readable during the call. +// - The returned C string pointer (on success) must be freed by the caller using the SDK's free function. struct DashSDKResult dash_sdk_token_get_direct_purchase_prices(const struct dash_sdk_handle_t *sdk_handle, const char *token_ids) ; // Fetch token balances for multiple identities for a specific token // // # Parameters // - `sdk_handle`: SDK handle -// - `identity_ids`: Comma-separated list of Base58-encoded identity IDs +// - `identity_ids`: Either a comma-separated list OR a JSON array of Base58-encoded identity IDs // - `token_id`: Base58-encoded token ID // // # Returns // JSON string containing identity IDs mapped to their token balances +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `identity_ids` and `token_id` must be valid pointers to NUL-terminated C strings and readable during the call. +// - The returned C string pointer (on success) must be freed using the SDK's free function. struct DashSDKResult dash_sdk_identities_fetch_token_balances(const struct dash_sdk_handle_t *sdk_handle, const char *identity_ids, const char *token_id) ; // Fetch token information for multiple identities for a specific token @@ -1916,6 +2785,10 @@ extern "C" { // // # Returns // JSON string containing identity IDs mapped to their token information +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `identity_ids` and `token_id` must be valid pointers to NUL-terminated C strings and readable during the call. +// - The returned C string pointer (on success) must be freed with the SDK's free function. struct DashSDKResult dash_sdk_identities_fetch_token_infos(const struct dash_sdk_handle_t *sdk_handle, const char *identity_ids, const char *token_id) ; // Fetch token balances for a specific identity @@ -1927,6 +2800,10 @@ extern "C" { // // # Returns // JSON string containing token IDs mapped to their balances +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `identity_id` and `token_ids` must be valid pointers to NUL-terminated C strings and readable during the call. +// - The returned C string pointer (on success) must be freed using the SDK's free function to avoid leaks. struct DashSDKResult dash_sdk_identity_fetch_token_balances(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, const char *token_ids) ; // Fetch token information for a specific identity @@ -1938,6 +2815,10 @@ extern "C" { // // # Returns // JSON string containing token IDs mapped to their information +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `identity_id` and `token_ids` must be valid pointers to NUL-terminated C strings and readable during the call. +// - The returned C string pointer (on success) must be freed using the SDK's free function to avoid leaks. struct DashSDKResult dash_sdk_identity_fetch_token_infos(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, const char *token_ids) ; // Get identity token information @@ -1951,6 +2832,10 @@ extern "C" { // // # Returns // JSON string containing token IDs mapped to their information +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `identity_id` and `token_ids` must be valid pointers to NUL-terminated C strings and readable for the call duration. +// - The returned string pointer (on success) must be freed with the SDK's string free routine to avoid leaks. struct DashSDKResult dash_sdk_token_get_identity_infos(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, const char *token_ids) ; // Get token perpetual distribution last claim @@ -1962,6 +2847,10 @@ extern "C" { // // # Returns // JSON string containing the last claim information +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `token_id` and `identity_id` must be valid pointers to NUL-terminated C strings and readable during the call. +// - The returned C string pointer (on success) must be freed by the caller using the SDK's free function to avoid memory leaks. struct DashSDKResult dash_sdk_token_get_perpetual_distribution_last_claim(const struct dash_sdk_handle_t *sdk_handle, const char *token_id, const char *identity_id) ; // Get token statuses @@ -1972,6 +2861,10 @@ extern "C" { // // # Returns // JSON string containing token IDs mapped to their status information +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `token_ids` must be a valid pointer to a NUL-terminated C string containing comma-separated IDs. +// - The returned C string pointer (on success) must be freed by the caller using the SDK's free function. struct DashSDKResult dash_sdk_token_get_statuses(const struct dash_sdk_handle_t *sdk_handle, const char *token_ids) ; // Fetches the total supply of a token @@ -1988,140 +2881,97 @@ extern "C" { // This function is unsafe because it handles raw pointers from C struct DashSDKResult dash_sdk_token_get_total_supply(const struct dash_sdk_handle_t *sdk_handle, const char *token_id) ; -// Create a new empty transaction +// Free a string allocated by the FFI // -// # Returns -// - Pointer to FFITransaction on success -// - NULL on error - struct FFITransaction *dash_tx_create(void) ; +// # Safety +// - `s` must be a pointer returned by this SDK to a heap-allocated NUL-terminated C string. +// - Passing a pointer not allocated by this SDK, or a pointer already freed, results in undefined behavior. +// - `s` may be null, in which case this is a no-op. + void dash_sdk_string_free(char *s) ; -// Add an input to a transaction -// -// # Parameters -// - `tx`: The transaction -// - `input`: The input to add +// Free binary data allocated by the FFI // -// # Returns -// - 0 on success -// - -1 on error - int32_t dash_tx_add_input(struct FFITransaction *tx, const struct FFITxIn *input) ; +// # Safety +// - `binary_data` must be a valid pointer returned by this SDK and not previously freed. +// - When non-null, the function takes ownership and frees both the struct and its internal buffer. +// - Do not use `binary_data` after this call. + void dash_sdk_binary_data_free(struct DashSDKBinaryData *binary_data) ; -// Add an output to a transaction -// -// # Parameters -// - `tx`: The transaction -// - `output`: The output to add +// Free an identity info structure // -// # Returns -// - 0 on success -// - -1 on error - int32_t dash_tx_add_output(struct FFITransaction *tx, const struct FFITxOut *output) ; +// # Safety +// - `info` must be a valid pointer to `DashSDKIdentityInfo` allocated by this SDK. +// - It may be null (no-op). When non-null, this frees any owned strings and the struct. +// - Do not access `info` after this call. + void dash_sdk_identity_info_free(struct DashSDKIdentityInfo *info) ; -// Get the transaction ID -// -// # Parameters -// - `tx`: The transaction -// - `txid_out`: Buffer to write txid (must be 32 bytes) +// Free a document info structure // -// # Returns -// - 0 on success -// - -1 on error - int32_t dash_tx_get_txid(const struct FFITransaction *tx, uint8_t *txid_out) ; +// # Safety +// - `info` must be a valid pointer to `DashSDKDocumentInfo` allocated by this SDK and not already freed. +// - It may be null (no-op). When non-null, this frees all owned strings and arrays. +// - Pointer must not be dereferenced after this call. + void dash_sdk_document_info_free(struct DashSDKDocumentInfo *info) ; -// Serialize a transaction -// -// # Parameters -// - `tx`: The transaction -// - `out_buf`: Buffer to write serialized data (can be NULL to get size) -// - `out_len`: In/out parameter for buffer size +// Free an identity balance map // -// # Returns -// - 0 on success -// - -1 on error - int32_t dash_tx_serialize(const struct FFITransaction *tx, uint8_t *out_buf, uint32_t *out_len) ; +// # Safety +// - `map` must be a valid, non-dangling pointer returned by this SDK. +// - It may be null (no-op). When non-null, this frees the entries array and the struct. +// - Using `map` after this function returns is undefined behavior. + void dash_sdk_identity_balance_map_free(struct DashSDKIdentityBalanceMap *map) ; -// Deserialize a transaction +// Free a contender structure // -// # Parameters -// - `data`: The serialized transaction data -// - `len`: Length of the data -// -// # Returns -// - Pointer to FFITransaction on success -// - NULL on error - struct FFITransaction *dash_tx_deserialize(const uint8_t *data, uint32_t len) ; - -// Destroy a transaction - void dash_tx_destroy(struct FFITransaction *tx) ; +// # Safety +// - `contender` must be a valid, non-dangling pointer obtained from this FFI (e.g., via an SDK function). +// - It must either be null (a no-op) or point to a heap-allocated `DashSDKContender` that has not been freed yet. +// - After this call, the pointer must not be used again (use-after-free is undefined behavior). +// - This function will also free any heap-allocated strings owned by the structure. +// # Safety +// - `contender` must be a valid, non-null pointer to a `DashSDKContender` allocated by this SDK, or null for no-op. +// - The pointer must not be used after this call. + void dash_sdk_contender_free(struct DashSDKContender *contender) ; -// Calculate signature hash for an input -// -// # Parameters -// - `tx`: The transaction -// - `input_index`: Which input to sign -// - `script_pubkey`: The script pubkey of the output being spent -// - `script_pubkey_len`: Length of script pubkey -// - `sighash_type`: Signature hash type (usually 0x01 for SIGHASH_ALL) -// - `hash_out`: Buffer to write hash (must be 32 bytes) +// Free contest info structure // -// # Returns -// - 0 on success -// - -1 on error - int32_t dash_tx_sighash(const struct FFITransaction *tx, uint32_t input_index, const uint8_t *script_pubkey, uint32_t script_pubkey_len, uint32_t sighash_type, uint8_t *hash_out) ; +// # Safety +// - `info` must be a valid, non-dangling pointer obtained from this FFI and not previously freed. +// - It may be null (no-op). When non-null, this frees the owned contender array and contained strings. +// - Do not use `info` after this call; doing so is undefined behavior. + void dash_sdk_contest_info_free(struct DashSDKContestInfo *info) ; -// Sign a transaction input -// -// # Parameters -// - `tx`: The transaction -// - `input_index`: Which input to sign -// - `private_key`: The private key (32 bytes) -// - `script_pubkey`: The script pubkey of the output being spent -// - `script_pubkey_len`: Length of script pubkey -// - `sighash_type`: Signature hash type +// Free a contested name structure // -// # Returns -// - 0 on success -// - -1 on error - int32_t dash_tx_sign_input(struct FFITransaction *tx, uint32_t input_index, const uint8_t *private_key, const uint8_t *script_pubkey, uint32_t script_pubkey_len, uint32_t sighash_type) ; +// # Safety +// - `name` must be a valid, non-dangling pointer to a `DashSDKContestedName` allocated by this SDK. +// - It may be null (no-op). When non-null, this frees the embedded strings and contender buffers. +// - Do not access `name` after freeing. + void dash_sdk_contested_name_free(struct DashSDKContestedName *name) ; -// Create a P2PKH script pubkey +// Free a contested names list // -// # Parameters -// - `pubkey_hash`: The public key hash (20 bytes) -// - `out_buf`: Buffer to write script (can be NULL to get size) -// - `out_len`: In/out parameter for buffer size -// -// # Returns -// - 0 on success -// - -1 on error - int32_t dash_script_p2pkh(const uint8_t *pubkey_hash, uint8_t *out_buf, uint32_t *out_len) ; +// # Safety +// - `list` must be a valid pointer returned by this SDK and not previously freed. +// - It may be null (no-op). When non-null, this frees the array of names and any nested strings/buffers. +// - Do not use `list` after this call. + void dash_sdk_contested_names_list_free(struct DashSDKContestedNamesList *list) ; -// Extract public key hash from P2PKH address +// Free a name-timestamp structure // -// # Parameters -// - `address`: The address string -// - `network`: The expected network -// - `hash_out`: Buffer to write hash (must be 20 bytes) -// -// # Returns -// - 0 on success -// - -1 on error - int32_t dash_address_to_pubkey_hash(const char *address, enum FFIKeyNetwork network, uint8_t *hash_out) ; - -// Free a string allocated by the FFI - void dash_sdk_string_free(char *s) ; - -// Free binary data allocated by the FFI - void dash_sdk_binary_data_free(struct DashSDKBinaryData *binary_data) ; - -// Free an identity info structure - void dash_sdk_identity_info_free(struct DashSDKIdentityInfo *info) ; - -// Free a document info structure - void dash_sdk_document_info_free(struct DashSDKDocumentInfo *info) ; +// # Safety +// - `entry` must be a valid, non-dangling pointer to a `DashSDKNameTimestamp` allocated by this SDK. +// - It may be null (no-op). When non-null, this frees the owned string and the struct. +// - Do not use `entry` after this call. + void dash_sdk_name_timestamp_free(struct DashSDKNameTimestamp *entry) ; -// Free an identity balance map - void dash_sdk_identity_balance_map_free(struct DashSDKIdentityBalanceMap *map) ; +// Free a name-timestamp list +// +// # Safety +// - `list` must be a valid pointer to a `DashSDKNameTimestampList` allocated by this SDK. +// - It may be null (no-op). When non-null, this frees the entries array and contained strings. +// - Pointer must not be used after this call. + void dash_sdk_name_timestamp_list_free(struct DashSDKNameTimestampList *list) ; // Initialize the unified SDK system // This initializes both Core SDK (if enabled) and Platform SDK @@ -2155,7 +3005,7 @@ extern "C" { // // # Safety // - `handle` must be a valid unified SDK handle - struct FFIDashSpvClient *dash_unified_sdk_get_core_client(struct UnifiedSDKHandle *handle) ; + FFIDashSpvClient *dash_unified_sdk_get_core_client(struct UnifiedSDKHandle *handle) ; // Get the Platform SDK from a unified handle // @@ -2204,6 +3054,11 @@ extern "C" { // # Returns // - Base58 encoded string on success // - Error if the hex string is invalid +// # Safety +// - `hex_string` must be a valid, non-null pointer to a NUL-terminated C string. +// - The memory pointed to by `hex_string` must be readable for the duration of the call. +// - The returned pointer (on success) must be freed by calling the appropriate free function +// (e.g., `dash_sdk_string_free`) from this SDK to avoid memory leaks. struct DashSDKResult dash_sdk_utils_hex_to_base58(const char *hex_string) ; // Convert a base58 string to hex @@ -2214,6 +3069,10 @@ extern "C" { // # Returns // - Hex encoded string on success // - Error if the base58 string is invalid +// # Safety +// - `base58_string` must be a valid, non-null pointer to a NUL-terminated C string. +// - The memory pointed to by `base58_string` must be readable for the duration of the call. +// - The returned C string pointer (on success) must be freed with the SDK's string free routine to avoid leaks. struct DashSDKResult dash_sdk_utils_base58_to_hex(const char *base58_string) ; // Validate if a string is valid base58 @@ -2223,6 +3082,9 @@ extern "C" { // // # Returns // - 1 if valid base58, 0 if invalid +// # Safety +// - `string` must be a valid, non-null pointer to a NUL-terminated C string. +// - The memory pointed to by `string` must be readable for the duration of the call. uint8_t dash_sdk_utils_is_valid_base58(const char *string) ; // Fetches vote polls by end date diff --git a/packages/rs-sdk-ffi/test_header.h b/packages/rs-sdk-ffi/test_header.h index d900e052065..44bb71e89e4 100644 --- a/packages/rs-sdk-ffi/test_header.h +++ b/packages/rs-sdk-ffi/test_header.h @@ -3,7 +3,7 @@ #pragma once -/* Generated with cbindgen:0.29.0 */ +/* Generated with cbindgen:0.29.2 */ /* This file is auto-generated. Do not modify manually. */ @@ -13,20 +13,27 @@ #include #include #include +#include "dash_spv_ffi.h" -// Authorized action takers for token operations -typedef enum DashSDKAuthorizedActionTakers { - // No one can perform the action - DashSDKAuthorizedActionTakers_NoOne = 0, - // Only the contract owner can perform the action - DashSDKAuthorizedActionTakers_AuthorizedContractOwner = 1, - // Main group can perform the action - DashSDKAuthorizedActionTakers_MainGroup = 2, - // A specific identity (requires identity_id to be set) - DashSDKAuthorizedActionTakers_Identity = 3, - // A specific group (requires group_position to be set) - DashSDKAuthorizedActionTakers_Group = 4, -} DashSDKAuthorizedActionTakers; +// Result data type indicator for iOS +typedef enum DashSDKResultDataType { + // No data (void/null) + DashSDKResultDataType_NoData = 0, + // C string (char*) + DashSDKResultDataType_String = 1, + // Binary data with length + DashSDKResultDataType_BinaryData = 2, + // Identity handle + DashSDKResultDataType_ResultIdentityHandle = 3, + // Document handle + DashSDKResultDataType_ResultDocumentHandle = 4, + // Data contract handle + DashSDKResultDataType_ResultDataContractHandle = 5, + // Map of identity IDs to balances + DashSDKResultDataType_IdentityBalanceMap = 6, + // Public key handle + DashSDKResultDataType_ResultPublicKeyHandle = 7, +} DashSDKResultDataType; // Error codes returned by FFI functions typedef enum DashSDKErrorCode { @@ -64,35 +71,50 @@ typedef enum DashSDKGasFeesPaidBy { DashSDKGasFeesPaidBy_GasFeesPreferContractOwner = 2, } DashSDKGasFeesPaidBy; +// Document field value types +typedef enum DashSDKDocumentFieldType { + DashSDKDocumentFieldType_FieldString = 0, + DashSDKDocumentFieldType_FieldInteger = 1, + DashSDKDocumentFieldType_FieldFloat = 2, + DashSDKDocumentFieldType_FieldBoolean = 3, + DashSDKDocumentFieldType_FieldBytes = 4, + DashSDKDocumentFieldType_FieldArray = 5, + DashSDKDocumentFieldType_FieldObject = 6, + DashSDKDocumentFieldType_FieldNull = 7, +} DashSDKDocumentFieldType; + +// State transition type for key selection +typedef enum StateTransitionType { + StateTransitionType_IdentityUpdate = 0, + StateTransitionType_IdentityTopUp = 1, + StateTransitionType_IdentityCreditTransfer = 2, + StateTransitionType_IdentityCreditWithdrawal = 3, + StateTransitionType_DocumentsBatch = 4, + StateTransitionType_DataContractCreate = 5, + StateTransitionType_DataContractUpdate = 6, +} StateTransitionType; + // Network type for SDK configuration typedef enum DashSDKNetwork { // Mainnet - DashSDKNetwork_Mainnet = 0, + DashSDKNetwork_SDKMainnet = 0, // Testnet - DashSDKNetwork_Testnet = 1, + DashSDKNetwork_SDKTestnet = 1, + // Regtest + DashSDKNetwork_SDKRegtest = 2, // Devnet - DashSDKNetwork_Devnet = 2, + DashSDKNetwork_SDKDevnet = 3, // Local development network - DashSDKNetwork_Local = 3, + DashSDKNetwork_SDKLocal = 4, } DashSDKNetwork; -// Result data type indicator for iOS -typedef enum DashSDKResultDataType { - // No data (void/null) - DashSDKResultDataType_None = 0, - // C string (char*) - DashSDKResultDataType_String = 1, - // Binary data with length - DashSDKResultDataType_BinaryData = 2, - // Identity handle - DashSDKResultDataType_ResultIdentityHandle = 3, - // Document handle - DashSDKResultDataType_ResultDocumentHandle = 4, - // Data contract handle - DashSDKResultDataType_ResultDataContractHandle = 5, - // Map of identity IDs to balances - DashSDKResultDataType_IdentityBalanceMap = 6, -} DashSDKResultDataType; +// Token distribution type for claim operations +typedef enum DashSDKTokenDistributionType { + // Pre-programmed distribution + DashSDKTokenDistributionType_PreProgrammed = 0, + // Perpetual distribution + DashSDKTokenDistributionType_Perpetual = 1, +} DashSDKTokenDistributionType; // Token configuration update type typedef enum DashSDKTokenConfigUpdateType { @@ -116,13 +138,19 @@ typedef enum DashSDKTokenConfigUpdateType { DashSDKTokenConfigUpdateType_MainControlGroup = 8, } DashSDKTokenConfigUpdateType; -// Token distribution type for claim operations -typedef enum DashSDKTokenDistributionType { - // Pre-programmed distribution - DashSDKTokenDistributionType_PreProgrammed = 0, - // Perpetual distribution - DashSDKTokenDistributionType_Perpetual = 1, -} DashSDKTokenDistributionType; +// Authorized action takers for token operations +typedef enum DashSDKAuthorizedActionTakers { + // No one can perform the action + DashSDKAuthorizedActionTakers_NoOne = 0, + // Only the contract owner can perform the action + DashSDKAuthorizedActionTakers_AuthorizedContractOwner = 1, + // Main group can perform the action + DashSDKAuthorizedActionTakers_MainGroup = 2, + // A specific identity (requires identity_id to be set) + DashSDKAuthorizedActionTakers_Identity = 3, + // A specific group (requires group_position to be set) + DashSDKAuthorizedActionTakers_Group = 4, +} DashSDKAuthorizedActionTakers; // Token emergency action type typedef enum DashSDKTokenEmergencyAction { @@ -158,6 +186,170 @@ typedef struct dash_sdk_handle_t dash_sdk_handle_t; // Opaque handle to a Signer typedef struct SignerHandle SignerHandle; +// A found address with its balance (FFI-compatible) +typedef struct DashSDKFoundAddress { + // The derivation index for this address + uint32_t index; + // Pointer to the address key bytes + uint8_t *key; + // Length of the key in bytes + uintptr_t key_len; + // Nonce associated with this address + uint32_t nonce; + // Balance in credits at this address + uint64_t balance; +} DashSDKFoundAddress; + +// An address proven absent from the tree (FFI-compatible) +typedef struct DashSDKAbsentAddress { + // The derivation index for this address + uint32_t index; + // Pointer to the address key bytes + uint8_t *key; + // Length of the key in bytes + uintptr_t key_len; +} DashSDKAbsentAddress; + +// Metrics about the synchronization process (FFI-compatible) +typedef struct DashSDKAddressSyncMetrics { + // Number of trunk queries (always 1 for a successful sync) + uint32_t trunk_queries; + // Number of branch queries + uint32_t branch_queries; + // Total elements seen across all proofs. + // + // This gives an indication of the "anonymity set" - how many addresses + // were potentially being queried from the server's perspective. + uint32_t total_elements_seen; + // Total proof bytes received + uint32_t total_proof_bytes; + // Number of iterations (0 = trunk only, 1+ = trunk plus branch rounds) + uint32_t iterations; +} DashSDKAddressSyncMetrics; + +// Result of address synchronization (FFI-compatible) +typedef struct DashSDKAddressSyncResult { + // Array of found addresses with balances + struct DashSDKFoundAddress *found; + // Number of found addresses + uintptr_t found_count; + // Array of addresses proven absent + struct DashSDKAbsentAddress *absent; + // Number of absent addresses + uintptr_t absent_count; + // Highest found index (for HD wallets) + // Only valid if has_highest_found_index is true + uint32_t highest_found_index; + // Whether highest_found_index is valid + bool has_highest_found_index; + // Metrics about the sync process + struct DashSDKAddressSyncMetrics metrics; +} DashSDKAddressSyncResult; + +// Function pointer type for getting the gap limit +typedef uint32_t (*GetGapLimitFn)(void *context); + +// A pending address entry for the provider callback +typedef struct DashSDKPendingAddress { + // The derivation index for this address + uint32_t index; + // Pointer to the address key bytes (32 bytes) + const uint8_t *key; + // Length of the key in bytes + uintptr_t key_len; +} DashSDKPendingAddress; + +// List of pending addresses returned by the provider callback +typedef struct DashSDKPendingAddressList { + // Array of pending addresses + struct DashSDKPendingAddress *addresses; + // Number of addresses + uintptr_t count; +} DashSDKPendingAddressList; + +// Function pointer type for getting pending addresses +// +// Returns a list of pending addresses that need to be synchronized. +// The returned list must remain valid until the next call to this function +// or until the sync operation completes. +typedef struct DashSDKPendingAddressList (*GetPendingAddressesFn)(void *context); + +// Function pointer type for handling a found address +// +// Called when an address is found in the tree with a balance and nonce. +typedef void (*OnAddressFoundFn)(void *context, uint32_t index, const uint8_t *key, uintptr_t key_len, uint32_t nonce, uint64_t balance); + +// Function pointer type for handling an absent address +// +// Called when an address is proven absent from the tree. +typedef void (*OnAddressAbsentFn)(void *context, uint32_t index, const uint8_t *key, uintptr_t key_len); + +// Optional function pointer type for checking if there are pending addresses. +// Nullable — may be null (cbindgen translates this to a nullable C function pointer). +typedef bool (*OptionalHasPendingFn)(void *context); + +// Optional function pointer type for getting the highest found index. +// Nullable — may be null (cbindgen translates this to a nullable C function pointer). +typedef uint32_t (*OptionalGetHighestFoundIndexFn)(void *context); + +// Optional destructor for cleanup. +// Nullable — may be null (cbindgen translates this to a nullable C function pointer). +typedef void (*OptionalDestroyProviderFn)(void *context); + +// VTable for address provider callbacks +typedef struct AddressProviderVTable { + // Get the gap limit for this provider + GetGapLimitFn gap_limit; + // Get currently pending addresses to synchronize + GetPendingAddressesFn pending_addresses; + // Called when an address is found with a balance + OnAddressFoundFn on_address_found; + // Called when an address is proven absent + OnAddressAbsentFn on_address_absent; + // Check if there are still pending addresses. + // May be null; if null the default implementation (pending_addresses is non-empty) is used. + OptionalHasPendingFn has_pending; + // Get the highest found index. + // May be null; if null returns None. + OptionalGetHighestFoundIndexFn highest_found_index; + // Optional destructor for cleanup. May be null. + OptionalDestroyProviderFn destroy; +} AddressProviderVTable; + +// FFI-compatible address provider using callbacks +typedef struct AddressProviderFFI { + // Opaque context pointer passed to all callbacks + void *context; + // Pointer to the vtable containing callback functions + const struct AddressProviderVTable *vtable; +} AddressProviderFFI; + +// Configuration for address synchronization (FFI-compatible) +typedef struct DashSDKAddressSyncConfig { + // Minimum privacy count - subtrees smaller than this will be expanded + // to include ancestor subtrees for better privacy. + // + // Higher values provide better privacy but may increase the number of + // elements returned per query. + // + // Default: 32 + uint64_t min_privacy_count; + // Maximum concurrent branch queries. + // + // Higher values can speed up synchronization but increase memory usage + // and network load. + // + // Default: 10 + uint32_t max_concurrent_requests; + // Maximum number of iterations (safety limit). + // + // The sync process iterates until all addresses are resolved. This limit + // prevents infinite loops in case of unexpected behavior. + // + // Default: 50 + uint32_t max_iterations; +} DashSDKAddressSyncConfig; + // Error structure returned by FFI functions typedef struct DashSDKError { // Error code @@ -182,16 +374,6 @@ typedef struct ContextProviderHandle { uint8_t private_[0]; } ContextProviderHandle; -typedef struct FFIDashSpvClient { - uint8_t opaque[0]; -} FFIDashSpvClient; - -// Handle for Core SDK that can be passed to Platform SDK -// This matches the definition from dash_spv_ffi.h -typedef struct CoreSDKHandle { - struct FFIDashSpvClient *client; -} CoreSDKHandle; - // Result type for FFI callbacks typedef struct CallbackResult { bool success; @@ -215,18 +397,56 @@ typedef struct ContextProviderCallbacks { GetQuorumPublicKeyFn get_quorum_public_key; } ContextProviderCallbacks; +// Result structure for data contract fetch with serialization +typedef struct DashSDKDataContractFetchResult { + // Handle to the data contract (null on error or if not requested) + struct DataContractHandle *contract_handle; + // JSON representation of the contract (null on error or if not requested) + char *json_string; + // Serialized contract bytes (null on error or if not requested) + uint8_t *serialized_data; + // Length of serialized data + uintptr_t serialized_data_len; + // Error information (null on success) + struct DashSDKError *error; +} DashSDKDataContractFetchResult; + // Document creation parameters typedef struct DashSDKDocumentCreateParams { - // Data contract handle - const struct DataContractHandle *data_contract_handle; + // Data contract ID (base58 encoded) + const char *data_contract_id; // Document type name const char *document_type; - // Owner identity handle - const struct IdentityHandle *owner_identity_handle; + // Owner identity ID (base58 encoded) + const char *owner_identity_id; // JSON string of document properties const char *properties_json; } DashSDKDocumentCreateParams; +// Document creation result containing handle and entropy +typedef struct DashSDKDocumentCreateResult { + // Handle to the created document + struct DocumentHandle *document_handle; + // Entropy used for document ID generation (32 bytes) + uint8_t entropy[32]; +} DashSDKDocumentCreateResult; + +// Document handle creation parameters +typedef struct DashSDKDocumentHandleParams { + // Document ID (base58 encoded) + const char *id; + // Data contract ID (base58 encoded) + const char *data_contract_id; + // Document type name + const char *document_type; + // Owner identity ID (base58 encoded) + const char *owner_identity_id; + // JSON string of document properties + const char *properties_json; + // Optional revision number (0 means no revision) + uint64_t revision; +} DashSDKDocumentHandleParams; + // Token payment information for transactions typedef struct DashSDKTokenPaymentInfo { // Payment token contract ID (32 bytes), null for same contract @@ -277,6 +497,23 @@ typedef struct DashSDKStateTransitionCreationOptions { uint16_t base_feature_version; } DashSDKStateTransitionCreationOptions; +// Document field value +typedef struct DashSDKDocumentField { + // Field name (null-terminated) + char *name; + // Field type + enum DashSDKDocumentFieldType field_type; + // Field value as string representation (null-terminated) + // For complex types, this will be JSON-encoded + char *value; + // Raw integer value (for Integer type) + int64_t int_value; + // Raw float value (for Float type) + double float_value; + // Raw boolean value (for Boolean type) + bool bool_value; +} DashSDKDocumentField; + // Document information typedef struct DashSDKDocumentInfo { // Document ID as hex string (null-terminated) @@ -293,6 +530,10 @@ typedef struct DashSDKDocumentInfo { int64_t created_at; // Updated at timestamp (milliseconds since epoch) int64_t updated_at; + // Number of data fields + uintptr_t data_fields_count; + // Array of data fields + struct DashSDKDocumentField *data_fields; } DashSDKDocumentInfo; // Document search parameters @@ -311,6 +552,92 @@ typedef struct DashSDKDocumentSearchParams { uint32_t start_at; } DashSDKDocumentSearchParams; +// Represents a simple name to timestamp mapping +typedef struct DashSDKNameTimestamp { + // The name + char *name; + // End timestamp in milliseconds + uint64_t end_time; +} DashSDKNameTimestamp; + +// Represents a list of name-timestamp pairs +typedef struct DashSDKNameTimestampList { + // Array of name-timestamp pairs + struct DashSDKNameTimestamp *entries; + // Number of entries + uintptr_t count; +} DashSDKNameTimestampList; + +// Represents a contender in a contested DPNS name +typedef struct DashSDKContender { + // Identity ID of the contender (base58 string) + char *identity_id; + // Vote count for this contender + uint32_t vote_count; +} DashSDKContender; + +// Represents contest information for a DPNS name +typedef struct DashSDKContestInfo { + // Array of contenders + struct DashSDKContender *contenders; + // Number of contenders + uintptr_t contender_count; + // Abstain vote tally (0 if none) + uint32_t abstain_votes; + // Lock vote tally (0 if none) + uint32_t lock_votes; + // End time in milliseconds since epoch + uint64_t end_time; + // Whether there is a winner + bool has_winner; +} DashSDKContestInfo; + +// Represents a contested DPNS name entry +typedef struct DashSDKContestedName { + // The contested name + char *name; + // Contest information + struct DashSDKContestInfo contest_info; +} DashSDKContestedName; + +// Represents a list of contested names +typedef struct DashSDKContestedNamesList { + // Array of contested names + struct DashSDKContestedName *names; + // Number of names + uintptr_t count; +} DashSDKContestedNamesList; + +// Result structure for DPNS registration +typedef struct DpnsRegistrationResult { + // JSON representation of the preorder document + char *preorder_document_json; + // JSON representation of the domain document + char *domain_document_json; + // The full domain name (e.g., "alice.dash") + char *full_domain_name; +} DpnsRegistrationResult; + +// Public key data for creating identity +typedef struct DashSDKPublicKeyData { + // Key ID (0-255) + uint8_t id; + // Key purpose (0-6) + uint8_t purpose; + // Security level (0-3) + uint8_t security_level; + // Key type (0-4) + uint8_t key_type; + // Whether key is read-only + bool read_only; + // Public key data pointer + const uint8_t *data; + // Public key data length + uintptr_t data_len; + // Disabled timestamp (0 if not disabled) + uint64_t disabled_at; +} DashSDKPublicKeyData; + // Identity information typedef struct DashSDKIdentityInfo { // Identity ID as hex string (null-terminated) @@ -346,6 +673,12 @@ typedef struct DashSDKConfig { uint64_t request_timeout_ms; } DashSDKConfig; +// Handle for Core SDK that can be passed to Platform SDK +// This matches the definition from dash_spv_ffi.h +typedef struct CoreSDKHandle { + void *client; +} CoreSDKHandle; + // Extended SDK configuration with context provider support typedef struct DashSDKConfigExtended { // Base SDK configuration @@ -356,13 +689,23 @@ typedef struct DashSDKConfigExtended { struct CoreSDKHandle *core_sdk_handle; } DashSDKConfigExtended; -// Function pointer type for iOS signing callback +// Function pointer type for signing callback from iOS/external code // Returns pointer to allocated byte array (caller must free with dash_sdk_bytes_free) // Returns null on error -typedef uint8_t *(*IOSSignCallback)(const uint8_t *identity_public_key_bytes, uintptr_t identity_public_key_len, const uint8_t *data, uintptr_t data_len, uintptr_t *result_len); +typedef uint8_t *(*SignCallback)(const void *signer, const uint8_t *identity_public_key_bytes, uintptr_t identity_public_key_len, const uint8_t *data, uintptr_t data_len, uintptr_t *result_len); -// Function pointer type for iOS can_sign_with callback -typedef bool (*IOSCanSignCallback)(const uint8_t *identity_public_key_bytes, uintptr_t identity_public_key_len); +// Function pointer type for can_sign_with callback from iOS/external code +typedef bool (*CanSignCallback)(const void *signer, const uint8_t *identity_public_key_bytes, uintptr_t identity_public_key_len); + +// Function pointer type for destructor callback +// This is an Option to allow for NULL pointers from C +typedef void (*DestroyCallback)(void *signer); + +// Signature result structure +typedef struct DashSDKSignature { + uint8_t *signature; + uintptr_t signature_len; +} DashSDKSignature; // Token burn parameters typedef struct DashSDKTokenBurnParams { @@ -582,7 +925,7 @@ typedef struct DashSDKIdentityBalanceMap { // Unified SDK handle containing both Core and Platform SDKs typedef struct UnifiedSDKHandle { - CoreSDKClient *core_client; + FFIDashSpvClient *core_client; struct dash_sdk_handle_t *platform_sdk; bool integration_enabled; } UnifiedSDKHandle; @@ -590,7 +933,7 @@ typedef struct UnifiedSDKHandle { // Unified SDK configuration combining both Core and Platform settings typedef struct UnifiedSDKConfig { // Core SDK configuration (ignored if core feature disabled) - CoreSDKConfig core_config; + const FFIClientConfig *core_config; // Platform SDK configuration struct DashSDKConfig platform_config; // Whether to enable cross-layer integration @@ -605,9 +948,88 @@ extern "C" { // This should be called once at app startup before using any other functions. void dash_sdk_init(void) ; +// Enable logging with the specified level +// Level values: 0 = Error, 1 = Warn, 2 = Info, 3 = Debug, 4 = Trace + void dash_sdk_enable_logging(uint8_t level) ; + // Get the version of the Dash SDK FFI library const char *dash_sdk_version(void) ; +// Synchronize address balances using trunk/branch chunk queries. +// +// This function discovers address balances for addresses supplied by the provider, +// using privacy-preserving chunk queries. It supports HD wallet gap limit behavior +// where finding a used address extends the search range. +// +// # Safety +// - `sdk_handle` must be a valid SDK handle created by this SDK +// - `provider` must be a valid pointer to an AddressProviderFFI structure +// - `config` may be null (uses defaults) or a valid pointer to DashSDKAddressSyncConfig +// - The returned result must be freed with `dash_sdk_address_sync_result_free` + struct DashSDKAddressSyncResult *dash_sdk_sync_address_balances(const struct dash_sdk_handle_t *sdk_handle, struct AddressProviderFFI *provider, const struct DashSDKAddressSyncConfig *config) ; + +// Synchronize address balances and return result with error information. +// +// This is an alternative version that returns a DashSDKResult for better error handling. +// +// # Safety +// - `sdk_handle` must be a valid SDK handle created by this SDK +// - `provider` must be a valid pointer to an AddressProviderFFI structure +// - `config` may be null (uses defaults) or a valid pointer to DashSDKAddressSyncConfig + struct DashSDKResult dash_sdk_sync_address_balances_with_result(const struct dash_sdk_handle_t *sdk_handle, struct AddressProviderFFI *provider, const struct DashSDKAddressSyncConfig *config) ; + +// Free an address sync result +// +// # Safety +// - `result` must be a valid pointer returned by `dash_sdk_sync_address_balances` +// or null (no-op) +// - After this call, the result must not be used again + void dash_sdk_address_sync_result_free(struct DashSDKAddressSyncResult *result) ; + +// Create an address provider with callbacks +// +// This creates an FFI-compatible address provider that uses callbacks +// for all operations. +// +// # Safety +// - `vtable` must be a valid pointer to an AddressProviderVTable structure +// - `context` is an opaque pointer that will be passed to all callbacks +// - The returned provider must be freed with `dash_sdk_address_provider_free` + struct AddressProviderFFI *dash_sdk_address_provider_create(const struct AddressProviderVTable *vtable, void *context) ; + +// Free an address provider +// +// # Safety +// - `provider` must be a valid pointer returned by `dash_sdk_address_provider_create` +// or null (no-op) +// - After this call, the provider must not be used again + void dash_sdk_address_provider_free(struct AddressProviderFFI *provider) ; + +// Get the total balance from a sync result +// +// # Safety +// - `result` must be a valid pointer to a DashSDKAddressSyncResult + uint64_t dash_sdk_address_sync_result_total_balance(const struct DashSDKAddressSyncResult *result) ; + +// Get the count of addresses with non-zero balance +// +// # Safety +// - `result` must be a valid pointer to a DashSDKAddressSyncResult + uintptr_t dash_sdk_address_sync_result_non_zero_count(const struct DashSDKAddressSyncResult *result) ; + +// Free a pending address list +// +// This should be called to clean up memory after the sync operation is complete +// if the caller allocated the list dynamically. +// +// Note: This only frees the list structure, not the key data which should be +// managed by the caller. +// +// # Safety +// - `list` must be a valid pointer to a DashSDKPendingAddressList +// or null (no-op) + void dash_sdk_pending_address_list_free(struct DashSDKPendingAddressList *list) ; + // Register Core SDK handle and setup callback bridge with Platform SDK // // This function implements the core pattern from dash-unified-ffi-old: @@ -646,7 +1068,12 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `identity_id` must be a valid, non-null pointer to a NUL-terminated C string that remains valid during the call. +// - `limit`, `offset`, and `order_ascending` are passed by value; no references are retained. +// - On success, the returned `DashSDKResult` may contain a heap-allocated C string; the caller must free +// it using the SDK's free routine. The result can also contain no data (null pointer). +// - All pointers provided to this function must be readable and valid. struct DashSDKResult dash_sdk_contested_resource_get_identity_votes(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, uint32_t limit, uint32_t offset, bool order_ascending) ; // Fetches contested resources @@ -666,7 +1093,14 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - All C string pointers (`contract_id`, `document_type_name`, `index_name`, +// `start_index_values_json`, `end_index_values_json`) must be either null (when documented as optional) +// or valid pointers to NUL-terminated strings that remain valid for the duration of the call. +// - The function reads the `count` and `order_ascending` by value and does not retain references. +// - On success, the returned `DashSDKResult` may contain a heap-allocated C string; the caller must +// free it using the SDK-provided free routine. The result can also contain no data (null pointer). +// - All pointers passed in must point to readable memory; behavior is undefined if they are dangling. struct DashSDKResult dash_sdk_contested_resource_get_resources(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, const char *document_type_name, const char *index_name, const char *start_index_values_json, const char *end_index_values_json, uint32_t count, bool order_ascending) ; // Fetches contested resource vote state @@ -686,7 +1120,13 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - All C string pointers (`contract_id`, `document_type_name`, `index_name`, `index_values_json`) +// must be valid, non-null pointers to NUL-terminated strings that remain valid for the duration of the call. +// - `result_type` and `allow_include_locked_and_abstaining_vote_tally` are passed by value. +// - The returned result may contain a heap-allocated C string which must be freed by the caller using +// the SDK's free routine. It may also contain no data (null pointer) on success. +// - All pointers must point to readable memory; passing invalid or dangling pointers results in undefined behavior. struct DashSDKResult dash_sdk_contested_resource_get_vote_state(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, const char *document_type_name, const char *index_name, const char *index_values_json, uint8_t result_type, bool allow_include_locked_and_abstaining_vote_tally, uint32_t count) ; // Fetches voters for a contested resource identity @@ -706,18 +1146,15 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - All C string pointers (`contract_id`, `document_type_name`, `index_name`, `index_values_json`, `contestant_id`) +// must be valid, non-null pointers to NUL-terminated strings that remain valid for the duration of the call. +// - The function reads `count` and `order_ascending` by value and does not retain references. +// - On success, the returned `DashSDKResult` may contain a heap-allocated C string; the caller must +// free it using the SDK-provided free routine. The result can also contain no data (null pointer). +// - All pointers must reference readable memory; passing invalid pointers leads to undefined behavior. struct DashSDKResult dash_sdk_contested_resource_get_voters_for_identity(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, const char *document_type_name, const char *index_name, const char *index_values_json, const char *contestant_id, uint32_t count, bool order_ascending) ; -// Create a context provider from a Core SDK handle (DEPRECATED) -// -// This function is deprecated. Use dash_sdk_context_provider_from_callbacks instead. -// -// # Safety -// - `core_handle` must be a valid Core SDK handle -// - String parameters must be valid UTF-8 C strings or null - struct ContextProviderHandle *dash_sdk_context_provider_from_core(struct CoreSDKHandle *core_handle, const char *core_rpc_url, const char *core_rpc_user, const char *core_rpc_password) ; - // Create a context provider from callbacks // // # Safety @@ -730,145 +1167,89 @@ extern "C" { // - `handle` must be a valid context provider handle or null void dash_sdk_context_provider_destroy(struct ContextProviderHandle *handle) ; -// Initialize the Core SDK -// Returns 0 on success, error code on failure - int32_t dash_core_sdk_init(void) ; - -// Create a Core SDK client with testnet config -// -// # Safety -// - Returns null on failure - CoreSDKClient *dash_core_sdk_create_client_testnet(void) ; - -// Create a Core SDK client with mainnet config -// -// # Safety -// - Returns null on failure - CoreSDKClient *dash_core_sdk_create_client_mainnet(void) ; - -// Create a Core SDK client with custom config -// -// # Safety -// - `config` must be a valid CoreSDKConfig pointer -// - Returns null on failure - CoreSDKClient *dash_core_sdk_create_client(const CoreSDKConfig *config) ; - -// Destroy a Core SDK client -// -// # Safety -// - `client` must be a valid Core SDK client handle or null - void dash_core_sdk_destroy_client(CoreSDKClient *client) ; - -// Start the Core SDK client (begin sync) -// -// # Safety -// - `client` must be a valid Core SDK client handle - int32_t dash_core_sdk_start(CoreSDKClient *client) ; - -// Stop the Core SDK client +// Validate that a private key corresponds to a public key using DPP's public_key_data_from_private_key_data // // # Safety -// - `client` must be a valid Core SDK client handle - int32_t dash_core_sdk_stop(CoreSDKClient *client) ; +// - `private_key_hex` and `public_key_hex` must be valid, non-null pointers to NUL-terminated C strings that +// remain valid for the duration of the call. +// - `key_type` and `is_testnet` are passed by value; no references are retained. +// - On success, the returned `DashSDKResult` contains a heap-allocated C string pointer which must be freed using +// the SDK's free routine. It may also return no data (null pointer) to indicate success without payload. +// - Passing invalid or dangling pointers results in undefined behavior. + struct DashSDKResult dash_sdk_validate_private_key_for_public_key(const char *private_key_hex, const char *public_key_hex, uint8_t key_type, bool is_testnet) ; -// Sync Core SDK client to tip +// Convert private key to WIF format // // # Safety -// - `client` must be a valid Core SDK client handle - int32_t dash_core_sdk_sync_to_tip(CoreSDKClient *client) ; +// - `private_key_hex` must be a valid, non-null pointer to a NUL-terminated C string representing a 32-byte hex key +// and remain valid for the duration of the call. +// - `is_testnet` is passed by value. +// - On success, the returned `DashSDKResult` contains a heap-allocated C string pointer which must be freed using +// the SDK's free routine. + struct DashSDKResult dash_sdk_private_key_to_wif(const char *private_key_hex, bool is_testnet) ; -// Get the current sync progress +// Get public key data from private key data // // # Safety -// - `client` must be a valid Core SDK client handle -// - Returns pointer to FFISyncProgress structure (caller must free it) - FFISyncProgress *dash_core_sdk_get_sync_progress(CoreSDKClient *client) ; +// - `private_key_hex` must be a valid, non-null pointer to a NUL-terminated C string representing a 32-byte hex key +// and remain valid for the duration of the call. +// - `key_type` and `is_testnet` are passed by value; no references are retained. +// - On success, the returned `DashSDKResult` contains a heap-allocated C string pointer which must be freed using +// the SDK's free routine. + struct DashSDKResult dash_sdk_public_key_data_from_private_key_data(const char *private_key_hex, uint8_t key_type, bool is_testnet) ; -// Get Core SDK statistics -// -// # Safety -// - `client` must be a valid Core SDK client handle -// - Returns pointer to FFISpvStats structure (caller must free it) - FFISpvStats *dash_core_sdk_get_stats(CoreSDKClient *client) ; - -// Get the current block height -// -// # Safety -// - `client` must be a valid Core SDK client handle -// - `height` must point to a valid u32 - int32_t dash_core_sdk_get_block_height(CoreSDKClient *client, uint32_t *height) ; - -// Add an address to watch +// Create a new data contract // // # Safety -// - `client` must be a valid Core SDK client handle -// - `address` must be a valid null-terminated C string - int32_t dash_core_sdk_watch_address(CoreSDKClient *client, const char *address) ; +// - `sdk_handle`, `owner_identity_handle`, and `documents_schema_json` must be valid, non-null pointers. +// - `documents_schema_json` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. + struct DashSDKResult dash_sdk_data_contract_create(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *owner_identity_handle, const char *documents_schema_json) ; -// Remove an address from watching +// Destroy a data contract handle // // # Safety -// - `client` must be a valid Core SDK client handle -// - `address` must be a valid null-terminated C string - int32_t dash_core_sdk_unwatch_address(CoreSDKClient *client, const char *address) ; +// - `handle` must be a pointer previously returned by this SDK or null (no-op). +// - After this call, `handle` becomes invalid and must not be used again. + void dash_sdk_data_contract_destroy(struct DataContractHandle *handle) ; -// Get balance for all watched addresses +// Put data contract to platform (broadcast state transition) // // # Safety -// - `client` must be a valid Core SDK client handle -// - Returns pointer to FFIBalance structure (caller must free it) - FFIBalance *dash_core_sdk_get_total_balance(CoreSDKClient *client) ; +// - `sdk_handle`, `data_contract_handle`, `identity_public_key_handle`, and `signer_handle` must be valid, non-null pointers. +// - On success, returns serialized data; any heap memory inside the result must be freed using SDK routines. + struct DashSDKResult dash_sdk_data_contract_put_to_platform(struct dash_sdk_handle_t *sdk_handle, const struct DataContractHandle *data_contract_handle, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle) ; -// Get platform activation height +// Put data contract to platform and wait for confirmation (broadcast state transition and wait for response) // // # Safety -// - `client` must be a valid Core SDK client handle -// - `height` must point to a valid u32 - int32_t dash_core_sdk_get_platform_activation_height(CoreSDKClient *client, uint32_t *height) ; +// - Same requirements as `dash_sdk_data_contract_put_to_platform`. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. + struct DashSDKResult dash_sdk_data_contract_put_to_platform_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DataContractHandle *data_contract_handle, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle) ; -// Get quorum public key +// Fetch a data contract by ID // // # Safety -// - `client` must be a valid Core SDK client handle -// - `quorum_hash` must point to a valid 32-byte buffer -// - `public_key` must point to a valid 48-byte buffer - int32_t dash_core_sdk_get_quorum_public_key(CoreSDKClient *client, uint32_t quorum_type, const uint8_t *quorum_hash, uint32_t core_chain_locked_height, uint8_t *public_key, uintptr_t public_key_size) ; +// - `sdk_handle` and `contract_id` must be valid, non-null pointers. +// - `contract_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. + struct DashSDKResult dash_sdk_data_contract_fetch(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id) ; -// Get Core SDK handle for platform integration +// Fetch a data contract by ID and return as JSON // // # Safety -// - `client` must be a valid Core SDK client handle - struct CoreSDKHandle *dash_core_sdk_get_core_handle(CoreSDKClient *client) ; +// - `sdk_handle` and `contract_id` must be valid, non-null pointers. +// - `contract_id` must point to a NUL-terminated C string that remains valid for the duration of the call. +// - On success, returns a heap-allocated C string pointer inside `DashSDKResult`; caller must free it using SDK routines. + struct DashSDKResult dash_sdk_data_contract_fetch_json(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id) ; -// Broadcast a transaction +// Fetch multiple data contracts by their IDs // // # Safety -// - `client` must be a valid Core SDK client handle -// - `transaction_hex` must be a valid null-terminated C string - int32_t dash_core_sdk_broadcast_transaction(CoreSDKClient *client, const char *transaction_hex) ; - -// Check if Core SDK feature is enabled at runtime - bool dash_core_sdk_is_enabled(void) ; - -// Get Core SDK version - const char *dash_core_sdk_version(void) ; - -// Create a new data contract - struct DashSDKResult dash_sdk_data_contract_create(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *owner_identity_handle, const char *documents_schema_json) ; - -// Destroy a data contract handle - void dash_sdk_data_contract_destroy(struct DataContractHandle *handle) ; - -// Put data contract to platform (broadcast state transition) - struct DashSDKResult dash_sdk_data_contract_put_to_platform(struct dash_sdk_handle_t *sdk_handle, const struct DataContractHandle *data_contract_handle, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle) ; - -// Put data contract to platform and wait for confirmation (broadcast state transition and wait for response) - struct DashSDKResult dash_sdk_data_contract_put_to_platform_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DataContractHandle *data_contract_handle, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle) ; - -// Fetch a data contract by ID - struct DashSDKResult dash_sdk_data_contract_fetch(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id) ; - -// Fetch multiple data contracts by their IDs +// - `sdk_handle` and `contract_ids` must be valid, non-null pointers. +// - `contract_ids` must point to a NUL-terminated C string containing either a JSON array of Base58 IDs or a comma-separated list; it must remain valid for the duration of the call. +// - On success, returns a heap-allocated C string pointer inside `DashSDKResult`; caller must free it using SDK routines. // // # Parameters // - `sdk_handle`: SDK handle @@ -878,6 +1259,22 @@ extern "C" { // JSON string containing contract IDs mapped to their data contracts struct DashSDKResult dash_sdk_data_contracts_fetch_many(const struct dash_sdk_handle_t *sdk_handle, const char *contract_ids) ; +// Fetch a data contract by ID with serialization +// +// # Safety +// - `sdk_handle` and `contract_id` must be valid, non-null pointers. +// - `contract_id` must point to a NUL-terminated C string valid for the duration of the call. +// - The returned result contains heap-allocated buffers/handles depending on flags; caller must free them using +// `dash_sdk_data_contract_fetch_result_free`. + struct DashSDKDataContractFetchResult dash_sdk_data_contract_fetch_with_serialization(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, bool return_json, bool return_serialized) ; + +// Free the memory allocated for a data contract fetch result +// +// # Safety +// - `result` must be a pointer previously returned by this SDK or null (no-op). +// - After this call, `result` and all contained pointers become invalid and must not be used again. + void dash_sdk_data_contract_fetch_result_free(struct DashSDKDataContractFetchResult *result) ; + // Fetch data contract history // // # Parameters @@ -889,52 +1286,169 @@ extern "C" { // // # Returns // JSON string containing the data contract history +// +// # Safety +// - `sdk_handle` and `contract_id` must be valid, non-null pointers. +// - `contract_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a heap-allocated C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_data_contract_fetch_history(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, unsigned int limit, unsigned int offset, uint64_t start_at_ms) ; // Get schema for a specific document type +// +// # Safety +// - `contract_handle` and `document_type` must be valid, non-null pointers. +// - `document_type` must point to a NUL-terminated C string valid for the duration of the call. +// - Returns a heap-allocated C string pointer on success; caller must free it using SDK routines. char *dash_sdk_data_contract_get_schema(const struct DataContractHandle *contract_handle, const char *document_type) ; // Create a new document +// +// # Safety +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `params` must be a valid, non-null pointer to a `DashSDKDocumentCreateParams` structure. +// - All C string fields inside `params` (`data_contract_id`, `document_type`, `owner_identity_id`, `properties_json`) +// must be valid pointers to NUL-terminated strings and remain valid for the duration of the call. +// - On success, the returned `DashSDKResult` contains a heap-allocated handle which must be freed by the caller +// using the appropriate SDK destroy function. +// - Passing dangling or invalid pointers results in undefined behavior. struct DashSDKResult dash_sdk_document_create(struct dash_sdk_handle_t *sdk_handle, const struct DashSDKDocumentCreateParams *params) ; +// Free a document creation result +// +// # Safety +// - `result` must be either null (no-op) or a pointer previously returned by this SDK. +// - After this call, `result` becomes invalid and must not be used again. + void dash_sdk_document_create_result_free(struct DashSDKDocumentCreateResult *result) ; + +// Create a document handle from parameters +// This creates a Document object directly without broadcasting to the network +// +// # Safety +// - `params` must be a valid, non-null pointer to a `DashSDKDocumentHandleParams` structure. +// - All C string fields inside `params` must be valid pointers to NUL-terminated strings and remain valid +// for the duration of the call. +// - On success, the returned `DashSDKResult` contains a heap-allocated `DocumentHandle` which must be freed by the caller +// using the appropriate SDK destroy function. +// - Passing dangling or invalid pointers results in undefined behavior. + struct DashSDKResult dash_sdk_document_make_handle(const struct DashSDKDocumentHandleParams *params) ; + // Delete a document from the platform - struct DashSDKResult dash_sdk_document_delete(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `document_id`, `owner_id`, `data_contract_id`, and `document_type_name` must be valid, non-null pointers to +// NUL-terminated C strings that remain valid for the duration of the call. +// - `identity_public_key_handle` and `signer_handle` must be valid, non-null pointers to initialized structures. +// - Optional pointers (`token_payment_info`, `put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_delete(struct dash_sdk_handle_t *sdk_handle, const char *document_id, const char *owner_id, const char *data_contract_id, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Delete a document from the platform and wait for confirmation - struct DashSDKResult dash_sdk_document_delete_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - Same requirements as `dash_sdk_document_delete` regarding pointer validity and lifetimes. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_delete_and_wait(struct dash_sdk_handle_t *sdk_handle, const char *document_id, const char *owner_id, const char *data_contract_id, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Update document price (broadcast state transition) - struct DashSDKResult dash_sdk_document_update_price_of_document(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, uint64_t price, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `document_handle`, `data_contract_id`, `document_type_name`, `identity_public_key_handle`, and `signer_handle` +// must be valid, non-null pointers. `data_contract_id` and `document_type_name` must point to NUL-terminated C strings. +// - Optional pointers (`token_payment_info`, `put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_update_price_of_document(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, uint64_t price, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Update document price and wait for confirmation (broadcast state transition and wait for response) - struct DashSDKResult dash_sdk_document_update_price_of_document_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, uint64_t price, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - Same requirements as `dash_sdk_document_update_price_of_document` regarding pointer validity and lifetimes. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_update_price_of_document_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, uint64_t price, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Purchase document (broadcast state transition) - struct DashSDKResult dash_sdk_document_purchase(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, uint64_t price, const char *purchaser_id, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `document_handle`, `data_contract_id`, `document_type_name`, `purchaser_id`, `identity_public_key_handle`, and `signer_handle` +// must be valid, non-null pointers. All C string pointers must point to NUL-terminated strings. +// - Optional pointers (`token_payment_info`, `put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_purchase(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, uint64_t price, const char *purchaser_id, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Purchase document and wait for confirmation (broadcast state transition and wait for response) - struct DashSDKResult dash_sdk_document_purchase_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, uint64_t price, const char *purchaser_id, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - Same requirements as `dash_sdk_document_purchase` regarding pointer validity and lifetimes. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_purchase_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, uint64_t price, const char *purchaser_id, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Put document to platform (broadcast state transition) - struct DashSDKResult dash_sdk_document_put_to_platform(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const uint8_t (*entropy)[32], const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `document_handle`, `data_contract_id`, `document_type_name`, `entropy`, `identity_public_key_handle`, and `signer_handle` +// must be valid, non-null pointers. `data_contract_id` and `document_type_name` must point to NUL-terminated C strings. +// - Optional pointers (`token_payment_info`, `put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. +// - All pointers must reference readable memory for the duration of the call. + struct DashSDKResult dash_sdk_document_put_to_platform(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, const uint8_t (*entropy)[32], const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Put document to platform and wait for confirmation (broadcast state transition and wait for response) - struct DashSDKResult dash_sdk_document_put_to_platform_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const uint8_t (*entropy)[32], const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - Same requirements as `dash_sdk_document_put_to_platform` regarding pointer validity and lifetimes. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_put_to_platform_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, const uint8_t (*entropy)[32], const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; -// Fetch a document by ID +// Fetch a document by ID using contract ID (gets contract from trusted provider) + struct DashSDKResult dash_sdk_document_fetch_by_contract_id(struct dash_sdk_handle_t *sdk_handle, const char *contract_id, const char *document_type, const char *document_id) ; + +// Fetch a document by ID (legacy - requires data contract handle) +// +// # Safety +// - `sdk_handle`, `data_contract_handle`, `document_type`, and `document_id` must be valid, non-null pointers. +// - `document_type` and `document_id` must point to NUL-terminated C strings valid for the duration of the call. +// - On success, returns a handle or no data; any heap memory must be freed using SDK routines. struct DashSDKResult dash_sdk_document_fetch(const struct dash_sdk_handle_t *sdk_handle, const struct DataContractHandle *data_contract_handle, const char *document_type, const char *document_id) ; // Get document information +// +// # Safety +// - `document_handle` must be a valid, non-null pointer to a `DocumentHandle` that remains valid for the duration of the call. +// - Returns a heap-allocated `DashSDKDocumentInfo` pointer on success; caller must free it using the SDK-provided free function. struct DashSDKDocumentInfo *dash_sdk_document_get_info(const struct DocumentHandle *document_handle) ; // Search for documents +// +// # Safety +// - `sdk_handle` and `params` must be valid, non-null pointers. +// - All C string pointers inside `params` must point to NUL-terminated strings and remain valid for the duration of the call; optional strings may be null. +// - On success, returns a heap-allocated C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_document_search(const struct dash_sdk_handle_t *sdk_handle, const struct DashSDKDocumentSearchParams *params) ; // Replace document on platform (broadcast state transition) - struct DashSDKResult dash_sdk_document_replace_on_platform(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `document_handle`, `data_contract_id`, `document_type_name`, `identity_public_key_handle`, and `signer_handle` +// must be valid, non-null pointers. `data_contract_id` and `document_type_name` must point to NUL-terminated C strings. +// - Optional pointers (`token_payment_info`, `put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_replace_on_platform(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Replace document on platform and wait for confirmation (broadcast state transition and wait for response) - struct DashSDKResult dash_sdk_document_replace_on_platform_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - Same requirements as `dash_sdk_document_replace_on_platform` regarding pointer validity and lifetimes. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_replace_on_platform_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *data_contract_id, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Transfer document to another identity // @@ -950,7 +1464,13 @@ extern "C" { // // # Returns // Serialized state transition on success - struct DashSDKResult dash_sdk_document_transfer_to_identity(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *recipient_id, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - `sdk_handle`, `document_handle`, `recipient_id`, `data_contract_id`, `document_type_name`, `identity_public_key_handle`, and `signer_handle` must be valid, non-null pointers. +// - All C string pointers must point to NUL-terminated strings valid for the duration of the call. +// - Optional pointers (`token_payment_info`, `put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - On success, any heap memory in the result must be freed using SDK routines. + struct DashSDKResult dash_sdk_document_transfer_to_identity(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *recipient_id, const char *data_contract_id, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Transfer document to another identity and wait for confirmation // @@ -966,21 +1486,254 @@ extern "C" { // // # Returns // Handle to the transferred document on success - struct DashSDKResult dash_sdk_document_transfer_to_identity_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *recipient_id, const struct DataContractHandle *data_contract_handle, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; +// +// # Safety +// - Same requirements as `dash_sdk_document_transfer_to_identity` regarding pointer validity and lifetimes. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, the result may contain heap-allocated data that must be freed using SDK-provided routines. + struct DashSDKResult dash_sdk_document_transfer_to_identity_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct DocumentHandle *document_handle, const char *recipient_id, const char *data_contract_id, const char *document_type_name, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKTokenPaymentInfo *token_payment_info, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Destroy a document +// +// # Safety +// - `sdk_handle` and `document_handle` must be valid, non-null pointers. +// - Returns a pointer to an error structure on failure; caller must free with `dash_sdk_error_free`. struct DashSDKError *dash_sdk_document_destroy(struct dash_sdk_handle_t *sdk_handle, struct DocumentHandle *document_handle) ; // Destroy a document handle +// +// # Safety +// - `handle` must be a pointer previously returned by this SDK or null (no-op). +// - After this call, `handle` becomes invalid and must not be used again. void dash_sdk_document_handle_destroy(struct DocumentHandle *handle) ; -// Free an error message - void dash_sdk_error_free(struct DashSDKError *error) ; +// Free a document handle (alias for destroy) +// +// # Safety +// - Same as `dash_sdk_document_handle_destroy`. + void dash_sdk_document_free(struct DocumentHandle *handle) ; -// Fetches proposed epoch blocks by evonode IDs +// Set document properties from JSON // -// # Parameters -// * `sdk_handle` - Handle to the SDK instance +// # Safety +// - `document_handle` and `properties_json` must be valid, non-null pointers. +// - `properties_json` must point to a NUL-terminated C string valid for the duration of the call. +// - Returns an error pointer on failure; caller must free with `dash_sdk_error_free`. + struct DashSDKError *dash_sdk_document_set_properties(struct DocumentHandle *document_handle, const char *properties_json) ; + +// Convert a string to homograph-safe characters by replacing 'o', 'i', and 'l' +// with '0', '1', and '1' respectively to prevent homograph attacks +// +// # Safety +// - `name` must be a valid null-terminated C string + struct DashSDKResult dash_sdk_dpns_normalize_username(const char *name) ; + +// Check if a username is valid according to DPNS rules +// +// A username is valid if: +// - It's between 3 and 63 characters long +// - It starts and ends with alphanumeric characters (a-zA-Z0-9) +// - It contains only alphanumeric characters and hyphens +// - It doesn't have consecutive hyphens +// +// # Safety +// - `name` must be a valid null-terminated C string +// +// # Returns +// - 1 if the username is valid +// - 0 if the username is invalid +// - -1 if there's an error + int32_t dash_sdk_dpns_is_valid_username(const char *name) ; + +// Check if a username is contested (requires masternode voting) +// +// A username is contested if its normalized label: +// - Is between 3 and 19 characters long (inclusive) +// - Contains only lowercase letters a-z, digits 0-1, and hyphens +// +// # Safety +// - `name` must be a valid null-terminated C string +// +// # Returns +// - 1 if the username is contested +// - 0 if the username is not contested +// - -1 if there's an error + int32_t dash_sdk_dpns_is_contested_username(const char *name) ; + +// Get a validation message for a username +// +// Returns a descriptive message about why a username is invalid, or "valid" if it's valid. +// +// # Safety +// - `name` must be a valid null-terminated C string + struct DashSDKResult dash_sdk_dpns_get_validation_message(const char *name) ; + +// Check if a DPNS username is available +// +// This function checks if a given username is available for registration. +// It also validates the username format and checks if it's contested. +// +// # Arguments +// * `sdk_handle` - Handle to the SDK instance +// * `label` - The username label to check (e.g., "alice") +// +// # Returns +// * On success: A JSON object with availability information +// * On error: An error result +// +// # Safety +// - `sdk_handle` and `label` must be valid, non-null pointers. +// - `label` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. + struct DashSDKResult dash_sdk_dpns_check_availability(const struct dash_sdk_handle_t *sdk_handle, const char *label) ; + +// Get all contested DPNS usernames where an identity is a contender +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. + struct DashSDKResult dash_sdk_dpns_get_contested_usernames_by_identity(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, uint32_t limit) ; + +// Get the vote state for a contested DPNS username +// +// # Safety +// This function is unsafe because it operates on raw pointers + struct DashSDKResult dash_sdk_dpns_get_contested_vote_state(const struct dash_sdk_handle_t *sdk_handle, const char *label, uint32_t limit) ; + +// Get all contested DPNS usernames +// +// # Safety +// This function is unsafe because it operates on raw pointers + struct DashSDKResult dash_sdk_dpns_get_all_contested_usernames(const struct dash_sdk_handle_t *sdk_handle, uint32_t limit, const char *start_after) ; + +// Get current DPNS contests (active vote polls) +// +// Returns a list of contested DPNS names with their end times. +// The caller is responsible for freeing the result with `dash_sdk_name_timestamp_list_free`. +// +// # Safety +// This function is unsafe because it operates on raw pointers + struct DashSDKNameTimestampList *dash_sdk_dpns_get_current_contests(const struct dash_sdk_handle_t *sdk_handle, uint64_t start_time, uint64_t end_time, uint16_t limit) ; + +// Get all contested DPNS usernames that an identity has voted on +// +// # Safety +// This function is unsafe because it operates on raw pointers + struct DashSDKResult dash_sdk_dpns_get_identity_votes(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, uint32_t limit, uint16_t offset) ; + +// Get non-resolved DPNS contests for a specific identity +// +// Returns a list of contested but unresolved DPNS usernames where the identity is a contender. +// The caller is responsible for freeing the result with `dash_sdk_contested_names_list_free`. +// +// # Safety +// This function is unsafe because it operates on raw pointers + struct DashSDKContestedNamesList *dash_sdk_dpns_get_non_resolved_contests_for_identity(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, uint32_t limit) ; + +// Get contested DPNS usernames that are not yet resolved +// +// Returns a list of contested but unresolved DPNS usernames with their contest information. +// The caller is responsible for freeing the result with `dash_sdk_contested_names_list_free`. +// +// # Safety +// This function is unsafe because it operates on raw pointers + struct DashSDKContestedNamesList *dash_sdk_dpns_get_contested_non_resolved_usernames(const struct dash_sdk_handle_t *sdk_handle, uint32_t limit) ; + +// Resolve a DPNS name to an identity ID +// +// This function resolves a DPNS username to its associated identity ID. +// The name can be either: +// - A full domain name (e.g., "alice.dash") +// - Just the label (e.g., "alice") +// +// # Arguments +// * `sdk_handle` - Handle to the SDK instance +// * `name` - The DPNS name to resolve +// +// # Returns +// * On success: A JSON object with the identity ID, or null if not found +// * On error: An error result +// +// # Safety +// - `sdk_handle` and `name` must be valid, non-null pointers. +// - `name` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. + struct DashSDKResult dash_sdk_dpns_resolve(const struct dash_sdk_handle_t *sdk_handle, const char *name) ; + +// Search for DPNS names that start with a given prefix +// +// This function searches for DPNS usernames that start with the given prefix. +// +// # Arguments +// * `sdk_handle` - Handle to the SDK instance +// * `prefix` - The prefix to search for (e.g., "ali" to find "alice", "alicia", etc.) +// * `limit` - Maximum number of results to return (0 for default of 10) +// +// # Returns +// * On success: A JSON array of username objects +// * On error: An error result +// +// # Safety +// - `sdk_handle` and `prefix` must be valid, non-null pointers. +// - `prefix` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. + struct DashSDKResult dash_sdk_dpns_search(const struct dash_sdk_handle_t *sdk_handle, const char *prefix, uint32_t limit) ; + +// Get DPNS usernames owned by an identity +// +// This function returns all DPNS usernames associated with a given identity ID. +// It checks for domains where the identity is: +// - The owner of the domain document +// - Listed in records.dashUniqueIdentityId +// - Listed in records.dashAliasIdentityId +// +// # Arguments +// * `sdk_handle` - Handle to the SDK instance +// * `identity_id` - The identity ID to search for (base58 string) +// * `limit` - Maximum number of results to return (0 for default of 10) +// +// # Returns +// * On success: A JSON array of username objects +// * On error: An error result +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. + struct DashSDKResult dash_sdk_dpns_get_usernames(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, uint32_t limit) ; + +// Register a DPNS username in a single operation +// +// This method handles both the preorder and domain registration steps automatically. +// It generates the necessary entropy, creates both documents, and submits them in order. +// +// # Safety +// - `handle` must be a valid, non-null SDK handle pointer. +// - `label` must be a valid pointer to a NUL-terminated C string that remains valid for the duration of the call. +// - `identity`, `identity_public_key`, and `signer` must be valid handles (as raw pointers) obtained from this SDK and not previously freed; they are not consumed by this call. +// +// # Returns +// Returns a DpnsRegistrationResult containing both created documents and the full domain name + struct DashSDKResult dash_sdk_dpns_register_name(const struct dash_sdk_handle_t *handle, const char *label, const void *identity, const void *identity_public_key, const void *signer) ; + +// Free a DPNS registration result +// +// # Safety +// - `result` must be a valid DpnsRegistrationResult pointer created by dash_sdk_dpns_register_name + void dash_sdk_dpns_registration_result_free(struct DpnsRegistrationResult *result) ; + +// Free an error message +// +// # Safety +// - `error` must be a pointer previously returned by this SDK or null (no-op). +// - After this call, `error` becomes invalid and must not be used again. + void dash_sdk_error_free(struct DashSDKError *error) ; + +// Fetches proposed epoch blocks by evonode IDs +// +// # Parameters +// * `sdk_handle` - Handle to the SDK instance // * `epoch` - Epoch number (optional, 0 for current epoch) // * `ids_json` - JSON array of hex-encoded evonode pro_tx_hash IDs // @@ -989,7 +1742,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` and `ids_json` must be valid pointers; `ids_json` must point to a NUL-terminated C string with a JSON array of hex IDs. +// - Pointers must remain valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_evonode_get_proposed_epoch_blocks_by_ids(const struct dash_sdk_handle_t *sdk_handle, uint32_t epoch, const char *ids_json) ; // Fetches proposed epoch blocks by range @@ -1006,7 +1761,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer. +// - `start_after` and `start_at` may be null; when non-null they must point to NUL-terminated C strings with hex-encoded 32-byte hashes. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_evonode_get_proposed_epoch_blocks_by_range(const struct dash_sdk_handle_t *sdk_handle, uint32_t epoch, uint32_t limit, const char *start_after, const char *start_at) ; // Fetches group action signers @@ -1023,7 +1780,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle`, `contract_id`, and `action_id` must be valid, non-null pointers. +// - `contract_id` and `action_id` must point to NUL-terminated C strings valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_group_get_action_signers(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, uint16_t group_contract_position, uint8_t status, const char *action_id) ; // Fetches group actions @@ -1041,7 +1800,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` and `contract_id` must be valid, non-null pointers. +// - `contract_id` must point to a NUL-terminated C string; `start_at_action_id` may be null, otherwise must be a valid NUL-terminated C string. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_group_get_actions(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, uint16_t group_contract_position, uint8_t status, const char *start_at_action_id, uint16_t limit) ; // Fetches information about a group @@ -1056,7 +1817,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` and `contract_id` must be valid, non-null pointers. +// - `contract_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_group_get_info(const struct dash_sdk_handle_t *sdk_handle, const char *contract_id, uint16_t group_contract_position) ; // Fetches information about multiple groups @@ -1071,23 +1834,200 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer. +// - `start_at_position` may be null; when non-null it must point to a NUL-terminated C string representing a number. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_group_get_infos(const struct dash_sdk_handle_t *sdk_handle, const char *start_at_position, uint32_t limit) ; // Create a new identity +// +// # Safety +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - On success, the returned `DashSDKResult` contains a heap-allocated handle that must be freed using the +// appropriate SDK destroy function. +// - Passing a dangling or invalid pointer results in undefined behavior. struct DashSDKResult dash_sdk_identity_create(struct dash_sdk_handle_t *sdk_handle) ; +// Create an identity handle from components +// +// This function creates an identity handle from basic components without +// requiring JSON serialization/deserialization. +// +// # Parameters +// - `identity_id`: 32-byte identity ID +// - `public_keys`: Array of public key data +// - `public_keys_count`: Number of public keys in the array +// - `balance`: Identity balance in credits +// - `revision`: Identity revision number +// +// # Returns +// - Handle to the created identity on success +// - Error if creation fails +// +// # Safety +// - `identity_id` must be a valid pointer to 32 readable bytes. +// - If `public_keys_count > 0`, `public_keys` must be a valid pointer to an array of `DashSDKPublicKeyData` +// structures of length `public_keys_count`; each `data` field in the array must point to at least `data_len` readable bytes. +// - All pointers must remain valid for the duration of the call. +// - On success, returns a heap-allocated handle; caller must destroy it using the SDK's destroy function. + struct DashSDKResult dash_sdk_identity_create_from_components(const uint8_t *identity_id, const struct DashSDKPublicKeyData *public_keys, uintptr_t public_keys_count, uint64_t balance, uint64_t revision) ; + +// Get a public key from an identity by its ID +// +// # Parameters +// - `identity`: Handle to the identity +// - `key_id`: The ID of the public key to retrieve +// +// # Returns +// - Handle to the public key on success +// - Error if key not found or invalid parameters +// +// # Safety +// - `identity` must be a valid, non-null pointer to an `IdentityHandle` that remains valid for the duration of the call. +// - On success, the returned `DashSDKResult` contains a heap-allocated handle which must be destroyed with the SDK's +// corresponding destroy function. +// - Passing invalid or dangling pointers results in undefined behavior. + struct DashSDKResult dash_sdk_identity_get_public_key_by_id(const struct IdentityHandle *identity, uint8_t key_id) ; + // Get identity information +// +// # Safety +// - `identity_handle` must be a valid, non-null pointer to an `IdentityHandle` that remains valid for the duration of the call. +// - Returns a heap-allocated `DashSDKIdentityInfo` pointer; caller must free it using the SDK-provided destroy function. +// - Passing invalid or dangling pointers results in undefined behavior. struct DashSDKIdentityInfo *dash_sdk_identity_get_info(const struct IdentityHandle *identity_handle) ; // Destroy an identity handle +// +// # Safety +// - `handle` must be a pointer previously returned by this SDK or null (no-op). +// - After this call, `handle` becomes invalid and must not be used again. void dash_sdk_identity_destroy(struct IdentityHandle *handle) ; +// Get the appropriate signing key for a state transition +// +// This function finds a key that meets the purpose and security level requirements +// for the specified state transition type. +// +// # Parameters +// - `identity_handle`: Handle to the identity +// - `transition_type`: Type of state transition to be signed +// +// # Returns +// - Handle to the identity public key on success +// - Error if no suitable key is found +// +// # Safety +// - `identity_handle` must be a valid, non-null pointer to an `IdentityHandle` that remains valid for the duration of the call. +// - On success, the returned `DashSDKResult` contains a heap-allocated handle which must be destroyed with the SDK's +// corresponding destroy function. +// - Passing invalid or dangling pointers results in undefined behavior. + struct DashSDKResult dash_sdk_identity_get_signing_key_for_transition(const struct IdentityHandle *identity_handle, enum StateTransitionType transition_type) ; + +// Get the private key data for a transfer key +// +// This function retrieves the private key data that corresponds to the +// lowest security level transfer key. In a real implementation, this would +// interface with a secure key storage system. +// +// # Parameters +// - `identity_handle`: Handle to the identity +// - `key_index`: The key index from the identity public key +// +// # Returns +// - 32-byte private key data on success +// - Error if key not found or not accessible +// +// # Safety +// - `identity_handle` must be a valid, non-null pointer to an `IdentityHandle`. +// - This function returns its result inside `DashSDKResult`; any heap pointers within must be freed using SDK routines. +// - Passing invalid or dangling pointers results in undefined behavior. + struct DashSDKResult dash_sdk_identity_get_transfer_private_key(const struct IdentityHandle *identity_handle, uint32_t key_index) ; + +// Get the key ID from an identity public key +// +// # Safety +// - `key_handle` must be a valid, non-null pointer to an `IdentityPublicKeyHandle`. +// - Returns 0 if the pointer is null. + uint32_t dash_sdk_identity_public_key_get_id(const struct IdentityPublicKeyHandle *key_handle) ; + +// Create an identity public key handle from key data +// +// This function creates an identity public key handle from the raw key data +// without needing to fetch the identity from the network. +// +// # Parameters +// - `key_id`: The key ID +// - `key_type`: The key type (0 = ECDSA_SECP256K1, 1 = BLS12_381, 2 = ECDSA_HASH160, 3 = BIP13_SCRIPT_HASH, 4 = ED25519_HASH160) +// - `purpose`: The key purpose (0 = Authentication, 1 = Encryption, 2 = Decryption, 3 = Transfer, 4 = SystemTransfer, 5 = Voting) +// - `security_level`: The security level (0 = Master, 1 = Critical, 2 = High, 3 = Medium) +// - `public_key_data`: The public key data +// - `public_key_data_len`: Length of the public key data +// - `read_only`: Whether the key is read-only +// - `disabled_at`: Optional timestamp when the key was disabled (0 if not disabled) +// +// # Returns +// - Handle to the identity public key on success +// - Error if parameters are invalid +// +// # Safety +// - `public_key_data` must be a valid, non-null pointer to a buffer of `public_key_data_len` readable bytes. +// - All scalar parameters are passed by value. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. +// - Passing invalid or dangling pointers results in undefined behavior. + struct DashSDKResult dash_sdk_identity_public_key_create_from_data(uint32_t key_id, uint8_t key_type, uint8_t purpose, uint8_t security_level, const uint8_t *public_key_data, uintptr_t public_key_data_len, bool read_only, uint64_t disabled_at) ; + +// Serialize an identity public key to bytes +// Returns the serialized bytes and their length +// +// # Safety +// - `key_handle` must be a valid, non-null pointer to an `IdentityPublicKeyHandle`. +// - `out_bytes` and `out_len` must be valid, non-null pointers to writable memory. +// - Caller must free the returned buffer with the appropriate SDK-provided free function. + struct DashSDKResult dash_sdk_identity_public_key_to_bytes(const struct IdentityPublicKeyHandle *key_handle, uint8_t **out_bytes, uintptr_t *out_len) ; + +// Free an identity public key handle +// +// # Safety +// - `handle` must be a pointer previously returned by this SDK or null (no-op). +// - After this call, `handle` becomes invalid and must not be used again. + void dash_sdk_identity_public_key_destroy(struct IdentityPublicKeyHandle *handle) ; + // Register a name for an identity +// +// # Safety +// - `_sdk_handle` and `_identity_handle` must be valid pointers when used; currently this stub ignores them. +// - `_name` must be a valid pointer to a NUL-terminated C string if used in the future. +// - Returns a heap-allocated error pointer; caller must free it using `dash_sdk_error_free`. struct DashSDKError *dash_sdk_identity_register_name(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *identity_handle, const char *name) ; +// Parse an identity from JSON string to handle +// +// This function takes a JSON string representation of an identity +// (as returned by dash_sdk_identity_fetch) and converts it to an +// identity handle that can be used with other FFI functions. +// +// # Parameters +// - `json_str`: JSON string containing the identity data +// +// # Returns +// - Handle to the parsed identity on success +// - Error if JSON parsing fails +// +// # Safety +// - `json_str` must be a valid, non-null pointer to a NUL-terminated C string and remain valid for the duration of the call. +// - On success, the returned `DashSDKResult` contains a heap-allocated handle which must be freed using the +// appropriate SDK destroy function to avoid leaks. + struct DashSDKResult dash_sdk_identity_parse_json(const char *json_str) ; + // Put identity to platform with instant lock proof // +// # Safety +// - `sdk_handle`, `identity_handle`, `instant_lock_bytes`, `transaction_bytes`, `private_key`, and `signer_handle` +// must be valid, non-null pointers. Buffer pointers must reference at least the specified lengths. +// - `put_settings` may be null; if non-null it must be valid for the duration of the call. +// - On success, returns serialized data; any heap memory inside the result must be freed using SDK routines. +// // # Parameters // - `instant_lock_bytes`: Serialized InstantLock data // - `transaction_bytes`: Serialized Transaction data @@ -1098,6 +2038,11 @@ extern "C" { // Put identity to platform with instant lock proof and wait for confirmation // +// # Safety +// - Same requirements as `dash_sdk_identity_put_to_platform_with_instant_lock`. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. +// // # Parameters // - `instant_lock_bytes`: Serialized InstantLock data // - `transaction_bytes`: Serialized Transaction data @@ -1111,6 +2056,12 @@ extern "C" { // Put identity to platform with chain lock proof // +// # Safety +// - `sdk_handle`, `identity_handle`, `out_point`, `private_key`, and `signer_handle` must be valid, non-null pointers. +// - `out_point` must reference 36 readable bytes; `private_key` must reference 32 readable bytes. +// - `put_settings` may be null; if non-null it must be valid for the duration of the call. +// - On success, returns serialized data; any heap memory inside the result must be freed using SDK routines. +// // # Parameters // - `core_chain_locked_height`: Core height at which the transaction was chain locked // - `out_point`: 36-byte OutPoint (32-byte txid + 4-byte vout) @@ -1120,6 +2071,11 @@ extern "C" { // Put identity to platform with chain lock proof and wait for confirmation // +// # Safety +// - Same requirements as `dash_sdk_identity_put_to_platform_with_chain_lock`. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. +// // # Parameters // - `core_chain_locked_height`: Core height at which the transaction was chain locked // - `out_point`: 36-byte OutPoint (32-byte txid + 4-byte vout) @@ -1138,6 +2094,11 @@ extern "C" { // // # Returns // The balance of the identity as a string +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_identity_fetch_balance(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id) ; // Fetch identity balance and revision @@ -1148,6 +2109,11 @@ extern "C" { // // # Returns // JSON string containing the balance and revision information +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_identity_fetch_balance_and_revision(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id) ; // Fetch identity by non-unique public key hash with optional pagination @@ -1159,10 +2125,21 @@ extern "C" { // // # Returns // JSON string containing the identity information, or null if not found +// +// # Safety +// - `sdk_handle` and `public_key_hash` must be valid, non-null pointers. +// - `public_key_hash` must point to a NUL-terminated C string. `start_after` may be null; if non-null it must be a valid +// pointer to a NUL-terminated C string. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_identity_fetch_by_non_unique_public_key_hash(const struct dash_sdk_handle_t *sdk_handle, const char *public_key_hash, const char *start_after) ; // Fetch identity by public key hash // +// # Safety +// - `sdk_handle` and `public_key_hash` must be valid, non-null pointers. +// - `public_key_hash` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a handle or no data; any heap memory must be freed using SDK routines. +// // # Parameters // - `sdk_handle`: SDK handle // - `public_key_hash`: Hex-encoded 20-byte public key hash @@ -1180,13 +2157,47 @@ extern "C" { // // # Returns // The contract nonce of the identity as a string +// +// # Safety +// - `sdk_handle`, `identity_id`, and `contract_id` must be valid, non-null pointers. +// - `identity_id` and `contract_id` must point to NUL-terminated C strings valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_identity_fetch_contract_nonce(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, const char *contract_id) ; // Fetch an identity by ID +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string. +// - On success, returns a handle or no data; any heap memory must be freed using SDK routines. struct DashSDKResult dash_sdk_identity_fetch(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id) ; +// Fetch an identity by ID and return a handle +// +// This function fetches an identity from the network and returns +// a handle that can be used with other FFI functions like transfers. +// +// # Parameters +// - `sdk_handle`: SDK handle +// - `identity_id`: Base58-encoded identity ID +// +// # Returns +// - Handle to the fetched identity on success +// - Error if fetch fails or identity not found +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. + struct DashSDKResult dash_sdk_identity_fetch_handle(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id) ; + // Fetch balances for multiple identities // +// # Safety +// - `sdk_handle` and `identity_ids` must be valid, non-null pointers. +// - `identity_ids` must point to an array of `[u8; 32]` of length `identity_ids_len` and remain valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. +// // # Parameters // - `sdk_handle`: SDK handle // - `identity_ids`: Array of identity IDs (32-byte arrays) @@ -1207,6 +2218,11 @@ extern "C" { // // # Returns // JSON string containing identity IDs mapped to their contract keys by purpose +// +// # Safety +// - `sdk_handle`, `identity_ids`, `contract_id`, and `purposes` must be valid, non-null pointers. +// - `identity_ids`, `contract_id`, `document_type_name` (when non-null), and `purposes` must point to NUL-terminated C strings valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_identities_fetch_contract_keys(const struct dash_sdk_handle_t *sdk_handle, const char *identity_ids, const char *contract_id, const char *document_type_name, const char *purposes) ; // Fetch identity nonce @@ -1217,10 +2233,20 @@ extern "C" { // // # Returns // The nonce of the identity as a string +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. struct DashSDKResult dash_sdk_identity_fetch_nonce(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id) ; // Fetch identity public keys // +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. +// // # Parameters // - `sdk_handle`: SDK handle // - `identity_id`: Base58-encoded identity ID @@ -1241,12 +2267,36 @@ extern "C" { // # Returns // * On success: A result containing the resolved identity ID // * On error: An error result +// +// # Safety +// - `sdk_handle` and `name` must be valid, non-null pointers. +// - `name` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, any heap memory in the result must be freed using SDK routines. struct DashSDKResult dash_sdk_identity_resolve_name(const struct dash_sdk_handle_t *sdk_handle, const char *name) ; +// Test function to diagnose the transfer crash +// +// # Safety +// - `sdk_handle` and `identity_id` must be valid, non-null pointers. +// - `identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - On success, any heap memory in the result must be freed using SDK routines. + struct DashSDKResult dash_sdk_test_identity_transfer_crash(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id) ; + // Top up an identity with credits using instant lock proof +// +// # Safety +// - `sdk_handle`, `identity_handle`, `instant_lock_bytes`, `transaction_bytes`, and `private_key` must be valid, non-null pointers. +// - Buffer pointers must reference at least the specified lengths. +// - `put_settings` may be null; if non-null it must be valid for the duration of the call. +// - On success, returns serialized data; any heap memory inside the result must be freed using SDK routines. struct DashSDKResult dash_sdk_identity_topup_with_instant_lock(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *identity_handle, const uint8_t *instant_lock_bytes, uintptr_t instant_lock_len, const uint8_t *transaction_bytes, uintptr_t transaction_len, uint32_t output_index, const uint8_t (*private_key)[32], const struct DashSDKPutSettings *put_settings) ; // Top up an identity with credits using instant lock proof and wait for confirmation +// +// # Safety +// - Same requirements as `dash_sdk_identity_topup_with_instant_lock`. +// - The function may block while waiting for confirmation; input pointers must remain valid throughout. +// - On success, returns a heap-allocated handle which must be destroyed with the SDK's destroy function. struct DashSDKResult dash_sdk_identity_topup_with_instant_lock_and_wait(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *identity_handle, const uint8_t *instant_lock_bytes, uintptr_t instant_lock_len, const uint8_t *transaction_bytes, uintptr_t transaction_len, uint32_t output_index, const uint8_t (*private_key)[32], const struct DashSDKPutSettings *put_settings) ; // Transfer credits from one identity to another @@ -1255,15 +2305,25 @@ extern "C" { // - `from_identity_handle`: Identity to transfer credits from // - `to_identity_id`: Base58-encoded ID of the identity to transfer credits to // - `amount`: Amount of credits to transfer -// - `identity_public_key_handle`: Public key for signing (optional, pass null to auto-select) +// - `public_key_id`: ID of the public key to use for signing (pass 0 to auto-select TRANSFER key) // - `signer_handle`: Cryptographic signer // - `put_settings`: Optional settings for the operation (can be null for defaults) // // # Returns // DashSDKTransferCreditsResult with sender and receiver final balances on success - struct DashSDKResult dash_sdk_identity_transfer_credits(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *from_identity_handle, const char *to_identity_id, uint64_t amount, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings) ; +// +// # Safety +// - `sdk_handle`, `from_identity_handle`, `to_identity_id`, and `signer_handle` must be valid, non-null pointers. +// - `to_identity_id` must point to a NUL-terminated C string valid for the duration of the call. +// - `put_settings` may be null; if non-null it must be valid for the duration of the call. +// - On success, any heap memory included in the result must be freed using SDK routines. + struct DashSDKResult dash_sdk_identity_transfer_credits(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *from_identity_handle, const char *to_identity_id, uint64_t amount, uint32_t public_key_id, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings) ; // Free a transfer credits result structure +// +// # Safety +// - `result` must be a pointer previously returned by this SDK or null (no-op). +// - After this call, `result` becomes invalid and must not be used again. void dash_sdk_transfer_credits_result_free(struct DashSDKTransferCreditsResult *result) ; // Withdraw credits from identity to a Dash address @@ -1273,13 +2333,19 @@ extern "C" { // - `address`: Base58-encoded Dash address to withdraw to // - `amount`: Amount of credits to withdraw // - `core_fee_per_byte`: Core fee per byte (optional, pass 0 for default) -// - `identity_public_key_handle`: Public key for signing (optional, pass null to auto-select) +// - `public_key_id`: ID of the public key to use for signing (pass 0 to auto-select TRANSFER key) // - `signer_handle`: Cryptographic signer // - `put_settings`: Optional settings for the operation (can be null for defaults) // // # Returns // The new balance of the identity after withdrawal - struct DashSDKResult dash_sdk_identity_withdraw(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *identity_handle, const char *address, uint64_t amount, uint32_t core_fee_per_byte, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings) ; +// +// # Safety +// - `sdk_handle`, `identity_handle`, `address`, and `signer_handle` must be valid, non-null pointers. +// - `address` must point to a NUL-terminated C string valid for the duration of the call. +// - `put_settings` may be null; if non-null it must be valid for the duration of the call. +// - On success, returns a C string pointer inside `DashSDKResult`; caller must free it using SDK routines. + struct DashSDKResult dash_sdk_identity_withdraw(struct dash_sdk_handle_t *sdk_handle, const struct IdentityHandle *identity_handle, const char *address, uint64_t amount, uint32_t core_fee_per_byte, uint32_t public_key_id, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings) ; // Fetches protocol version upgrade state // @@ -1291,7 +2357,11 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - The function does not retain references to the input pointer beyond the duration of the call. +// - On success, the returned `DashSDKResult` may contain a heap-allocated C string; the caller must +// free it using the SDK's free routine to avoid leaks. It may also return no data (null pointer). +// - Passing a dangling or invalid pointer for `sdk_handle` results in undefined behavior. struct DashSDKResult dash_sdk_protocol_version_get_upgrade_state(const struct dash_sdk_handle_t *sdk_handle) ; // Fetches protocol version upgrade vote status @@ -1306,16 +2376,46 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `start_pro_tx_hash` may be null (meaning no start); when non-null it must be a valid pointer to a +// NUL-terminated C string containing a hex-encoded 32-byte hash and remain valid for the duration of the call. +// - `count` is passed by value; no references are retained. +// - On success, the returned `DashSDKResult` may contain a heap-allocated C string which the caller must free +// using the SDK's free routine. It may also contain no data (null pointer). +// - All pointers must reference readable memory; invalid pointers result in undefined behavior. struct DashSDKResult dash_sdk_protocol_version_get_upgrade_vote_status(const struct dash_sdk_handle_t *sdk_handle, const char *start_pro_tx_hash, uint32_t count) ; // Create a new SDK instance +// +// # Safety +// - `config` must be a valid pointer to a DashSDKConfig structure for the duration of the call. +// - The returned handle inside `DashSDKResult` must be destroyed using the SDK destroy function to avoid leaks. struct DashSDKResult dash_sdk_create(const struct DashSDKConfig *config) ; // Create a new SDK instance with extended configuration including context provider +// +// # Safety +// - `config` must be a valid pointer to a DashSDKConfigExtended structure for the duration of the call. +// - Any embedded pointers (context_provider/core_sdk_handle) must be valid when non-null. +// - The returned handle inside `DashSDKResult` must be destroyed using the SDK destroy function to avoid leaks. struct DashSDKResult dash_sdk_create_extended(const struct DashSDKConfigExtended *config) ; +// Create a new SDK instance with trusted setup +// +// This creates an SDK with a trusted context provider that fetches quorum keys and +// data contracts from trusted endpoints instead of requiring proof verification. +// +// # Safety +// - `config` must be a valid pointer to a DashSDKConfig structure +// # Safety +// - `config` must be a valid pointer to a DashSDKConfig structure for the duration of the call. +// - The returned handle inside `DashSDKResult` must be destroyed using the SDK destroy function to avoid leaks. + struct DashSDKResult dash_sdk_create_trusted(const struct DashSDKConfig *config) ; + // Destroy an SDK instance +// # Safety +// - `handle` must be a valid pointer previously returned by this SDK and not yet destroyed. +// - It may be null (no-op). After this call the handle must not be used again. void dash_sdk_destroy(struct dash_sdk_handle_t *handle) ; // Register global context provider callbacks @@ -1337,20 +2437,80 @@ extern "C" { struct DashSDKResult dash_sdk_create_with_callbacks(const struct DashSDKConfig *config, const struct ContextProviderCallbacks *callbacks) ; // Get the current network the SDK is connected to +// +// # Safety +// - `handle` must be a valid pointer to an SDKHandle (or null, in which case a default is returned). enum DashSDKNetwork dash_sdk_get_network(const struct dash_sdk_handle_t *handle) ; +// Add known contracts to the SDK's trusted context provider +// +// This allows pre-loading data contracts into the trusted provider's cache, +// avoiding network calls for these contracts. +// +// # Safety +// - `handle` must be a valid SDK handle created with dash_sdk_create_trusted +// - `contract_ids` must be a valid comma-separated list of contract IDs +// - `serialized_contracts` must be a valid pointer to an array of serialized contract data +// - `contract_lengths` must be a valid pointer to an array of contract data lengths +// - `contract_count` must match the actual number of contracts provided + struct DashSDKResult dash_sdk_add_known_contracts(const struct dash_sdk_handle_t *handle, const char *contract_ids, const uint8_t *const *serialized_contracts, const uintptr_t *contract_lengths, uintptr_t contract_count) ; + // Create a mock SDK instance with a dump directory (for offline testing) +// +// # Safety +// - `dump_dir` must be either null (no dumps) or a valid pointer to a NUL-terminated C string readable for the duration of the call. +// - The returned handle must be destroyed using the SDK destroy function to avoid leaks. struct dash_sdk_handle_t *dash_sdk_create_handle_with_mock(const char *dump_dir) ; -// Create a new iOS signer - struct SignerHandle *dash_sdk_signer_create(IOSSignCallback sign_callback, IOSCanSignCallback can_sign_callback) ; +// Create a new signer with callbacks from iOS/external code +// +// This creates a VTableSigner that can be used for all state transitions. +// The callbacks should handle the actual signing logic. +// +// # Parameters +// - `sign_callback`: Function to sign data +// - `can_sign_callback`: Function to check if can sign with a key +// - `destroy_callback`: Optional destructor (can be NULL) +// # Safety +// - Callback function pointers must be valid and follow the required ABI and lifetime for the duration of use. +// - The returned `SignerHandle` must be destroyed with `dash_sdk_signer_destroy` to avoid leaks. + struct SignerHandle *dash_sdk_signer_create(SignCallback sign_callback, CanSignCallback can_sign_callback, DestroyCallback destroy_callback) ; -// Destroy an iOS signer +// Destroy a signer +// # Safety +// - `handle` must be a valid pointer previously returned by this SDK and not yet destroyed. +// - It may be null (no-op). After this call the handle must not be used again. void dash_sdk_signer_destroy(struct SignerHandle *handle) ; -// Free bytes allocated by iOS callbacks +// Free bytes allocated by callbacks +// # Safety +// - `bytes` must be a pointer to a buffer allocated by the corresponding FFI and compatible with `libc::free`. +// - It may be null (no-op). After this call the pointer must not be used again. void dash_sdk_bytes_free(uint8_t *bytes) ; +// Create a signer from a private key +// +// # Safety +// - `private_key` must be a valid pointer to at least 32 readable bytes. +// - The function reads exactly `private_key_len` bytes; it must be 32. +// - The returned handle inside DashSDKResult must be freed using the appropriate SDK destroy function. + struct DashSDKResult dash_sdk_signer_create_from_private_key(const uint8_t *private_key, uintptr_t private_key_len) ; + +// Sign data with a signer +// +// # Safety +// - `signer_handle` must be a valid pointer obtained from this SDK and not previously destroyed. +// - `data` must be a valid pointer to `data_len` readable bytes. +// - The returned signature pointer inside DashSDKResult must be freed with `dash_sdk_signature_free`. + struct DashSDKResult dash_sdk_signer_sign(struct SignerHandle *signer_handle, const uint8_t *data, uintptr_t data_len) ; + +// Free a signature +// +// # Safety +// - `signature` must be a valid pointer returned by this SDK, or null for no-op. +// - After this call the pointer must not be used again. + void dash_sdk_signature_free(struct DashSDKSignature *signature) ; + // Fetches information about current quorums // // # Parameters @@ -1361,7 +2521,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - The function does not retain references to inputs beyond the call. +// - On success, returns a heap-allocated C string pointer; caller must free it using SDK routines. struct DashSDKResult dash_sdk_system_get_current_quorums_info(const struct dash_sdk_handle_t *sdk_handle) ; // Fetches information about multiple epochs @@ -1377,7 +2539,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `start_epoch` may be null (no explicit start); when non-null it must be a valid pointer to a NUL-terminated C string. +// - On success, returns a heap-allocated C string pointer; caller must free it using SDK routines. struct DashSDKResult dash_sdk_system_get_epochs_info(const struct dash_sdk_handle_t *sdk_handle, const char *start_epoch, uint32_t count, bool ascending) ; // Fetches path elements @@ -1392,9 +2556,17 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `path_json` and `keys_json` must be valid, non-null pointers to NUL-terminated C strings that remain valid for the duration of the call. +// - On success, returns a heap-allocated C string pointer; caller must free it using SDK routines. struct DashSDKResult dash_sdk_system_get_path_elements(const struct dash_sdk_handle_t *sdk_handle, const char *path_json, const char *keys_json) ; +// Get platform status including block heights +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - The returned C string pointer (on success) must be freed by the caller using the SDK's free routine. + struct DashSDKResult dash_sdk_get_platform_status(const struct dash_sdk_handle_t *sdk_handle) ; + // Fetches a prefunded specialized balance // // # Parameters @@ -1406,7 +2578,9 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - `id` must be a valid, non-null pointer to a NUL-terminated C string that remains valid for the duration of the call. +// - On success, returns a heap-allocated C string pointer; caller must free it using SDK routines. struct DashSDKResult dash_sdk_system_get_prefunded_specialized_balance(const struct dash_sdk_handle_t *sdk_handle, const char *id) ; // Fetches the total credits in the platform @@ -1419,40 +2593,127 @@ extern "C" { // * Error message if operation fails // // # Safety -// This function is unsafe because it handles raw pointers from C +// - `sdk_handle` must be a valid, non-null pointer to an initialized `SDKHandle`. +// - The function does not retain references to inputs beyond the call. +// - On success, returns a heap-allocated C string pointer; caller must free it using SDK routines. struct DashSDKResult dash_sdk_system_get_total_credits_in_platform(const struct dash_sdk_handle_t *sdk_handle) ; +// Get SDK status including mode and quorum count +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - The returned C string pointer inside DashSDKResult (on success) must be freed by the caller +// using the SDK's free routine to avoid memory leaks. + struct DashSDKResult dash_sdk_get_status(const struct dash_sdk_handle_t *sdk_handle) ; + // Burn tokens from an identity and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory from the result using SDK free routines. struct DashSDKResult dash_sdk_token_burn(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenBurnParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Claim tokens from a distribution and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, and `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory in the result using SDK free routines. struct DashSDKResult dash_sdk_token_claim(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenClaimParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Mint tokens to an identity and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, and `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory in the result using SDK free routines. struct DashSDKResult dash_sdk_token_mint(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenMintParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Token transfer to another identity and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory in the result using SDK free routines. struct DashSDKResult dash_sdk_token_transfer(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenTransferParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Update token configuration and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory in the result using SDK free routines. struct DashSDKResult dash_sdk_token_update_contract_token_configuration(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenConfigUpdateParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Destroy frozen token funds and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - The function may allocate and return heap memory via the DashSDKResult; caller must free it using SDK free routines. struct DashSDKResult dash_sdk_token_destroy_frozen_funds(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenDestroyFrozenFundsParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Perform emergency action on token and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, `signer_handle` must be valid, non-null pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Returned pointers embedded in DashSDKResult must be freed by the caller using SDK free routines. struct DashSDKResult dash_sdk_token_emergency_action(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenEmergencyActionParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Freeze a token for an identity and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Any returned heap memory in the result must be freed by the caller using SDK free routines. struct DashSDKResult dash_sdk_token_freeze(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenFreezeParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Unfreeze a token for an identity and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, and `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory from the result using SDK free routines. struct DashSDKResult dash_sdk_token_unfreeze(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenFreezeParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Purchase tokens directly and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, and `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory in the result using SDK-provided free routines. struct DashSDKResult dash_sdk_token_purchase(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenPurchaseParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Set token price for direct purchase and wait for confirmation +// +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `transition_owner_id` must point to at least 32 readable bytes. +// - `params`, `identity_public_key_handle`, `signer_handle` must be valid pointers to initialized structures. +// - Optional pointers (`put_settings`, `state_transition_creation_options`) may be null; when non-null they must be valid. +// - Caller must free any returned heap memory in the result using SDK free routines. struct DashSDKResult dash_sdk_token_set_price(struct dash_sdk_handle_t *sdk_handle, const uint8_t *transition_owner_id, const struct DashSDKTokenSetPriceParams *params, const struct IdentityPublicKeyHandle *identity_public_key_handle, const struct SignerHandle *signer_handle, const struct DashSDKPutSettings *put_settings, const struct DashSDKStateTransitionCreationOptions *state_transition_creation_options) ; // Get identity token balances @@ -1466,6 +2727,10 @@ extern "C" { // // # Returns // JSON string containing token IDs mapped to their balances +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `identity_id` and `token_ids` must be valid pointers to NUL-terminated C strings and readable during the call. +// - The returned pointer (on success) must be freed using the SDK's free routine to avoid memory leaks. struct DashSDKResult dash_sdk_token_get_identity_balances(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, const char *token_ids) ; // Get token contract info @@ -1476,6 +2741,10 @@ extern "C" { // // # Returns // JSON string containing the contract ID and token position, or null if not found +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `token_id` must be a valid pointer to a NUL-terminated C string and readable during the call. +// - The returned C string pointer (on success) must be freed with the SDK's string-free function by the caller. struct DashSDKResult dash_sdk_token_get_contract_info(const struct dash_sdk_handle_t *sdk_handle, const char *token_id) ; // Get token direct purchase prices @@ -1486,17 +2755,25 @@ extern "C" { // // # Returns // JSON string containing token IDs mapped to their pricing information +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `token_ids` must be a valid pointer to a NUL-terminated C string and readable during the call. +// - The returned C string pointer (on success) must be freed by the caller using the SDK's free function. struct DashSDKResult dash_sdk_token_get_direct_purchase_prices(const struct dash_sdk_handle_t *sdk_handle, const char *token_ids) ; // Fetch token balances for multiple identities for a specific token // // # Parameters // - `sdk_handle`: SDK handle -// - `identity_ids`: Comma-separated list of Base58-encoded identity IDs +// - `identity_ids`: Either a comma-separated list OR a JSON array of Base58-encoded identity IDs // - `token_id`: Base58-encoded token ID // // # Returns // JSON string containing identity IDs mapped to their token balances +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `identity_ids` and `token_id` must be valid pointers to NUL-terminated C strings and readable during the call. +// - The returned C string pointer (on success) must be freed using the SDK's free function. struct DashSDKResult dash_sdk_identities_fetch_token_balances(const struct dash_sdk_handle_t *sdk_handle, const char *identity_ids, const char *token_id) ; // Fetch token information for multiple identities for a specific token @@ -1508,6 +2785,10 @@ extern "C" { // // # Returns // JSON string containing identity IDs mapped to their token information +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `identity_ids` and `token_id` must be valid pointers to NUL-terminated C strings and readable during the call. +// - The returned C string pointer (on success) must be freed with the SDK's free function. struct DashSDKResult dash_sdk_identities_fetch_token_infos(const struct dash_sdk_handle_t *sdk_handle, const char *identity_ids, const char *token_id) ; // Fetch token balances for a specific identity @@ -1519,6 +2800,10 @@ extern "C" { // // # Returns // JSON string containing token IDs mapped to their balances +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `identity_id` and `token_ids` must be valid pointers to NUL-terminated C strings and readable during the call. +// - The returned C string pointer (on success) must be freed using the SDK's free function to avoid leaks. struct DashSDKResult dash_sdk_identity_fetch_token_balances(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, const char *token_ids) ; // Fetch token information for a specific identity @@ -1530,6 +2815,10 @@ extern "C" { // // # Returns // JSON string containing token IDs mapped to their information +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `identity_id` and `token_ids` must be valid pointers to NUL-terminated C strings and readable during the call. +// - The returned C string pointer (on success) must be freed using the SDK's free function to avoid leaks. struct DashSDKResult dash_sdk_identity_fetch_token_infos(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, const char *token_ids) ; // Get identity token information @@ -1543,6 +2832,10 @@ extern "C" { // // # Returns // JSON string containing token IDs mapped to their information +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `identity_id` and `token_ids` must be valid pointers to NUL-terminated C strings and readable for the call duration. +// - The returned string pointer (on success) must be freed with the SDK's string free routine to avoid leaks. struct DashSDKResult dash_sdk_token_get_identity_infos(const struct dash_sdk_handle_t *sdk_handle, const char *identity_id, const char *token_ids) ; // Get token perpetual distribution last claim @@ -1554,6 +2847,10 @@ extern "C" { // // # Returns // JSON string containing the last claim information +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `token_id` and `identity_id` must be valid pointers to NUL-terminated C strings and readable during the call. +// - The returned C string pointer (on success) must be freed by the caller using the SDK's free function to avoid memory leaks. struct DashSDKResult dash_sdk_token_get_perpetual_distribution_last_claim(const struct dash_sdk_handle_t *sdk_handle, const char *token_id, const char *identity_id) ; // Get token statuses @@ -1564,6 +2861,10 @@ extern "C" { // // # Returns // JSON string containing token IDs mapped to their status information +// # Safety +// - `sdk_handle` must be a valid pointer to an initialized SDKHandle. +// - `token_ids` must be a valid pointer to a NUL-terminated C string containing comma-separated IDs. +// - The returned C string pointer (on success) must be freed by the caller using the SDK's free function. struct DashSDKResult dash_sdk_token_get_statuses(const struct dash_sdk_handle_t *sdk_handle, const char *token_ids) ; // Fetches the total supply of a token @@ -1581,20 +2882,97 @@ extern "C" { struct DashSDKResult dash_sdk_token_get_total_supply(const struct dash_sdk_handle_t *sdk_handle, const char *token_id) ; // Free a string allocated by the FFI +// +// # Safety +// - `s` must be a pointer returned by this SDK to a heap-allocated NUL-terminated C string. +// - Passing a pointer not allocated by this SDK, or a pointer already freed, results in undefined behavior. +// - `s` may be null, in which case this is a no-op. void dash_sdk_string_free(char *s) ; // Free binary data allocated by the FFI +// +// # Safety +// - `binary_data` must be a valid pointer returned by this SDK and not previously freed. +// - When non-null, the function takes ownership and frees both the struct and its internal buffer. +// - Do not use `binary_data` after this call. void dash_sdk_binary_data_free(struct DashSDKBinaryData *binary_data) ; // Free an identity info structure +// +// # Safety +// - `info` must be a valid pointer to `DashSDKIdentityInfo` allocated by this SDK. +// - It may be null (no-op). When non-null, this frees any owned strings and the struct. +// - Do not access `info` after this call. void dash_sdk_identity_info_free(struct DashSDKIdentityInfo *info) ; // Free a document info structure +// +// # Safety +// - `info` must be a valid pointer to `DashSDKDocumentInfo` allocated by this SDK and not already freed. +// - It may be null (no-op). When non-null, this frees all owned strings and arrays. +// - Pointer must not be dereferenced after this call. void dash_sdk_document_info_free(struct DashSDKDocumentInfo *info) ; // Free an identity balance map +// +// # Safety +// - `map` must be a valid, non-dangling pointer returned by this SDK. +// - It may be null (no-op). When non-null, this frees the entries array and the struct. +// - Using `map` after this function returns is undefined behavior. void dash_sdk_identity_balance_map_free(struct DashSDKIdentityBalanceMap *map) ; +// Free a contender structure +// +// # Safety +// - `contender` must be a valid, non-dangling pointer obtained from this FFI (e.g., via an SDK function). +// - It must either be null (a no-op) or point to a heap-allocated `DashSDKContender` that has not been freed yet. +// - After this call, the pointer must not be used again (use-after-free is undefined behavior). +// - This function will also free any heap-allocated strings owned by the structure. +// # Safety +// - `contender` must be a valid, non-null pointer to a `DashSDKContender` allocated by this SDK, or null for no-op. +// - The pointer must not be used after this call. + void dash_sdk_contender_free(struct DashSDKContender *contender) ; + +// Free contest info structure +// +// # Safety +// - `info` must be a valid, non-dangling pointer obtained from this FFI and not previously freed. +// - It may be null (no-op). When non-null, this frees the owned contender array and contained strings. +// - Do not use `info` after this call; doing so is undefined behavior. + void dash_sdk_contest_info_free(struct DashSDKContestInfo *info) ; + +// Free a contested name structure +// +// # Safety +// - `name` must be a valid, non-dangling pointer to a `DashSDKContestedName` allocated by this SDK. +// - It may be null (no-op). When non-null, this frees the embedded strings and contender buffers. +// - Do not access `name` after freeing. + void dash_sdk_contested_name_free(struct DashSDKContestedName *name) ; + +// Free a contested names list +// +// # Safety +// - `list` must be a valid pointer returned by this SDK and not previously freed. +// - It may be null (no-op). When non-null, this frees the array of names and any nested strings/buffers. +// - Do not use `list` after this call. + void dash_sdk_contested_names_list_free(struct DashSDKContestedNamesList *list) ; + +// Free a name-timestamp structure +// +// # Safety +// - `entry` must be a valid, non-dangling pointer to a `DashSDKNameTimestamp` allocated by this SDK. +// - It may be null (no-op). When non-null, this frees the owned string and the struct. +// - Do not use `entry` after this call. + void dash_sdk_name_timestamp_free(struct DashSDKNameTimestamp *entry) ; + +// Free a name-timestamp list +// +// # Safety +// - `list` must be a valid pointer to a `DashSDKNameTimestampList` allocated by this SDK. +// - It may be null (no-op). When non-null, this frees the entries array and contained strings. +// - Pointer must not be used after this call. + void dash_sdk_name_timestamp_list_free(struct DashSDKNameTimestampList *list) ; + // Initialize the unified SDK system // This initializes both Core SDK (if enabled) and Platform SDK int32_t dash_unified_sdk_init(void) ; @@ -1627,7 +3005,7 @@ extern "C" { // // # Safety // - `handle` must be a valid unified SDK handle - CoreSDKClient *dash_unified_sdk_get_core_client(struct UnifiedSDKHandle *handle) ; + FFIDashSpvClient *dash_unified_sdk_get_core_client(struct UnifiedSDKHandle *handle) ; // Get the Platform SDK from a unified handle // @@ -1668,6 +3046,47 @@ extern "C" { // Check if unified SDK was compiled with core support bool dash_unified_sdk_has_core_support(void) ; +// Convert a hex string to base58 +// +// # Parameters +// - `hex_string`: Hex encoded string (must be 64 characters for identity IDs) +// +// # Returns +// - Base58 encoded string on success +// - Error if the hex string is invalid +// # Safety +// - `hex_string` must be a valid, non-null pointer to a NUL-terminated C string. +// - The memory pointed to by `hex_string` must be readable for the duration of the call. +// - The returned pointer (on success) must be freed by calling the appropriate free function +// (e.g., `dash_sdk_string_free`) from this SDK to avoid memory leaks. + struct DashSDKResult dash_sdk_utils_hex_to_base58(const char *hex_string) ; + +// Convert a base58 string to hex +// +// # Parameters +// - `base58_string`: Base58 encoded string +// +// # Returns +// - Hex encoded string on success +// - Error if the base58 string is invalid +// # Safety +// - `base58_string` must be a valid, non-null pointer to a NUL-terminated C string. +// - The memory pointed to by `base58_string` must be readable for the duration of the call. +// - The returned C string pointer (on success) must be freed with the SDK's string free routine to avoid leaks. + struct DashSDKResult dash_sdk_utils_base58_to_hex(const char *base58_string) ; + +// Validate if a string is valid base58 +// +// # Parameters +// - `string`: String to validate +// +// # Returns +// - 1 if valid base58, 0 if invalid +// # Safety +// - `string` must be a valid, non-null pointer to a NUL-terminated C string. +// - The memory pointed to by `string` must be readable for the duration of the call. + uint8_t dash_sdk_utils_is_valid_base58(const char *string) ; + // Fetches vote polls by end date // // # Parameters diff --git a/packages/swift-sdk/SwiftTests/Sources/SwiftDashSDKMock/SwiftDashSDK.h b/packages/swift-sdk/SwiftTests/Sources/SwiftDashSDKMock/SwiftDashSDK.h index a979ff86bab..ac38e5cd5e5 100644 --- a/packages/swift-sdk/SwiftTests/Sources/SwiftDashSDKMock/SwiftDashSDK.h +++ b/packages/swift-sdk/SwiftTests/Sources/SwiftDashSDKMock/SwiftDashSDK.h @@ -1,4 +1,4 @@ -/* Generated with cbindgen:0.27.0 */ +/* Generated with cbindgen:0.29.2 */ /* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */ From 10b1d211e44e759a92b4f9729b5191fd26dfb2ed Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 19 Feb 2026 17:45:41 +0100 Subject: [PATCH 09/19] fix(swift-sdk): address PR review comments for iOS build and Swift SDK - Fix BUILD_ARCH-aware SPV lib selection in build_ios.sh: x86 mode now builds the correct x86_64-apple-ios SPV target, and universal mode lipo-creates both SPV thin libs into a fat archive before libtool merge - Fix addWallet TOCTOU: use wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes to get wallet ID directly instead of querying getWalletIds().last - Deprecate clearSyncState() with @available renamed to clearStorage() and update docstring to reflect actual behavior - Remove unused network property from ManagedWallet - Change Wallet.init(nonOwningHandle:) from public to internal - Deprecate vestigial network: parameters across 8 WalletManager methods - Add assertion for NetworkSet.ffiNetwork single-network invariant - Fix pre-existing double-free risk in Account.derivePrivateKeyWIF by splitting shared FFIError into separate deriveError/wifError variables - Add trap for temp file cleanup in swift-sdk build_ios.sh Co-Authored-By: Claude Opus 4.6 --- packages/rs-sdk-ffi/build_ios.sh | 28 ++- .../SwiftDashSDK/KeyWallet/Account.swift | 29 +-- .../KeyWallet/KeyWalletTypes.swift | 1 + .../KeyWallet/ManagedWallet.swift | 5 +- .../SwiftDashSDK/KeyWallet/Wallet.swift | 2 +- .../KeyWallet/WalletManager.swift | 197 ++++++++++++++---- .../Sources/SwiftDashSDK/SPV/SPVClient.swift | 7 +- packages/swift-sdk/build_ios.sh | 1 + 8 files changed, 204 insertions(+), 66 deletions(-) diff --git a/packages/rs-sdk-ffi/build_ios.sh b/packages/rs-sdk-ffi/build_ios.sh index d390d60f2a0..36bf4082d40 100755 --- a/packages/rs-sdk-ffi/build_ios.sh +++ b/packages/rs-sdk-ffi/build_ios.sh @@ -344,7 +344,15 @@ if [ -d "$SPV_CRATE_PATH" ]; then cargo build --lib --target aarch64-apple-ios-sim --release > /tmp/cargo_build_spv_sim_arm.log 2>&1 || { echo -e "${RED}✗ dash-spv-ffi sim (arm64) build failed${NC}"; cat /tmp/cargo_build_spv_sim_arm.log; exit 1; } cargo build --lib --target x86_64-apple-ios --release > /tmp/cargo_build_spv_sim_x86.log 2>&1 || { echo -e "${RED}✗ dash-spv-ffi sim (x86_64) build failed${NC}"; cat /tmp/cargo_build_spv_sim_x86.log; exit 1; } fi + elif [ "$BUILD_ARCH" = "x86" ]; then + if [ -n "${RUST_DASHCORE_TOOLCHAIN:-}" ]; then + echo -e "${GREEN}Using toolchain '+${RUST_DASHCORE_TOOLCHAIN}' for sim build (x86_64)${NC}" + cargo +"${RUST_DASHCORE_TOOLCHAIN}" build --lib --target x86_64-apple-ios --release > /tmp/cargo_build_spv_sim_x86.log 2>&1 || { echo -e "${RED}✗ dash-spv-ffi sim (x86_64) build failed${NC}"; cat /tmp/cargo_build_spv_sim_x86.log; exit 1; } + else + cargo build --lib --target x86_64-apple-ios --release > /tmp/cargo_build_spv_sim_x86.log 2>&1 || { echo -e "${RED}✗ dash-spv-ffi sim (x86_64) build failed${NC}"; cat /tmp/cargo_build_spv_sim_x86.log; exit 1; } + fi else + # arm64-sim only (arm default) if [ -n "${RUST_DASHCORE_TOOLCHAIN:-}" ]; then echo -e "${GREEN}Using toolchain '+${RUST_DASHCORE_TOOLCHAIN}' for sim build${NC}" cargo +"${RUST_DASHCORE_TOOLCHAIN}" build --lib --target aarch64-apple-ios-sim --release > /tmp/cargo_build_spv_sim_arm.log 2>&1 || { echo -e "${RED}✗ dash-spv-ffi sim (arm64) build failed${NC}"; cat /tmp/cargo_build_spv_sim_arm.log; exit 1; } @@ -449,12 +457,20 @@ if [ "$BUILD_ARCH" != "x86" ] && [ -f "$OUTPUT_DIR/device/librs_sdk_ffi.a" ]; th fi if [ -f "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" ]; then - # Try to merge with SPV sim lib if it exists + # Try to merge with SPV sim lib if it exists (must match BUILD_ARCH) SIM_SPV_LIB="" - if [ -f "$SPV_TARGET_DIR/aarch64-apple-ios-sim/release/libdash_spv_ffi.a" ]; then - SIM_SPV_LIB="$SPV_TARGET_DIR/aarch64-apple-ios-sim/release/libdash_spv_ffi.a" - elif [ -f "$SPV_TARGET_DIR/x86_64-apple-ios/release/libdash_spv_ffi.a" ]; then - SIM_SPV_LIB="$SPV_TARGET_DIR/x86_64-apple-ios/release/libdash_spv_ffi.a" + SPV_SIM_ARM="$SPV_TARGET_DIR/aarch64-apple-ios-sim/release/libdash_spv_ffi.a" + SPV_SIM_X86="$SPV_TARGET_DIR/x86_64-apple-ios/release/libdash_spv_ffi.a" + if [ "$BUILD_ARCH" = "universal" ] && [ -f "$SPV_SIM_ARM" ] && [ -f "$SPV_SIM_X86" ]; then + # Universal: lipo both SPV sim slices into a fat library before merging + FAT_SPV_SIM="$OUTPUT_DIR/simulator/libdash_spv_ffi_fat.a" + lipo -create "$SPV_SIM_ARM" "$SPV_SIM_X86" -output "$FAT_SPV_SIM" + SIM_SPV_LIB="$FAT_SPV_SIM" + elif [ "$BUILD_ARCH" = "x86" ] && [ -f "$SPV_SIM_X86" ]; then + SIM_SPV_LIB="$SPV_SIM_X86" + elif [ -f "$SPV_SIM_ARM" ]; then + # arm (default) + SIM_SPV_LIB="$SPV_SIM_ARM" fi if [ -n "$SIM_SPV_LIB" ]; then echo -e "${GREEN}Merging simulator libs (rs-sdk-ffi + dash-spv-ffi)${NC}" @@ -470,6 +486,8 @@ if [ -f "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" ]; then grep -v "duplicate member name" "$LIBTOOL_LOG" >&2 || true rm -f "$LIBTOOL_LOG" mv "$OUTPUT_DIR/simulator/librs_sdk_ffi_merged.a" "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" + # Clean up temporary fat SPV archive if it was created + rm -f "$OUTPUT_DIR/simulator/libdash_spv_ffi_fat.a" fi XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/simulator/librs_sdk_ffi.a -headers $HEADERS_DIR" fi diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Account.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Account.swift index 49c51242b91..e9ce1c0afbb 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Account.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Account.swift @@ -27,36 +27,37 @@ public class Account { /// - index: The child index to derive (e.g., 0 for the first key) /// - Returns: The private key encoded as WIF public func derivePrivateKeyWIF(wallet: Wallet, masterPath: String, index: UInt32) throws -> String { - var error = FFIError() + var deriveError = FFIError() // Derive master extended private key for this account root let masterPtr = masterPath.withCString { pathCStr in - wallet_derive_extended_private_key(wallet.ffiHandle, pathCStr, &error) + wallet_derive_extended_private_key(wallet.ffiHandle, pathCStr, &deriveError) } - + defer { - if error.message != nil { - error_message_free(error.message) + if deriveError.message != nil { + error_message_free(deriveError.message) } if let m = masterPtr { extended_private_key_free(m) } } - + guard let master = masterPtr else { - throw KeyWalletError(ffiError: error) + throw KeyWalletError(ffiError: deriveError) } - + // Derive child private key as WIF at the given index - let wifPtr = account_derive_private_key_as_wif_at(self.handle, master, index, &error) - + var wifError = FFIError() + let wifPtr = account_derive_private_key_as_wif_at(self.handle, master, index, &wifError) + defer { - if error.message != nil { - error_message_free(error.message) + if wifError.message != nil { + error_message_free(wifError.message) } } - + guard let ptr = wifPtr else { - throw KeyWalletError(ffiError: error) + throw KeyWalletError(ffiError: wifError) } let wif = String(cString: ptr) string_free(ptr) diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift index e6ff58f24c5..0939f4ac905 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift @@ -22,6 +22,7 @@ public struct NetworkSet { /// Since the FFI no longer supports multi-network bitmaps, only the /// first network is used. public var ffiNetwork: FFINetwork { + assert(networks.count <= 1, "FFI only supports a single network; NetworkSet contains \(networks.count)") let network = networks.first ?? .mainnet return network.ffiValue } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift index 49f2c9ea42d..31b15e2c9bf 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift @@ -4,13 +4,10 @@ import DashSDKFFI /// Swift wrapper for managed wallet with address pool management and transaction checking public class ManagedWallet { private let handle: UnsafeMutablePointer - private let network: KeyWalletNetwork - + /// Create a managed wallet wrapper from a regular wallet /// - Parameter wallet: The wallet to manage public init(wallet: Wallet) throws { - self.network = wallet.network - var error = FFIError() guard let managedPointer = wallet_create_managed_wallet(wallet.ffiHandle, &error) else { defer { diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift index e93c2c6fa05..62161804e28 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift @@ -525,7 +525,7 @@ public class Wallet { internal var ffiHandle: UnsafeMutablePointer { handle } // Non-owning initializer for wallets obtained from WalletManager - public init(nonOwningHandle handle: UnsafeRawPointer, network: KeyWalletNetwork) { + internal init(nonOwningHandle handle: UnsafeRawPointer, network: KeyWalletNetwork) { self.handle = UnsafeMutablePointer(mutating: handle.bindMemory(to: FFIWallet.self, capacity: 1)) self.network = network self.ownsHandle = false diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift index 11e590dd2eb..ff6f10516fe 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift @@ -57,39 +57,61 @@ public class WalletManager { /// - network: The network type (ignored; manager network is used) /// - accountOptions: Account creation options /// - Returns: The wallet ID + @available(*, deprecated, message: "network parameter is ignored; the manager's network is used") + @discardableResult + public func addWallet(mnemonic: String, passphrase: String? = nil, + network: KeyWalletNetwork, + accountOptions: AccountCreationOption = .default) throws -> Data { + try addWallet(mnemonic: mnemonic, passphrase: passphrase, accountOptions: accountOptions) + } + + /// Add a wallet from mnemonic + /// - Parameters: + /// - mnemonic: The mnemonic phrase + /// - passphrase: Optional BIP39 passphrase + /// - accountOptions: Account creation options + /// - Returns: The wallet ID @discardableResult public func addWallet(mnemonic: String, passphrase: String? = nil, - network: KeyWalletNetwork = .mainnet, accountOptions: AccountCreationOption = .default) throws -> Data { var error = FFIError() + var walletBytesPtr: UnsafeMutablePointer? + var walletBytesLen: size_t = 0 + var walletId = [UInt8](repeating: 0, count: 32) let success = mnemonic.withCString { mnemonicCStr in - if case .specificAccounts = accountOptions { - var options = accountOptions.toFFIOptions() - - if let passphrase = passphrase { - return passphrase.withCString { passphraseCStr in - wallet_manager_add_wallet_from_mnemonic_with_options( - handle, mnemonicCStr, passphraseCStr, - &options, &error) - } - } else { - return wallet_manager_add_wallet_from_mnemonic_with_options( - handle, mnemonicCStr, nil, - &options, &error) + var options = accountOptions.toFFIOptions() + + if let passphrase = passphrase { + return passphrase.withCString { passphraseCStr in + wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( + handle, + mnemonicCStr, + passphraseCStr, + 0, + &options, + false, + false, + &walletBytesPtr, + &walletBytesLen, + &walletId, + &error + ) } } else { - if let passphrase = passphrase { - return passphrase.withCString { passphraseCStr in - wallet_manager_add_wallet_from_mnemonic( - handle, mnemonicCStr, passphraseCStr, - &error) - } - } else { - return wallet_manager_add_wallet_from_mnemonic( - handle, mnemonicCStr, nil, - &error) - } + return wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( + handle, + mnemonicCStr, + nil, + 0, + &options, + false, + false, + &walletBytesPtr, + &walletBytesLen, + &walletId, + &error + ) } } @@ -97,14 +119,16 @@ public class WalletManager { if error.message != nil { error_message_free(error.message) } + if let ptr = walletBytesPtr { + wallet_manager_free_wallet_bytes(ptr, walletBytesLen) + } } guard success else { throw KeyWalletError(ffiError: error) } - // Get the wallet IDs to return the newly added wallet ID - return try getWalletIds().last ?? Data() + return Data(walletId) } /// Add a wallet from mnemonic for multiple networks @@ -118,9 +142,8 @@ public class WalletManager { public func addWallet(mnemonic: String, passphrase: String? = nil, networks: [KeyWalletNetwork], accountOptions: AccountCreationOption = .default) throws -> Data { - let network = networks.first ?? .mainnet return try addWallet(mnemonic: mnemonic, passphrase: passphrase, - network: network, accountOptions: accountOptions) + accountOptions: accountOptions) } /// Get all wallet IDs @@ -209,10 +232,21 @@ public class WalletManager { /// Get next receive address for a wallet /// - Parameters: /// - walletId: The wallet ID - /// - network: The network type + /// - network: The network type (ignored; manager network is used) + /// - accountIndex: The account index + /// - Returns: The next receive address + @available(*, deprecated, message: "network parameter is ignored; the manager's network is used") + public func getReceiveAddress(walletId: Data, network: KeyWalletNetwork, + accountIndex: UInt32 = 0) throws -> String { + try getReceiveAddress(walletId: walletId, accountIndex: accountIndex) + } + + /// Get next receive address for a wallet + /// - Parameters: + /// - walletId: The wallet ID /// - accountIndex: The account index /// - Returns: The next receive address - public func getReceiveAddress(walletId: Data, network: KeyWalletNetwork = .mainnet, + public func getReceiveAddress(walletId: Data, accountIndex: UInt32 = 0) throws -> String { guard walletId.count == 32 else { throw KeyWalletError.invalidInput("Wallet ID must be exactly 32 bytes") @@ -273,10 +307,21 @@ public class WalletManager { /// Get next change address for a wallet /// - Parameters: /// - walletId: The wallet ID - /// - network: The network type + /// - network: The network type (ignored; manager network is used) + /// - accountIndex: The account index + /// - Returns: The next change address + @available(*, deprecated, message: "network parameter is ignored; the manager's network is used") + public func getChangeAddress(walletId: Data, network: KeyWalletNetwork, + accountIndex: UInt32 = 0) throws -> String { + try getChangeAddress(walletId: walletId, accountIndex: accountIndex) + } + + /// Get next change address for a wallet + /// - Parameters: + /// - walletId: The wallet ID /// - accountIndex: The account index /// - Returns: The next change address - public func getChangeAddress(walletId: Data, network: KeyWalletNetwork = .mainnet, + public func getChangeAddress(walletId: Data, accountIndex: UInt32 = 0) throws -> String { guard walletId.count == 32 else { throw KeyWalletError.invalidInput("Wallet ID must be exactly 32 bytes") @@ -377,9 +422,23 @@ public class WalletManager { /// - contextDetails: Transaction context details /// - updateStateIfFound: Whether to update wallet state if transaction is relevant /// - Returns: True if transaction was relevant to at least one wallet + @available(*, deprecated, message: "network parameter is ignored; the manager's network is used") + @discardableResult + public func processTransaction(_ transactionData: Data, + network: KeyWalletNetwork, + contextDetails: TransactionContextDetails, + updateStateIfFound: Bool = true) throws -> Bool { + try processTransaction(transactionData, contextDetails: contextDetails, updateStateIfFound: updateStateIfFound) + } + + /// Process a transaction through all wallets + /// - Parameters: + /// - transactionData: The transaction bytes + /// - contextDetails: Transaction context details + /// - updateStateIfFound: Whether to update wallet state if transaction is relevant + /// - Returns: True if transaction was relevant to at least one wallet @discardableResult public func processTransaction(_ transactionData: Data, - network: KeyWalletNetwork = .mainnet, contextDetails: TransactionContextDetails, updateStateIfFound: Bool = true) throws -> Bool { var error = FFIError() @@ -438,7 +497,19 @@ public class WalletManager { /// - accountIndex: The account index /// - accountType: The type of account to get /// - Returns: The managed account - public func getManagedAccount(walletId: Data, network: KeyWalletNetwork = .mainnet, + @available(*, deprecated, message: "network parameter is ignored; the manager's network is used") + public func getManagedAccount(walletId: Data, network: KeyWalletNetwork, + accountIndex: UInt32, accountType: AccountType) throws -> ManagedAccount { + try getManagedAccount(walletId: walletId, accountIndex: accountIndex, accountType: accountType) + } + + /// Get a managed account from a wallet + /// - Parameters: + /// - walletId: The wallet ID + /// - accountIndex: The account index + /// - accountType: The type of account to get + /// - Returns: The managed account + public func getManagedAccount(walletId: Data, accountIndex: UInt32, accountType: AccountType) throws -> ManagedAccount { guard walletId.count == 32 else { throw KeyWalletError.invalidInput("Wallet ID must be exactly 32 bytes") @@ -470,7 +541,18 @@ public class WalletManager { /// - network: The network type (ignored; manager network is used) /// - registrationIndex: The registration index /// - Returns: The managed account - public func getManagedTopUpAccount(walletId: Data, network: KeyWalletNetwork = .mainnet, + @available(*, deprecated, message: "network parameter is ignored; the manager's network is used") + public func getManagedTopUpAccount(walletId: Data, network: KeyWalletNetwork, + registrationIndex: UInt32) throws -> ManagedAccount { + try getManagedTopUpAccount(walletId: walletId, registrationIndex: registrationIndex) + } + + /// Get a managed top-up account with a specific registration index + /// - Parameters: + /// - walletId: The wallet ID + /// - registrationIndex: The registration index + /// - Returns: The managed account + public func getManagedTopUpAccount(walletId: Data, registrationIndex: UInt32) throws -> ManagedAccount { guard walletId.count == 32 else { throw KeyWalletError.invalidInput("Wallet ID must be exactly 32 bytes") @@ -501,7 +583,16 @@ public class WalletManager { /// - walletId: The wallet ID /// - network: The network type (ignored; manager network is used) /// - Returns: The managed account collection - public func getManagedAccountCollection(walletId: Data, network: KeyWalletNetwork = .mainnet) throws -> ManagedAccountCollection { + @available(*, deprecated, message: "network parameter is ignored; the manager's network is used") + public func getManagedAccountCollection(walletId: Data, network: KeyWalletNetwork) throws -> ManagedAccountCollection { + try getManagedAccountCollection(walletId: walletId) + } + + /// Get a collection of all managed accounts for a wallet + /// - Parameters: + /// - walletId: The wallet ID + /// - Returns: The managed account collection + public func getManagedAccountCollection(walletId: Data) throws -> ManagedAccountCollection { guard walletId.count == 32 else { throw KeyWalletError.invalidInput("Wallet ID must be exactly 32 bytes") } @@ -540,10 +631,38 @@ public class WalletManager { /// - downgradeToPublicKeyWallet: If true, creates a watch-only or externally signable wallet /// - allowExternalSigning: If true AND downgradeToPublicKeyWallet is true, creates an externally signable wallet /// - Returns: Tuple containing (walletId: Data, serializedWallet: Data) + @available(*, deprecated, message: "network parameter is ignored; the manager's network is used") + public func addWalletAndSerialize( + mnemonic: String, + passphrase: String? = nil, + network: KeyWalletNetwork, + birthHeight: UInt32 = 0, + accountOptions: AccountCreationOption = .default, + downgradeToPublicKeyWallet: Bool = false, + allowExternalSigning: Bool = false + ) throws -> (walletId: Data, serializedWallet: Data) { + try addWalletAndSerialize( + mnemonic: mnemonic, + passphrase: passphrase, + birthHeight: birthHeight, + accountOptions: accountOptions, + downgradeToPublicKeyWallet: downgradeToPublicKeyWallet, + allowExternalSigning: allowExternalSigning + ) + } + + /// Add a wallet from mnemonic and return serialized wallet bytes + /// - Parameters: + /// - mnemonic: The mnemonic phrase + /// - passphrase: Optional BIP39 passphrase + /// - birthHeight: Optional birth height for wallet + /// - accountOptions: Account creation options + /// - downgradeToPublicKeyWallet: If true, creates a watch-only or externally signable wallet + /// - allowExternalSigning: If true AND downgradeToPublicKeyWallet is true, creates an externally signable wallet + /// - Returns: Tuple containing (walletId: Data, serializedWallet: Data) public func addWalletAndSerialize( mnemonic: String, passphrase: String? = nil, - network: KeyWalletNetwork = .mainnet, birthHeight: UInt32 = 0, accountOptions: AccountCreationOption = .default, downgradeToPublicKeyWallet: Bool = false, @@ -630,11 +749,9 @@ public class WalletManager { downgradeToPublicKeyWallet: Bool = false, allowExternalSigning: Bool = false ) throws -> (walletId: Data, serializedWallet: Data) { - let network = networks.first ?? .mainnet return try addWalletAndSerialize( mnemonic: mnemonic, passphrase: passphrase, - network: network, birthHeight: birthHeight, accountOptions: accountOptions, downgradeToPublicKeyWallet: downgradeToPublicKeyWallet, diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/SPV/SPVClient.swift b/packages/swift-sdk/Sources/SwiftDashSDK/SPV/SPVClient.swift index 2afb45cc0cc..35bfa747112 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/SPV/SPVClient.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/SPV/SPVClient.swift @@ -486,8 +486,11 @@ public class SPVClient: ObservableObject { self.lastError = nil } - /// Clear only the persisted sync-state snapshot while keeping headers/filters. - /// Note: Uses clearStorage() as the granular clear_sync_state FFI was removed. + /// Clear all persisted SPV data (headers, filters, and sync state). + /// + /// - Note: The granular `clear_sync_state` FFI was removed; this now delegates + /// to ``clearStorage()`` which clears **everything**, not just the sync-state snapshot. + @available(*, deprecated, renamed: "clearStorage()") public func clearSyncState() throws { try clearStorage() } diff --git a/packages/swift-sdk/build_ios.sh b/packages/swift-sdk/build_ios.sh index 0781320e040..7ac75707958 100755 --- a/packages/swift-sdk/build_ios.sh +++ b/packages/swift-sdk/build_ios.sh @@ -45,6 +45,7 @@ echo " - Verifying required SPV symbols are present in XCFramework libs" # match, causing nm to receive SIGPIPE and return exit code 141. With pipefail # enabled, this makes the pipeline fail even though the symbol was found. NM_SYMBOLS=$(mktemp) +trap 'rm -f "$NM_SYMBOLS"' EXIT nm -gU "$LIB_SIM_MAIN" > "$NM_SYMBOLS" 2>/dev/null || true if [[ -f "$LIB_SIM_SPV" ]]; then nm -gU "$LIB_SIM_SPV" >> "$NM_SYMBOLS" 2>/dev/null || true From 9095c0e634b2c991af63b1dfa50ab9dcd97c4826 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 19 Feb 2026 17:46:14 +0100 Subject: [PATCH 10/19] chore: cargo.lock update --- Cargo.lock | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cf357c554be..437c6d25d7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -776,25 +776,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" -[[package]] -name = "cbindgen" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb" -dependencies = [ - "clap", - "heck 0.4.1", - "indexmap 2.13.0", - "log", - "proc-macro2", - "quote", - "serde", - "serde_json", - "syn 2.0.116", - "tempfile", - "toml 0.8.23", -] - [[package]] name = "cbindgen" version = "0.29.2" @@ -802,7 +783,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "befbfd072a8e81c02f8c507aefce431fe5e7d051f83d48a23ffc9b9fe5a11799" dependencies = [ "clap", - "heck 0.5.0", + "heck", "indexmap 2.13.0", "log", "proc-macro2", @@ -7843,7 +7824,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" dependencies = [ "anyhow", - "heck 0.5.0", + "heck", "wit-parser", ] @@ -7854,7 +7835,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", - "heck 0.5.0", + "heck", "indexmap 2.13.0", "prettyplease", "syn 2.0.116", From 22fe6a2041dcdc3acf61e2b6703b8afb3ac49c54 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 19 Feb 2026 17:56:35 +0100 Subject: [PATCH 11/19] fix(swift-sdk): replace deprecated clearSyncState() call with clearStorage() The SwiftExampleApp called clearSyncState() which is now deprecated and triggers a build error with warnings-as-errors. Since clearSyncState() already delegates to clearStorage(), use clearStorage() directly. Co-Authored-By: Claude Opus 4.6 --- .../SwiftExampleApp/Core/Services/WalletService.swift | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Services/WalletService.swift b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Services/WalletService.swift index e274fb22537..d2f246ac6db 100644 --- a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Services/WalletService.swift +++ b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Services/WalletService.swift @@ -527,11 +527,10 @@ public class WalletService: ObservableObject { let service = serviceBox.value do { - if fullReset { - try await client.clearStorage() - } else { - try await client.clearSyncState() - } + // clearSyncState() was deprecated (now delegates to clearStorage()), + // so we call clearStorage() unconditionally. + // The fullReset flag still controls resetAfterClearingStorage() below. + try await client.clearStorage() await MainActor.run { service.resetAfterClearingStorage(fullReset: fullReset) From 753218989ce1320e487789eaed052e68aa900fb6 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 19 Feb 2026 18:02:15 +0100 Subject: [PATCH 12/19] fix(swift-sdk): update SwiftExampleApp to use non-deprecated SDK methods Remove network: parameter from getManagedAccountCollection() and getManagedAccount() calls, using the non-deprecated overloads that rely on the WalletManager's instance-scoped network instead. Co-Authored-By: Claude Opus 4.6 --- .../Core/Wallet/WalletManager.swift | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Wallet/WalletManager.swift b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Wallet/WalletManager.swift index 0144410c522..8f7d0ac90ed 100644 --- a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Wallet/WalletManager.swift +++ b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Wallet/WalletManager.swift @@ -214,9 +214,8 @@ class WalletManager: ObservableObject { /// Sync wallet data using SwiftDashSDK wrappers (no direct FFI in app) private func syncWalletFromManagedInfo(for wallet: HDWallet) async throws { guard let walletId = wallet.walletId else { throw WalletError.walletError("Wallet ID not available") } - let network = wallet.dashNetwork.toKeyWalletNetwork() - let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId, network: network) - + let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId) + for account in wallet.accounts { if let managed = collection.getBIP44Account(at: account.accountNumber) { if let bal = try? managed.getBalance() { @@ -333,12 +332,9 @@ class WalletManager: ObservableObject { throw WalletError.walletError("Wallet ID not available") } - let network = wallet.dashNetwork.toKeyWalletNetwork() - // Get managed account let managedAccount = try sdkWalletManager.getManagedAccount( walletId: walletId, - network: network, accountIndex: accountIndex, accountType: .standardBIP44 ) @@ -358,8 +354,7 @@ class WalletManager: ObservableObject { /// - Returns: Detailed account information func getAccountDetails(for wallet: HDWallet, accountInfo: AccountInfo) async throws -> AccountDetailInfo { guard let walletId = wallet.walletId else { throw WalletError.walletError("Wallet ID not available") } - let network = wallet.dashNetwork.toKeyWalletNetwork() - let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId, network: network) + let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId) // Resolve managed account from category and optional index var managed: ManagedAccount? @@ -515,10 +510,9 @@ class WalletManager: ObservableObject { /// - Returns: Account information including balances and address counts func getAccounts(for wallet: HDWallet, network: Network? = nil) async throws -> [AccountInfo] { guard let walletId = wallet.walletId else { throw WalletError.walletError("Wallet ID not available") } - let effectiveNetwork = (network ?? wallet.dashNetwork).toKeyWalletNetwork() let collection: ManagedAccountCollection do { - collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId, network: effectiveNetwork) + collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId) } catch let err as KeyWalletError { // If the managed wallet info isn't found (e.g., after fresh start), try restoring from serialized bytes if case .notFound = err, let bytes = wallet.serializedWalletBytes { @@ -526,7 +520,7 @@ class WalletManager: ObservableObject { let restoredId = try sdkWalletManager.importWallet(from: bytes) if wallet.walletId != restoredId { wallet.walletId = restoredId } // Retry once after import - collection = try sdkWalletManager.getManagedAccountCollection(walletId: wallet.walletId!, network: effectiveNetwork) + collection = try sdkWalletManager.getManagedAccountCollection(walletId: wallet.walletId!) } catch { throw err } @@ -687,7 +681,7 @@ class WalletManager: ObservableObject { // Get balance via SDK wrappers do { - let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId, network: wallet.dashNetwork.toKeyWalletNetwork()) + let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId) if let managed = collection.getBIP44Account(at: account.accountNumber) { if let bal = try? managed.getBalance() { account.confirmedBalance = bal.confirmed @@ -705,10 +699,8 @@ class WalletManager: ObservableObject { func syncWalletStateFromRust(for wallet: HDWallet) async { guard let walletId = wallet.walletId else { return } - let network = wallet.dashNetwork.toKeyWalletNetwork() - do { - let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId, network: network) + let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId) // Sync all accounts for account in wallet.accounts { From 7b7369c5194e4d718772466433a50c2e776a3739 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 23 Feb 2026 09:33:47 +0100 Subject: [PATCH 13/19] fix(swift-sdk): honour CARGO_TARGET_DIR override for SPV target directory If a CI environment or developer sets CARGO_TARGET_DIR, the hardcoded SPV_TARGET_DIR path silently diverges from where Cargo actually writes artifacts. Use parameter expansion to respect the override while falling back to the workspace root target directory. Co-Authored-By: Claude Opus 4.6 --- packages/rs-sdk-ffi/build_ios.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rs-sdk-ffi/build_ios.sh b/packages/rs-sdk-ffi/build_ios.sh index 36bf4082d40..72d18f19cd9 100755 --- a/packages/rs-sdk-ffi/build_ios.sh +++ b/packages/rs-sdk-ffi/build_ios.sh @@ -323,7 +323,7 @@ fi # Build dash-spv-ffi from local rust-dashcore for device and simulator RUST_DASHCORE_PATH="$PROJECT_ROOT/../rust-dashcore" SPV_CRATE_PATH="$RUST_DASHCORE_PATH/dash-spv-ffi" -SPV_TARGET_DIR="$RUST_DASHCORE_PATH/target" # workspace root target dir +SPV_TARGET_DIR="${CARGO_TARGET_DIR:-$RUST_DASHCORE_PATH/target}" # honour override; default to workspace root if [ -d "$SPV_CRATE_PATH" ]; then echo -e "${GREEN}Building dash-spv-ffi (local rust-dashcore)${NC}" pushd "$SPV_CRATE_PATH" >/dev/null From a2d9d1921fcf9911fb602838d4177a2698f0e949 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 23 Feb 2026 09:33:59 +0100 Subject: [PATCH 14/19] fix(swift-sdk): make simulator SPV lib selection strictly architecture-aware The fallback branch in the SPV lib selection could pick an arm64 SPV library even when BUILD_ARCH=x86, if a stale arm64 build artifact existed. Gate the arm64 fallback on BUILD_ARCH != x86 to prevent merging mismatched architectures via libtool. Co-Authored-By: Claude Opus 4.6 --- packages/rs-sdk-ffi/build_ios.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/rs-sdk-ffi/build_ios.sh b/packages/rs-sdk-ffi/build_ios.sh index 72d18f19cd9..4266e7f0040 100755 --- a/packages/rs-sdk-ffi/build_ios.sh +++ b/packages/rs-sdk-ffi/build_ios.sh @@ -468,8 +468,9 @@ if [ -f "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" ]; then SIM_SPV_LIB="$FAT_SPV_SIM" elif [ "$BUILD_ARCH" = "x86" ] && [ -f "$SPV_SIM_X86" ]; then SIM_SPV_LIB="$SPV_SIM_X86" - elif [ -f "$SPV_SIM_ARM" ]; then - # arm (default) + elif [ "$BUILD_ARCH" != "x86" ] && [ -f "$SPV_SIM_ARM" ]; then + # arm64 (default) — only pick the arm64 SPV lib when NOT building for x86, + # to prevent merging a mismatched architecture from a stale build. SIM_SPV_LIB="$SPV_SIM_ARM" fi if [ -n "$SIM_SPV_LIB" ]; then From 46ac1fac4f8910b85fd34ed413edbcd215c9cb6e Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 23 Feb 2026 09:34:13 +0100 Subject: [PATCH 15/19] fix(swift-sdk): clean up temporary fat SPV archive on libtool failure The FAT_SPV_SIM archive was only removed on the success path. If libtool failed, the stale file was left behind. Clean it up in the error path as well, using ${FAT_SPV_SIM:-} to safely handle the case where the variable is unset (non-universal builds). Co-Authored-By: Claude Opus 4.6 --- packages/rs-sdk-ffi/build_ios.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rs-sdk-ffi/build_ios.sh b/packages/rs-sdk-ffi/build_ios.sh index 4266e7f0040..67963027c2f 100755 --- a/packages/rs-sdk-ffi/build_ios.sh +++ b/packages/rs-sdk-ffi/build_ios.sh @@ -480,7 +480,7 @@ if [ -f "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" ]; then "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" \ "$SIM_SPV_LIB" 2>"$LIBTOOL_LOG"; then cat "$LIBTOOL_LOG" >&2 - rm -f "$LIBTOOL_LOG" + rm -f "$LIBTOOL_LOG" "${FAT_SPV_SIM:-}" exit 1 fi # Filter out expected duplicate member warnings (shared deps between the two libs) @@ -488,7 +488,7 @@ if [ -f "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" ]; then rm -f "$LIBTOOL_LOG" mv "$OUTPUT_DIR/simulator/librs_sdk_ffi_merged.a" "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" # Clean up temporary fat SPV archive if it was created - rm -f "$OUTPUT_DIR/simulator/libdash_spv_ffi_fat.a" + rm -f "${FAT_SPV_SIM:-}" fi XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/simulator/librs_sdk_ffi.a -headers $HEADERS_DIR" fi From 6ca7174eaefee309d09d2793831de2bdb313b24c Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 23 Feb 2026 09:34:27 +0100 Subject: [PATCH 16/19] fix(swift-sdk): remove double-free in Wallet.init(xpub:network:) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When addAccount threw, the catch block called wallet_free(handle) manually, but ownsHandle was already true and deinit would free the handle again—classic double-free. Since Swift calls deinit on a partially-initialised object when a designated init throws (after all stored properties are set), the manual free is unnecessary. Remove the do/catch wrapper and let deinit handle cleanup. Co-Authored-By: Claude Opus 4.6 --- .../Sources/SwiftDashSDK/KeyWallet/Wallet.swift | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift index 62161804e28..8ad2dea296a 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift @@ -171,14 +171,9 @@ public class Wallet { self.handle = handle self.ownsHandle = true - // Now add the watch-only account with the provided xpub - do { - _ = try addAccount(type: .standardBIP44, index: 0, xpub: xpub) - } catch { - // Clean up the wallet if adding account failed - wallet_free(handle) - throw error - } + // Now add the watch-only account with the provided xpub. + // If this throws, deinit will free the handle (ownsHandle is true). + _ = try addAccount(type: .standardBIP44, index: 0, xpub: xpub) } /// Create a new random wallet From 0aa0dd9a5f1fd2b2067083829c696ed3e1143547 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 23 Feb 2026 09:34:41 +0100 Subject: [PATCH 17/19] fix(swift-sdk): correct misleading log message after clearStorage() Both the fullReset and partial code paths now call clearStorage(), so the old "sync-state" vs "full storage" wording was inaccurate. Update the log to reflect that storage is always cleared and only the post-clear UI reset scope differs. Co-Authored-By: Claude Opus 4.6 --- .../SwiftExampleApp/Core/Services/WalletService.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Services/WalletService.swift b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Services/WalletService.swift index d2f246ac6db..30647af3c29 100644 --- a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Services/WalletService.swift +++ b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Services/WalletService.swift @@ -564,8 +564,8 @@ public class WalletService: ObservableObject { detailedSyncProgress = nil lastSyncError = nil - let modeDescription = fullReset ? "full storage" : "sync-state" - print("[SPV][Clear] Completed \(modeDescription) reset for \(currentNetwork.rawValue)") + let resetDescription = fullReset ? "full" : "partial" + print("[SPV][Clear] Completed storage clear + \(resetDescription) UI reset for \(currentNetwork.rawValue)") } // MARK: - Network Management From e15234e2d3947334980da7441a1c138d66437e4f Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 23 Feb 2026 09:35:13 +0100 Subject: [PATCH 18/19] fix(swift-sdk): reinitialise FFIError before each sequential FFI call getReceiveAddress and getChangeAddress reuse a single FFIError across three sequential FFI calls. If an FFI function ever set a non-null error message on a successful return, the prior message would leak. Reinitialise the error struct before each call to make the contract explicit and prevent potential memory leaks. Co-Authored-By: Claude Opus 4.6 --- .../SwiftDashSDK/KeyWallet/WalletManager.swift | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift index ff6f10516fe..f9e47a2fef0 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift @@ -271,7 +271,8 @@ public class WalletManager { managed_wallet_info_free(managedInfo) } - // Get the wallet + // Get the wallet — reinitialise error to avoid leaking a prior message + error = FFIError() guard let wallet = walletId.withUnsafeBytes({ idBytes in let idPtr = idBytes.bindMemory(to: UInt8.self).baseAddress return wallet_manager_get_wallet(handle, idPtr, &error) @@ -284,7 +285,8 @@ public class WalletManager { throw KeyWalletError(ffiError: error) } - // Now get the receive address + // Now get the receive address — reinitialise error for the same reason + error = FFIError() let addressPtr = managed_wallet_get_next_bip44_receive_address( managedInfo, wallet, accountIndex, &error) @@ -346,7 +348,8 @@ public class WalletManager { managed_wallet_info_free(managedInfo) } - // Get the wallet + // Get the wallet — reinitialise error to avoid leaking a prior message + error = FFIError() guard let wallet = walletId.withUnsafeBytes({ idBytes in let idPtr = idBytes.bindMemory(to: UInt8.self).baseAddress return wallet_manager_get_wallet(handle, idPtr, &error) @@ -359,7 +362,8 @@ public class WalletManager { throw KeyWalletError(ffiError: error) } - // Now get the change address + // Now get the change address — reinitialise error for the same reason + error = FFIError() let addressPtr = managed_wallet_get_next_bip44_change_address( managedInfo, wallet, accountIndex, &error) From 090126ff9de4f153c2e1cbf26363cf0f6197aadc Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 23 Feb 2026 09:35:33 +0100 Subject: [PATCH 19/19] fix(swift-sdk): warn when multi-network wallet overloads silently drop networks addWallet(networks:) and addWalletAndSerialize(networks:) accept an array of KeyWalletNetwork but delegate to the single-network variant, silently discarding extras. Add a runtime log when networks.count > 1 so callers get a visible diagnostic instead of silent data loss. Co-Authored-By: Claude Opus 4.6 --- .../Sources/SwiftDashSDK/KeyWallet/WalletManager.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift index f9e47a2fef0..c34be5cc01b 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift @@ -142,6 +142,9 @@ public class WalletManager { public func addWallet(mnemonic: String, passphrase: String? = nil, networks: [KeyWalletNetwork], accountOptions: AccountCreationOption = .default) throws -> Data { + if networks.count > 1 { + print("[WalletManager] Warning: addWallet(networks:) received \(networks.count) networks \(networks), but only the manager's network is used. Extra networks are ignored.") + } return try addWallet(mnemonic: mnemonic, passphrase: passphrase, accountOptions: accountOptions) } @@ -753,6 +756,9 @@ public class WalletManager { downgradeToPublicKeyWallet: Bool = false, allowExternalSigning: Bool = false ) throws -> (walletId: Data, serializedWallet: Data) { + if networks.count > 1 { + print("[WalletManager] Warning: addWalletAndSerialize(networks:) received \(networks.count) networks \(networks), but only the manager's network is used. Extra networks are ignored.") + } return try addWalletAndSerialize( mnemonic: mnemonic, passphrase: passphrase,