diff --git a/packages/rs-drive-abci/tests/strategy_tests/execution.rs b/packages/rs-drive-abci/tests/strategy_tests/execution.rs index 60b8c884a3..f0ca6aa4af 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/execution.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/execution.rs @@ -792,7 +792,7 @@ pub(crate) fn create_chain_for_strategy( strategy: NetworkStrategy, config: PlatformConfig, rng: StdRng, -) -> ChainExecutionOutcome { +) -> ChainExecutionOutcome<'_> { let abci_application = FullAbciApplication::new(platform); let seed = strategy diff --git a/packages/rs-drive/src/drive/document/paths.rs b/packages/rs-drive/src/drive/document/paths.rs index 9d1c0516d9..3cb642a19b 100644 --- a/packages/rs-drive/src/drive/document/paths.rs +++ b/packages/rs-drive/src/drive/document/paths.rs @@ -1,7 +1,11 @@ use crate::drive::{constants, RootTree}; +#[cfg(feature = "server")] use crate::util::type_constants::DEFAULT_HASH_SIZE_U8; +#[cfg(feature = "server")] use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; +#[cfg(feature = "server")] use dpp::data_contract::document_type::methods::DocumentTypeBasicMethods; +#[cfg(feature = "server")] use dpp::data_contract::document_type::DocumentTypeRef; #[cfg(feature = "server")] use grovedb::batch::key_info::KeyInfo; @@ -36,7 +40,7 @@ pub(crate) fn contract_document_type_path_vec( ] } -#[cfg(any(feature = "server", feature = "verify"))] +#[cfg(feature = "server")] /// Returns the path to the primary keys of a contract document type. pub(crate) fn contract_documents_primary_key_path<'a>( contract_id: &'a [u8], diff --git a/packages/rs-drive/src/drive/identity/key/fetch/mod.rs b/packages/rs-drive/src/drive/identity/key/fetch/mod.rs index 3a3951a474..909a5a20ce 100644 --- a/packages/rs-drive/src/drive/identity/key/fetch/mod.rs +++ b/packages/rs-drive/src/drive/identity/key/fetch/mod.rs @@ -13,15 +13,15 @@ use { }, query::{Query, QueryItem}, }, - dpp::{ - identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0, - identity::{KeyID, Purpose, SecurityLevel}, - }, + dpp::identity::{KeyID, Purpose, SecurityLevel}, grovedb::{PathQuery, SizedQuery}, integer_encoding::VarInt, std::{collections::BTreeMap, ops::RangeFull}, }; +#[cfg(feature = "server")] +use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; + #[cfg(feature = "server")] use { crate::error::{drive::DriveError, fee::FeeError, identity::IdentityError, Error}, diff --git a/packages/rs-drive/src/drive/identity/withdrawals/document/fetch_oldest_withdrawal_documents_by_status/v0/mod.rs b/packages/rs-drive/src/drive/identity/withdrawals/document/fetch_oldest_withdrawal_documents_by_status/v0/mod.rs index 1ecf53df25..0006afffbe 100644 --- a/packages/rs-drive/src/drive/identity/withdrawals/document/fetch_oldest_withdrawal_documents_by_status/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/withdrawals/document/fetch_oldest_withdrawal_documents_by_status/v0/mod.rs @@ -438,10 +438,10 @@ mod tests { let doc_value: serde_json::Value = serde_json::from_str(doc_json).expect("Failed to parse withdrawal document JSON"); - // Extract required fields - let status = doc_value["status"] - .as_u64() - .expect("status should be a number") as u8; + // // Extract required fields + // let status = doc_value["status"] + // .as_u64() + // .expect("status should be a number") as u8; let mut properties: Value = doc_value.clone().into(); diff --git a/packages/rs-drive/src/drive/votes/resolved/vote_polls/contested_document_resource_vote_poll/resolve.rs b/packages/rs-drive/src/drive/votes/resolved/vote_polls/contested_document_resource_vote_poll/resolve.rs index 933c747724..a1cb9bc1ef 100644 --- a/packages/rs-drive/src/drive/votes/resolved/vote_polls/contested_document_resource_vote_poll/resolve.rs +++ b/packages/rs-drive/src/drive/votes/resolved/vote_polls/contested_document_resource_vote_poll/resolve.rs @@ -20,8 +20,9 @@ use dpp::prelude::DataContract; use dpp::voting::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePoll; #[cfg(feature = "server")] use grovedb::TransactionArg; +#[cfg(feature = "server")] use platform_version::version::PlatformVersion; -#[cfg(any(feature = "server", feature = "verify"))] +#[cfg(feature = "server")] use std::sync::Arc; /// A trait for resolving information related to a contested document resource vote poll. diff --git a/packages/rs-drive/src/query/mod.rs b/packages/rs-drive/src/query/mod.rs index ae609403d3..dbbf500528 100644 --- a/packages/rs-drive/src/query/mod.rs +++ b/packages/rs-drive/src/query/mod.rs @@ -24,10 +24,7 @@ use { document_type::{DocumentTypeRef, Index, IndexProperty}, DataContract, }, - document::{ - document_methods::DocumentMethodsV0, - serialization_traits::DocumentPlatformConversionMethodsV0, Document, DocumentV0Getters, - }, + document::{document_methods::DocumentMethodsV0, Document, DocumentV0Getters}, platform_value::{btreemap_extensions::BTreeValueRemoveFromMapHelper, Value}, version::PlatformVersion, ProtocolError, @@ -41,9 +38,11 @@ use { std::{collections::BTreeMap, ops::BitXor}, }; -#[cfg(feature = "verify")] +#[cfg(all(feature = "server", feature = "verify"))] use crate::verify::RootHash; +#[cfg(feature = "server")] +use dpp::document::serialization_traits::DocumentPlatformConversionMethodsV0; #[cfg(feature = "server")] pub use grovedb::{ query_result_type::{QueryResultElements, QueryResultType}, diff --git a/packages/rs-drive/src/query/vote_poll_vote_state_query.rs b/packages/rs-drive/src/query/vote_poll_vote_state_query.rs index 4915267810..7b616b06c2 100644 --- a/packages/rs-drive/src/query/vote_poll_vote_state_query.rs +++ b/packages/rs-drive/src/query/vote_poll_vote_state_query.rs @@ -19,13 +19,15 @@ use dpp::data_contract::DataContract; use dpp::identifier::Identifier; #[cfg(feature = "server")] use dpp::serialization::PlatformDeserializable; +#[cfg(feature = "server")] +use dpp::voting::contender_structs::ContenderWithSerializedDocumentV0; use dpp::voting::contender_structs::{ - ContenderWithSerializedDocument, ContenderWithSerializedDocumentV0, - FinalizedContenderWithSerializedDocument, -}; -use dpp::voting::vote_info_storage::contested_document_vote_poll_stored_info::{ - ContestedDocumentVotePollStoredInfo, ContestedDocumentVotePollStoredInfoV0Getters, + ContenderWithSerializedDocument, FinalizedContenderWithSerializedDocument, }; +#[cfg(feature = "server")] +use dpp::voting::vote_info_storage::contested_document_vote_poll_stored_info::ContestedDocumentVotePollStoredInfo; +#[cfg(feature = "server")] +use dpp::voting::vote_info_storage::contested_document_vote_poll_stored_info::ContestedDocumentVotePollStoredInfoV0Getters; use dpp::voting::vote_info_storage::contested_document_vote_poll_winner_info::ContestedDocumentVotePollWinnerInfo; use dpp::voting::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePoll; #[cfg(feature = "server")] diff --git a/packages/rs-drive/src/query/vote_polls_by_document_type_query.rs b/packages/rs-drive/src/query/vote_polls_by_document_type_query.rs index 59458a4c22..7014533ece 100644 --- a/packages/rs-drive/src/query/vote_polls_by_document_type_query.rs +++ b/packages/rs-drive/src/query/vote_polls_by_document_type_query.rs @@ -377,6 +377,7 @@ impl<'a> ResolvedVotePollsByDocumentTypeQuery<'a> { } /// Operations to construct a path query. + #[allow(dead_code)] pub(crate) fn construct_path_query( &self, platform_version: &PlatformVersion, diff --git a/packages/rs-drive/src/query/vote_polls_by_end_date_query.rs b/packages/rs-drive/src/query/vote_polls_by_end_date_query.rs index 21d859fd66..12aad421eb 100644 --- a/packages/rs-drive/src/query/vote_polls_by_end_date_query.rs +++ b/packages/rs-drive/src/query/vote_polls_by_end_date_query.rs @@ -1,14 +1,18 @@ use crate::drive::votes::paths::vote_end_date_queries_tree_path_vec; +#[cfg(feature = "server")] use crate::drive::Drive; #[cfg(feature = "server")] use crate::error::drive::DriveError; +#[cfg(feature = "server")] use crate::error::Error; #[cfg(feature = "server")] use crate::fees::op::LowLevelDriveOperation; #[cfg(feature = "server")] use crate::query::GroveError; use crate::query::Query; -use crate::util::common::encode::{decode_u64, encode_u64}; +#[cfg(feature = "server")] +use crate::util::common::encode::decode_u64; +use crate::util::common::encode::encode_u64; use bincode::{Decode, Encode}; #[cfg(feature = "server")] use dpp::block::block_info::BlockInfo; diff --git a/packages/rs-drive/src/util/object_size_info/contract_info.rs b/packages/rs-drive/src/util/object_size_info/contract_info.rs index fff3c68550..f3fa0ae2e1 100644 --- a/packages/rs-drive/src/util/object_size_info/contract_info.rs +++ b/packages/rs-drive/src/util/object_size_info/contract_info.rs @@ -11,9 +11,11 @@ use crate::fees::op::LowLevelDriveOperation; #[cfg(feature = "server")] use dpp::block::block_info::BlockInfo; use dpp::data_contract::accessors::v0::DataContractV0Getters; +#[cfg(feature = "server")] use dpp::data_contract::document_type::DocumentTypeRef; use dpp::data_contract::DataContract; use dpp::identifier::Identifier; +#[cfg(feature = "server")] use dpp::ProtocolError; #[cfg(feature = "server")] use grovedb::TransactionArg; @@ -26,6 +28,7 @@ use std::sync::Arc; /// might be needed, providing a unified interface to access their data. #[allow(clippy::large_enum_variant)] #[derive(Clone, Debug)] +#[cfg(feature = "server")] pub enum DataContractInfo<'a> { /// A unique identifier for a data contract. This variant is typically used /// when only the identity of the data contract is required without needing @@ -47,6 +50,7 @@ pub enum DataContractInfo<'a> { OwnedDataContract(DataContract), } +#[cfg(feature = "server")] impl<'a> DataContractInfo<'a> { #[cfg(feature = "server")] /// Resolve the data contract info into an object that contains the data contract @@ -208,7 +212,9 @@ impl AsRef for DataContractResolvedInfo<'_> { } /// Enumerates methods for identifying or referencing document types, accommodating various application needs. +#[allow(clippy::enum_variant_names)] #[derive(Clone, Debug)] +#[cfg(feature = "server")] pub enum DocumentTypeInfo<'a> { /// Contains the document type name as an owned `String`, suitable for dynamic or mutable scenarios. DocumentTypeName(String), @@ -220,6 +226,7 @@ pub enum DocumentTypeInfo<'a> { DocumentTypeRef(DocumentTypeRef<'a>), } +#[cfg(feature = "server")] impl<'a> DocumentTypeInfo<'a> { /// Resolve the data contract info into an object that contains the data contract pub fn resolve(self, contract: &'a DataContract) -> Result, ProtocolError> { diff --git a/packages/rs-drive/src/util/type_constants.rs b/packages/rs-drive/src/util/type_constants.rs index 8979cca62a..c55210da81 100644 --- a/packages/rs-drive/src/util/type_constants.rs +++ b/packages/rs-drive/src/util/type_constants.rs @@ -1,3 +1,7 @@ +#![allow(dead_code)] +// Common numeric type-size constants used across Drive. +// Many are referenced conditionally; allow dead_code at file scope. + /// Default hash size pub const DEFAULT_HASH_SIZE_USIZE: usize = 32; /// Default hash 160 size as u8 diff --git a/packages/rs-sdk-ffi/src/callback_bridge.rs b/packages/rs-sdk-ffi/src/callback_bridge.rs index 0c7b91b5c3..b526016f85 100644 --- a/packages/rs-sdk-ffi/src/callback_bridge.rs +++ b/packages/rs-sdk-ffi/src/callback_bridge.rs @@ -55,7 +55,7 @@ unsafe extern "C" fn bridge_get_platform_activation_height( return CallbackResult { success: false, error_code: -1, - error_message: "Invalid handle or output pointer\0".as_ptr() as *const i8, + error_message: c"Invalid handle or output pointer".as_ptr(), }; } @@ -80,7 +80,7 @@ unsafe extern "C" fn bridge_get_platform_activation_height( CallbackResult { success: false, error_code: result, - error_message: "Failed to get platform activation height\0".as_ptr() as *const i8, + error_message: c"Failed to get platform activation height".as_ptr(), } } } @@ -104,7 +104,7 @@ unsafe extern "C" fn bridge_get_quorum_public_key( return CallbackResult { success: false, error_code: -1, - error_message: "Invalid handle or pointer parameters\0".as_ptr() as *const i8, + error_message: c"Invalid handle or pointer parameters".as_ptr(), }; } @@ -139,7 +139,7 @@ unsafe extern "C" fn bridge_get_quorum_public_key( CallbackResult { success: false, error_code: result, - error_message: "Failed to get quorum public key\0".as_ptr() as *const i8, + error_message: c"Failed to get quorum public key".as_ptr(), } } } diff --git a/packages/rs-sdk-ffi/src/contested_resource/mod.rs b/packages/rs-sdk-ffi/src/contested_resource/mod.rs index f080b01bc1..b1ba67a504 100644 --- a/packages/rs-sdk-ffi/src/contested_resource/mod.rs +++ b/packages/rs-sdk-ffi/src/contested_resource/mod.rs @@ -1,5 +1,5 @@ // Contested resource modules -pub mod queries; +mod queries; // Re-export all public functions pub use queries::*; diff --git a/packages/rs-sdk-ffi/src/contested_resource/queries/identity_votes.rs b/packages/rs-sdk-ffi/src/contested_resource/queries/identity_votes.rs index 26c9b71ec9..130d7bd0de 100644 --- a/packages/rs-sdk-ffi/src/contested_resource/queries/identity_votes.rs +++ b/packages/rs-sdk-ffi/src/contested_resource/queries/identity_votes.rs @@ -20,7 +20,12 @@ use std::ffi::{c_char, c_void, CStr, CString}; /// * 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_contested_resource_get_identity_votes( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/contested_resource/queries/resources.rs b/packages/rs-sdk-ffi/src/contested_resource/queries/resources.rs index 9170cc860e..df641df86a 100644 --- a/packages/rs-sdk-ffi/src/contested_resource/queries/resources.rs +++ b/packages/rs-sdk-ffi/src/contested_resource/queries/resources.rs @@ -23,7 +23,14 @@ use std::ffi::{c_char, c_void, CStr, CString}; /// * 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_contested_resource_get_resources( sdk_handle: *const SDKHandle, @@ -81,6 +88,7 @@ pub unsafe extern "C" fn dash_sdk_contested_resource_get_resources( } } +#[allow(clippy::too_many_arguments)] fn get_contested_resources( sdk_handle: *const SDKHandle, contract_id: *const c_char, diff --git a/packages/rs-sdk-ffi/src/contested_resource/queries/vote_state.rs b/packages/rs-sdk-ffi/src/contested_resource/queries/vote_state.rs index 7a794a16d2..1007427d52 100644 --- a/packages/rs-sdk-ffi/src/contested_resource/queries/vote_state.rs +++ b/packages/rs-sdk-ffi/src/contested_resource/queries/vote_state.rs @@ -26,7 +26,13 @@ use std::ffi::{c_char, c_void, CStr, CString}; /// * 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_contested_resource_get_vote_state( sdk_handle: *const SDKHandle, @@ -84,6 +90,7 @@ pub unsafe extern "C" fn dash_sdk_contested_resource_get_vote_state( } } +#[allow(clippy::too_many_arguments)] fn get_contested_resource_vote_state( sdk_handle: *const SDKHandle, contract_id: *const c_char, diff --git a/packages/rs-sdk-ffi/src/contested_resource/queries/voters_for_identity.rs b/packages/rs-sdk-ffi/src/contested_resource/queries/voters_for_identity.rs index 182663c544..74429b5bf3 100644 --- a/packages/rs-sdk-ffi/src/contested_resource/queries/voters_for_identity.rs +++ b/packages/rs-sdk-ffi/src/contested_resource/queries/voters_for_identity.rs @@ -24,7 +24,13 @@ use std::ffi::{c_char, c_void, CStr, CString}; /// * 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_contested_resource_get_voters_for_identity( sdk_handle: *const SDKHandle, @@ -82,6 +88,7 @@ pub unsafe extern "C" fn dash_sdk_contested_resource_get_voters_for_identity( } } +#[allow(clippy::too_many_arguments)] fn get_contested_resource_voters_for_identity( sdk_handle: *const SDKHandle, contract_id: *const c_char, diff --git a/packages/rs-sdk-ffi/src/context_callbacks.rs b/packages/rs-sdk-ffi/src/context_callbacks.rs index 99fff22dcb..d0fe9bd6aa 100644 --- a/packages/rs-sdk-ffi/src/context_callbacks.rs +++ b/packages/rs-sdk-ffi/src/context_callbacks.rs @@ -101,7 +101,7 @@ impl CallbackContextProvider { /// Create from global callbacks if available pub fn from_global() -> Option { - get_global_callbacks().map(|callbacks| Self::new(callbacks)) + get_global_callbacks().map(Self::new) } } diff --git a/packages/rs-sdk-ffi/src/context_provider.rs b/packages/rs-sdk-ffi/src/context_provider.rs index c88434629c..66db6893d0 100644 --- a/packages/rs-sdk-ffi/src/context_provider.rs +++ b/packages/rs-sdk-ffi/src/context_provider.rs @@ -3,7 +3,6 @@ //! This module provides FFI bindings for configuring context providers, //! allowing the Platform SDK to connect to Core SDK for proof verification. -use std::ffi::c_char; use std::sync::Arc; use drive_proof_verifier::ContextProvider; diff --git a/packages/rs-sdk-ffi/src/context_provider_stubs.rs b/packages/rs-sdk-ffi/src/context_provider_stubs.rs index 2c18ca9c58..ceb29a841e 100644 --- a/packages/rs-sdk-ffi/src/context_provider_stubs.rs +++ b/packages/rs-sdk-ffi/src/context_provider_stubs.rs @@ -3,16 +3,18 @@ //! These are temporary stubs for testing compilation. //! In production, these symbols would be provided by linking against the Core SDK library. -use super::context_provider::CoreSDKHandle; +#[cfg(all(test, feature = "ffi_core_stubs", not(feature = "dash_spv")))] use std::ffi::c_char; // Local test-only definitions for stubs +#[cfg(all(test, feature = "ffi_core_stubs", not(feature = "dash_spv")))] #[repr(C)] pub struct FFIResult { pub error_code: i32, pub error_message: *const c_char, } +#[cfg(all(test, feature = "ffi_core_stubs", not(feature = "dash_spv")))] type FFIDashSpvClient = std::ffi::c_void; // Only compile stubs for tests when explicitly enabled AND dash-spv FFI is not linked. diff --git a/packages/rs-sdk-ffi/src/crypto/mod.rs b/packages/rs-sdk-ffi/src/crypto/mod.rs index be4806617c..b9b409baf7 100644 --- a/packages/rs-sdk-ffi/src/crypto/mod.rs +++ b/packages/rs-sdk-ffi/src/crypto/mod.rs @@ -6,6 +6,14 @@ use dash_sdk::dpp::identity::KeyType; use std::ffi::{c_char, CStr}; /// Validate that a private key corresponds to a public key using DPP's public_key_data_from_private_key_data +/// +/// # Safety +/// - `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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_validate_private_key_for_public_key( private_key_hex: *const c_char, @@ -115,6 +123,13 @@ pub unsafe extern "C" fn dash_sdk_validate_private_key_for_public_key( } /// Convert private key to WIF format +/// +/// # Safety +/// - `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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_private_key_to_wif( private_key_hex: *const c_char, @@ -161,7 +176,9 @@ pub unsafe extern "C" fn dash_sdk_private_key_to_wif( Network::Dash }; - match dash_sdk::dpp::dashcore::PrivateKey::from_slice(&private_key_bytes, network) { + let mut key_array = [0u8; 32]; + key_array.copy_from_slice(&private_key_bytes); + match dash_sdk::dpp::dashcore::PrivateKey::from_byte_array(&key_array, network) { Ok(private_key) => { let wif = private_key.to_wif(); match std::ffi::CString::new(wif) { @@ -180,6 +197,13 @@ pub unsafe extern "C" fn dash_sdk_private_key_to_wif( } /// Get public key data from private key data +/// +/// # Safety +/// - `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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_public_key_data_from_private_key_data( private_key_hex: *const c_char, diff --git a/packages/rs-sdk-ffi/src/data_contract/mod.rs b/packages/rs-sdk-ffi/src/data_contract/mod.rs index 06b77f12ec..9d3b1ae5e2 100644 --- a/packages/rs-sdk-ffi/src/data_contract/mod.rs +++ b/packages/rs-sdk-ffi/src/data_contract/mod.rs @@ -1,7 +1,7 @@ //! Data contract operations mod put; -pub mod queries; +mod queries; mod util; use std::ffi::CStr; @@ -32,6 +32,11 @@ pub struct DashSDKDataContractInfo { } /// Create a new data contract +/// +/// # Safety +/// - `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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_data_contract_create( sdk_handle: *mut SDKHandle, @@ -84,7 +89,7 @@ pub unsafe extern "C" fn dash_sdk_data_contract_create( .map_err(|e| FFIError::InternalError(format!("Failed to create factory: {}", e)))?; // Get identity nonce - let identity_nonce = identity.revision() as u64; + let identity_nonce = identity.revision(); // Create the data contract let created_contract = factory @@ -112,6 +117,10 @@ pub unsafe extern "C" fn dash_sdk_data_contract_create( } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_data_contract_destroy(handle: *mut DataContractHandle) { if !handle.is_null() { diff --git a/packages/rs-sdk-ffi/src/data_contract/put.rs b/packages/rs-sdk-ffi/src/data_contract/put.rs index d652848517..7d1873a41d 100644 --- a/packages/rs-sdk-ffi/src/data_contract/put.rs +++ b/packages/rs-sdk-ffi/src/data_contract/put.rs @@ -6,6 +6,10 @@ use crate::{ use dash_sdk::platform::{DataContract, IdentityPublicKey}; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_data_contract_put_to_platform( sdk_handle: *mut SDKHandle, @@ -60,6 +64,11 @@ pub unsafe extern "C" fn dash_sdk_data_contract_put_to_platform( } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_data_contract_put_to_platform_and_wait( sdk_handle: *mut SDKHandle, diff --git a/packages/rs-sdk-ffi/src/data_contract/queries/fetch.rs b/packages/rs-sdk-ffi/src/data_contract/queries/fetch.rs index 9f747d9b05..6b81183fc1 100644 --- a/packages/rs-sdk-ffi/src/data_contract/queries/fetch.rs +++ b/packages/rs-sdk-ffi/src/data_contract/queries/fetch.rs @@ -8,6 +8,11 @@ use std::ffi::CStr; use std::os::raw::c_char; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_data_contract_fetch( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/data_contract/queries/fetch_json.rs b/packages/rs-sdk-ffi/src/data_contract/queries/fetch_json.rs index fac817d16e..a2d4092755 100644 --- a/packages/rs-sdk-ffi/src/data_contract/queries/fetch_json.rs +++ b/packages/rs-sdk-ffi/src/data_contract/queries/fetch_json.rs @@ -8,6 +8,11 @@ use std::ffi::{CStr, CString}; use std::os::raw::c_char; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_data_contract_fetch_json( sdk_handle: *const SDKHandle, @@ -49,7 +54,7 @@ pub unsafe extern "C" fn dash_sdk_data_contract_fetch_json( let platform_version = wrapper.sdk.version(); // Convert to JSON - match contract.to_json(&platform_version) { + match contract.to_json(platform_version) { Ok(json_value) => match serde_json::to_string(&json_value) { Ok(json_string) => match CString::new(json_string) { Ok(c_str) => { diff --git a/packages/rs-sdk-ffi/src/data_contract/queries/fetch_many.rs b/packages/rs-sdk-ffi/src/data_contract/queries/fetch_many.rs index aab72f99c7..44fe4781bf 100644 --- a/packages/rs-sdk-ffi/src/data_contract/queries/fetch_many.rs +++ b/packages/rs-sdk-ffi/src/data_contract/queries/fetch_many.rs @@ -13,6 +13,11 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// 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 diff --git a/packages/rs-sdk-ffi/src/data_contract/queries/fetch_with_serialization.rs b/packages/rs-sdk-ffi/src/data_contract/queries/fetch_with_serialization.rs index 5e0a746c9c..983cd543fb 100644 --- a/packages/rs-sdk-ffi/src/data_contract/queries/fetch_with_serialization.rs +++ b/packages/rs-sdk-ffi/src/data_contract/queries/fetch_with_serialization.rs @@ -59,6 +59,12 @@ impl DashSDKDataContractFetchResult { } /// 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`. #[no_mangle] pub unsafe extern "C" fn dash_sdk_data_contract_fetch_with_serialization( sdk_handle: *const SDKHandle, @@ -105,7 +111,7 @@ pub unsafe extern "C" fn dash_sdk_data_contract_fetch_with_serialization( // Prepare JSON if requested let json = if return_json { - match contract.to_json(&platform_version) { + match contract.to_json(platform_version) { Ok(json_value) => match serde_json::to_string(&json_value) { Ok(json_string) => match CString::new(json_string) { Ok(c_str) => Some(c_str.into_raw()), @@ -148,6 +154,10 @@ pub unsafe extern "C" fn dash_sdk_data_contract_fetch_with_serialization( } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_data_contract_fetch_result_free( result: *mut DashSDKDataContractFetchResult, diff --git a/packages/rs-sdk-ffi/src/data_contract/queries/history.rs b/packages/rs-sdk-ffi/src/data_contract/queries/history.rs index 06e4a0bf97..6507755654 100644 --- a/packages/rs-sdk-ffi/src/data_contract/queries/history.rs +++ b/packages/rs-sdk-ffi/src/data_contract/queries/history.rs @@ -59,6 +59,11 @@ impl dash_sdk::platform::Query id, - }; + let dash_sdk::platform::documents::transitions::DocumentDeleteResult::Deleted(deleted_id) = result; Ok(deleted_id) }); @@ -380,6 +391,7 @@ mod tests { use std::ptr; // Helper function to create a mock document + #[allow(dead_code)] fn create_mock_document() -> Box { let id = Identifier::from_bytes(&[2u8; 32]).unwrap(); let owner_id = Identifier::from_bytes(&[1u8; 32]).unwrap(); @@ -390,7 +402,7 @@ mod tests { let document = Document::V0(DocumentV0 { id, owner_id, - properties: properties, + properties, revision: Some(1), created_at: None, updated_at: None, diff --git a/packages/rs-sdk-ffi/src/document/helpers.rs b/packages/rs-sdk-ffi/src/document/helpers.rs index 8fdc66b79e..d38b9b1587 100644 --- a/packages/rs-sdk-ffi/src/document/helpers.rs +++ b/packages/rs-sdk-ffi/src/document/helpers.rs @@ -13,6 +13,9 @@ use crate::types::{ use crate::FFIError; /// Convert FFI GasFeesPaidBy to Rust enum +/// +/// # Safety +/// - `ffi_value` is passed by value; no pointer preconditions. pub unsafe fn convert_gas_fees_paid_by(ffi_value: DashSDKGasFeesPaidBy) -> GasFeesPaidBy { match ffi_value { DashSDKGasFeesPaidBy::DocumentOwner => GasFeesPaidBy::DocumentOwner, @@ -22,6 +25,11 @@ pub unsafe fn convert_gas_fees_paid_by(ffi_value: DashSDKGasFeesPaidBy) -> GasFe } /// Convert FFI TokenPaymentInfo to Rust TokenPaymentInfo +/// +/// # Safety +/// - `ffi_token_payment_info` may be null; when non-null it must be a valid pointer to a `DashSDKTokenPaymentInfo` +/// that remains valid for the duration of the call. +#[allow(clippy::result_large_err)] pub unsafe fn convert_token_payment_info( ffi_token_payment_info: *const DashSDKTokenPaymentInfo, ) -> Result, FFIError> { @@ -60,6 +68,10 @@ pub unsafe fn convert_token_payment_info( } /// Convert FFI StateTransitionCreationOptions to Rust StateTransitionCreationOptions +/// +/// # Safety +/// - `ffi_options` may be null; when non-null it must be a valid pointer to a `DashSDKStateTransitionCreationOptions` +/// that remains valid for the duration of the call. pub unsafe fn convert_state_transition_creation_options( ffi_options: *const DashSDKStateTransitionCreationOptions, ) -> Option { diff --git a/packages/rs-sdk-ffi/src/document/mod.rs b/packages/rs-sdk-ffi/src/document/mod.rs index ba808243da..4205f9426a 100644 --- a/packages/rs-sdk-ffi/src/document/mod.rs +++ b/packages/rs-sdk-ffi/src/document/mod.rs @@ -1,14 +1,14 @@ //! Document operations -pub mod create; -pub mod delete; -pub mod helpers; -pub mod price; -pub mod purchase; -pub mod put; -pub mod queries; -pub mod replace; -pub mod transfer; +mod create; +mod delete; +mod helpers; +mod price; +mod purchase; +mod put; +mod queries; +mod replace; +mod transfer; mod util; // Re-export functions from submodules diff --git a/packages/rs-sdk-ffi/src/document/price.rs b/packages/rs-sdk-ffi/src/document/price.rs index 15cb640d48..bf026e3545 100644 --- a/packages/rs-sdk-ffi/src/document/price.rs +++ b/packages/rs-sdk-ffi/src/document/price.rs @@ -13,15 +13,21 @@ use dash_sdk::dpp::document::document_methods::DocumentMethodsV0; use dash_sdk::dpp::document::Document; use dash_sdk::dpp::fee::Credits; use dash_sdk::dpp::platform_value::string_encoding::Encoding; -use dash_sdk::dpp::prelude::{DataContract, Identifier, UserFeeIncrease}; +use dash_sdk::dpp::prelude::{Identifier, UserFeeIncrease}; use dash_sdk::platform::documents::transitions::DocumentSetPriceTransitionBuilder; use dash_sdk::platform::IdentityPublicKey; use drive_proof_verifier::ContextProvider; use std::ffi::CStr; use std::os::raw::c_char; -use std::sync::Arc; /// Update document price (broadcast state transition) +/// +/// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_update_price_of_document( sdk_handle: *mut SDKHandle, @@ -136,7 +142,7 @@ pub unsafe extern "C" fn dash_sdk_document_update_price_of_document( let state_transition = builder .sign( &wrapper.sdk, - &identity_public_key, + identity_public_key, signer, wrapper.sdk.version(), ) @@ -159,6 +165,11 @@ pub unsafe extern "C" fn dash_sdk_document_update_price_of_document( } /// Update document price and wait for confirmation (broadcast state transition and wait for response) +/// +/// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_update_price_of_document_and_wait( sdk_handle: *mut SDKHandle, @@ -272,17 +283,15 @@ pub unsafe extern "C" fn dash_sdk_document_update_price_of_document_and_wait( let result = wrapper .sdk - .document_set_price(builder, &identity_public_key, signer) + .document_set_price(builder, identity_public_key, signer) .await .map_err(|e| { FFIError::InternalError(format!("Failed to update document price and wait: {}", e)) })?; - let updated_document = match result { - dash_sdk::platform::documents::transitions::DocumentSetPriceResult::Document(doc) => { - doc - } - }; + let dash_sdk::platform::documents::transitions::DocumentSetPriceResult::Document( + updated_document, + ) = result; Ok(updated_document) }); @@ -303,7 +312,7 @@ pub unsafe extern "C" fn dash_sdk_document_update_price_of_document_and_wait( mod tests { use super::*; use crate::test_utils::test_utils::*; - use crate::types::DataContractHandle; + use crate::DashSDKErrorCode; use dash_sdk::dpp::document::{Document, DocumentV0}; @@ -329,7 +338,7 @@ mod tests { let document = Document::V0(DocumentV0 { id, owner_id, - properties: properties, + properties, revision: Some(1), created_at: None, updated_at: None, diff --git a/packages/rs-sdk-ffi/src/document/purchase.rs b/packages/rs-sdk-ffi/src/document/purchase.rs index 9a39b3abca..7f2c8c1348 100644 --- a/packages/rs-sdk-ffi/src/document/purchase.rs +++ b/packages/rs-sdk-ffi/src/document/purchase.rs @@ -16,11 +16,17 @@ use dash_sdk::dpp::prelude::{Identifier, UserFeeIncrease}; use dash_sdk::platform::documents::transitions::DocumentPurchaseTransitionBuilder; use dash_sdk::platform::IdentityPublicKey; use drive_proof_verifier::ContextProvider; -use hex; use std::ffi::CStr; use std::os::raw::c_char; /// Purchase document (broadcast state transition) +/// +/// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_purchase( sdk_handle: *mut SDKHandle, @@ -153,7 +159,7 @@ pub unsafe extern "C" fn dash_sdk_document_purchase( let state_transition = builder .sign( &wrapper.sdk, - &identity_public_key, + identity_public_key, signer, wrapper.sdk.version(), ) @@ -188,6 +194,11 @@ pub unsafe extern "C" fn dash_sdk_document_purchase( } /// Purchase document and wait for confirmation (broadcast state transition and wait for response) +/// +/// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_purchase_and_wait( sdk_handle: *mut SDKHandle, @@ -319,17 +330,15 @@ pub unsafe extern "C" fn dash_sdk_document_purchase_and_wait( let result = wrapper .sdk - .document_purchase(builder, &identity_public_key, signer) + .document_purchase(builder, identity_public_key, signer) .await .map_err(|e| { FFIError::InternalError(format!("Failed to purchase document and wait: {}", e)) })?; - let purchased_document = match result { - dash_sdk::platform::documents::transitions::DocumentPurchaseResult::Document(doc) => { - doc - } - }; + let dash_sdk::platform::documents::transitions::DocumentPurchaseResult::Document( + purchased_document, + ) = result; Ok(purchased_document) }); @@ -375,7 +384,7 @@ mod tests { let document = Document::V0(DocumentV0 { id, owner_id, - properties: properties, + properties, revision: Some(1), created_at: None, updated_at: None, diff --git a/packages/rs-sdk-ffi/src/document/put.rs b/packages/rs-sdk-ffi/src/document/put.rs index 8742461d17..18d5b8a58a 100644 --- a/packages/rs-sdk-ffi/src/document/put.rs +++ b/packages/rs-sdk-ffi/src/document/put.rs @@ -2,7 +2,7 @@ use dash_sdk::dpp::document::{Document, DocumentV0Getters}; use dash_sdk::dpp::platform_value::string_encoding::Encoding; -use dash_sdk::dpp::prelude::{DataContract, Identifier, UserFeeIncrease}; +use dash_sdk::dpp::prelude::{Identifier, UserFeeIncrease}; use dash_sdk::platform::documents::transitions::{ DocumentCreateTransitionBuilder, DocumentReplaceTransitionBuilder, }; @@ -10,7 +10,6 @@ use dash_sdk::platform::IdentityPublicKey; use drive_proof_verifier::ContextProvider; use std::ffi::CStr; use std::os::raw::c_char; -use std::sync::Arc; use crate::document::helpers::{ convert_state_transition_creation_options, convert_token_payment_info, @@ -23,6 +22,14 @@ use crate::types::{ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// Put document to platform (broadcast state transition) +/// +/// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_put_to_platform( sdk_handle: *mut SDKHandle, @@ -134,7 +141,7 @@ pub unsafe extern "C" fn dash_sdk_document_put_to_platform( builder .sign( &wrapper.sdk, - &identity_public_key, + identity_public_key, signer, wrapper.sdk.version(), ) @@ -166,7 +173,7 @@ pub unsafe extern "C" fn dash_sdk_document_put_to_platform( builder .sign( &wrapper.sdk, - &identity_public_key, + identity_public_key, signer, wrapper.sdk.version(), ) @@ -190,6 +197,11 @@ pub unsafe extern "C" fn dash_sdk_document_put_to_platform( } /// Put document to platform and wait for confirmation (broadcast state transition and wait for response) +/// +/// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_put_to_platform_and_wait( sdk_handle: *mut SDKHandle, @@ -300,7 +312,7 @@ pub unsafe extern "C" fn dash_sdk_document_put_to_platform_and_wait( let result = wrapper .sdk - .document_create(builder, &identity_public_key, signer) + .document_create(builder, identity_public_key, signer) .await .map_err(|e| { FFIError::InternalError(format!("Failed to create document and wait: {}", e)) @@ -337,7 +349,7 @@ pub unsafe extern "C" fn dash_sdk_document_put_to_platform_and_wait( let result = wrapper .sdk - .document_replace(builder, &identity_public_key, signer) + .document_replace(builder, identity_public_key, signer) .await .map_err(|e| { FFIError::InternalError(format!("Failed to replace document and wait: {}", e)) @@ -390,7 +402,7 @@ mod tests { let document = Document::V0(DocumentV0 { id, owner_id, - properties: properties, + properties, revision: Some(revision), created_at: None, updated_at: None, @@ -462,7 +474,7 @@ mod tests { #[test] fn test_put_with_null_document() { let sdk_handle = create_mock_sdk_handle(); - let data_contract = create_mock_data_contract(); + // create_mock_data_contract() not needed here let identity_public_key = create_mock_identity_public_key(); let signer = create_mock_signer(); @@ -510,7 +522,7 @@ mod tests { fn test_put_with_null_entropy() { let sdk_handle = create_mock_sdk_handle(); let document = create_mock_document_with_revision(1); - let data_contract = create_mock_data_contract(); + // create_mock_data_contract() not needed here let identity_public_key = create_mock_identity_public_key(); let signer = create_mock_signer(); @@ -560,7 +572,7 @@ mod tests { // Test that revision 1 documents use DocumentCreateTransitionBuilder let sdk_handle = create_mock_sdk_handle(); let document = create_mock_document_with_revision(1); - let data_contract = create_mock_data_contract(); + // create_mock_data_contract() not needed here let identity_public_key = create_mock_identity_public_key(); let signer = create_mock_signer(); @@ -618,7 +630,7 @@ mod tests { // Test that revision > 1 documents use DocumentReplaceTransitionBuilder let sdk_handle = create_mock_sdk_handle(); let document = create_mock_document_with_revision(2); - let data_contract = create_mock_data_contract(); + // create_mock_data_contract() not needed here let identity_public_key = create_mock_identity_public_key(); let signer = create_mock_signer(); @@ -675,7 +687,7 @@ mod tests { fn test_put_and_wait_with_null_parameters() { let sdk_handle = create_mock_sdk_handle(); let document = create_mock_document_with_revision(1); - let data_contract = create_mock_data_contract(); + // create_mock_data_contract() not needed here let identity_public_key = create_mock_identity_public_key(); let signer = create_mock_signer(); diff --git a/packages/rs-sdk-ffi/src/document/queries/fetch.rs b/packages/rs-sdk-ffi/src/document/queries/fetch.rs index 3d1d09b2b9..719837fd43 100644 --- a/packages/rs-sdk-ffi/src/document/queries/fetch.rs +++ b/packages/rs-sdk-ffi/src/document/queries/fetch.rs @@ -101,6 +101,11 @@ pub unsafe extern "C" fn dash_sdk_document_fetch_by_contract_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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_fetch( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/document/queries/info.rs b/packages/rs-sdk-ffi/src/document/queries/info.rs index 2b105415f3..3e5a60ac56 100644 --- a/packages/rs-sdk-ffi/src/document/queries/info.rs +++ b/packages/rs-sdk-ffi/src/document/queries/info.rs @@ -10,6 +10,10 @@ use crate::types::{ }; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_get_info( document_handle: *const DocumentHandle, @@ -370,7 +374,7 @@ pub unsafe extern "C" fn dash_sdk_document_get_info( owner_id: owner_id_str, data_contract_id: data_contract_id_str, document_type: document_type_str, - revision: document.revision().map(|r| r as u64).unwrap_or(0), + revision: document.revision().unwrap_or(0), created_at: document.created_at().map(|t| t as i64).unwrap_or(0), updated_at: document.updated_at().map(|t| t as i64).unwrap_or(0), data_fields_count: properties.len(), diff --git a/packages/rs-sdk-ffi/src/document/queries/search.rs b/packages/rs-sdk-ffi/src/document/queries/search.rs index 7919276c84..a6b8b940a1 100644 --- a/packages/rs-sdk-ffi/src/document/queries/search.rs +++ b/packages/rs-sdk-ffi/src/document/queries/search.rs @@ -78,6 +78,7 @@ fn parse_where_operator(op: &str) -> Result { } /// Convert JSON value to platform value +#[allow(clippy::result_large_err)] fn json_to_platform_value(json: serde_json::Value) -> Result { match json { serde_json::Value::Null => Ok(Value::Null), @@ -111,6 +112,11 @@ fn json_to_platform_value(json: serde_json::Value) -> Result { } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_search( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/document/replace.rs b/packages/rs-sdk-ffi/src/document/replace.rs index 2b09f36b15..370a1078f5 100644 --- a/packages/rs-sdk-ffi/src/document/replace.rs +++ b/packages/rs-sdk-ffi/src/document/replace.rs @@ -13,16 +13,22 @@ use dash_sdk::dpp::document::document_methods::DocumentMethodsV0; use dash_sdk::dpp::document::{Document, DocumentV0Getters}; use dash_sdk::dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; use dash_sdk::dpp::platform_value::string_encoding::Encoding; -use dash_sdk::dpp::prelude::{DataContract, Identifier, UserFeeIncrease}; +use dash_sdk::dpp::prelude::{Identifier, UserFeeIncrease}; use dash_sdk::platform::documents::transitions::DocumentReplaceTransitionBuilder; use dash_sdk::platform::IdentityPublicKey; use drive_proof_verifier::ContextProvider; use std::ffi::CStr; use std::os::raw::c_char; -use std::sync::Arc; use tracing::{debug, error, info}; /// Replace document on platform (broadcast state transition) +/// +/// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_replace_on_platform( sdk_handle: *mut SDKHandle, @@ -130,7 +136,7 @@ pub unsafe extern "C" fn dash_sdk_document_replace_on_platform( let state_transition = builder .sign( &wrapper.sdk, - &identity_public_key, + identity_public_key, signer, wrapper.sdk.version(), ) @@ -161,6 +167,11 @@ pub unsafe extern "C" fn dash_sdk_document_replace_on_platform( } /// Replace document on platform and wait for confirmation (broadcast state transition and wait for response) +/// +/// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_replace_on_platform_and_wait( sdk_handle: *mut SDKHandle, @@ -332,7 +343,7 @@ pub unsafe extern "C" fn dash_sdk_document_replace_on_platform_and_wait( let result = wrapper .sdk - .document_replace(builder, &identity_public_key, signer) + .document_replace(builder, identity_public_key, signer) .await .map_err(|e| { eprintln!("❌ [DOCUMENT REPLACE] SDK call failed: {}", e); @@ -345,9 +356,9 @@ pub unsafe extern "C" fn dash_sdk_document_replace_on_platform_and_wait( eprintln!("✅ [DOCUMENT REPLACE] SDK call completed successfully"); - let replaced_document = match result { - dash_sdk::platform::documents::transitions::DocumentReplaceResult::Document(doc) => doc, - }; + let dash_sdk::platform::documents::transitions::DocumentReplaceResult::Document( + replaced_document, + ) = result; Ok(replaced_document) }); @@ -398,7 +409,7 @@ mod tests { let document = Document::V0(DocumentV0 { id, owner_id, - properties: properties, + properties, revision: Some(2), // Revision > 1 for replace created_at: None, updated_at: None, diff --git a/packages/rs-sdk-ffi/src/document/transfer.rs b/packages/rs-sdk-ffi/src/document/transfer.rs index 2cd4b6df14..1b2b3288c0 100644 --- a/packages/rs-sdk-ffi/src/document/transfer.rs +++ b/packages/rs-sdk-ffi/src/document/transfer.rs @@ -1,16 +1,14 @@ //! Document transfer operations -use dash_sdk::dpp::data_contract::accessors::v0::DataContractV0Getters; use dash_sdk::dpp::document::document_methods::DocumentMethodsV0; use dash_sdk::dpp::document::Document; use dash_sdk::dpp::platform_value::string_encoding::Encoding; -use dash_sdk::dpp::prelude::{DataContract, Identifier, UserFeeIncrease}; +use dash_sdk::dpp::prelude::{Identifier, UserFeeIncrease}; use dash_sdk::platform::documents::transitions::DocumentTransferTransitionBuilder; use dash_sdk::platform::IdentityPublicKey; use drive_proof_verifier::ContextProvider; use std::ffi::CStr; use std::os::raw::c_char; -use std::sync::Arc; use crate::document::helpers::{ convert_state_transition_creation_options, convert_token_payment_info, @@ -36,6 +34,12 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # Returns /// Serialized state transition on success +/// +/// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_transfer_to_identity( sdk_handle: *mut SDKHandle, @@ -166,7 +170,7 @@ pub unsafe extern "C" fn dash_sdk_document_transfer_to_identity( let state_transition = builder .sign( &wrapper.sdk, - &identity_public_key, + identity_public_key, signer, wrapper.sdk.version(), ) @@ -202,6 +206,11 @@ pub unsafe extern "C" fn dash_sdk_document_transfer_to_identity( /// /// # Returns /// Handle to the transferred document on success +/// +/// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_transfer_to_identity_and_wait( sdk_handle: *mut SDKHandle, @@ -331,17 +340,15 @@ pub unsafe extern "C" fn dash_sdk_document_transfer_to_identity_and_wait( let result = wrapper .sdk - .document_transfer(builder, &identity_public_key, signer) + .document_transfer(builder, identity_public_key, signer) .await .map_err(|e| { FFIError::InternalError(format!("Failed to transfer document and wait: {}", e)) })?; - let transferred_document = match result { - dash_sdk::platform::documents::transitions::DocumentTransferResult::Document(doc) => { - doc - } - }; + let dash_sdk::platform::documents::transitions::DocumentTransferResult::Document( + transferred_document, + ) = result; Ok(transferred_document) }); @@ -386,7 +393,7 @@ mod tests { let document = Document::V0(DocumentV0 { id, owner_id, - properties: properties, + properties, revision: Some(1), created_at: None, updated_at: None, @@ -405,7 +412,7 @@ mod tests { #[test] fn test_transfer_with_null_sdk_handle() { let document = create_mock_document(); - let data_contract = create_mock_data_contract(); + // create_mock_data_contract() not needed here let identity_public_key = create_mock_identity_public_key(); let signer = create_mock_signer(); @@ -454,7 +461,7 @@ mod tests { #[test] fn test_transfer_with_null_document() { let sdk_handle = create_mock_sdk_handle(); - let data_contract = create_mock_data_contract(); + // create_mock_data_contract() not needed here let identity_public_key = create_mock_identity_public_key(); let signer = create_mock_signer(); @@ -501,7 +508,7 @@ mod tests { fn test_transfer_with_null_recipient_id() { let sdk_handle = create_mock_sdk_handle(); let document = create_mock_document(); - let data_contract = create_mock_data_contract(); + // create_mock_data_contract() not needed here let identity_public_key = create_mock_identity_public_key(); let signer = create_mock_signer(); @@ -549,7 +556,7 @@ mod tests { fn test_transfer_with_invalid_recipient_id() { let sdk_handle = create_mock_sdk_handle(); let document = create_mock_document(); - let data_contract = create_mock_data_contract(); + // create_mock_data_contract() not needed here let identity_public_key = create_mock_identity_public_key(); let signer = create_mock_signer(); @@ -646,7 +653,7 @@ mod tests { fn test_transfer_with_null_document_type_name() { let sdk_handle = create_mock_sdk_handle(); let document = create_mock_document(); - let data_contract = create_mock_data_contract(); + // create_mock_data_contract() not needed here let identity_public_key = create_mock_identity_public_key(); let signer = create_mock_signer(); @@ -694,7 +701,7 @@ mod tests { fn test_transfer_and_wait_with_null_parameters() { let sdk_handle = create_mock_sdk_handle(); let document = create_mock_document(); - let data_contract = create_mock_data_contract(); + // create_mock_data_contract() not needed here let identity_public_key = create_mock_identity_public_key(); let signer = create_mock_signer(); diff --git a/packages/rs-sdk-ffi/src/document/util.rs b/packages/rs-sdk-ffi/src/document/util.rs index 5fceb849de..33b6cc69bf 100644 --- a/packages/rs-sdk-ffi/src/document/util.rs +++ b/packages/rs-sdk-ffi/src/document/util.rs @@ -1,11 +1,15 @@ use crate::sdk::SDKWrapper; use crate::{DashSDKError, DashSDKErrorCode, DocumentHandle, FFIError, SDKHandle}; -use dash_sdk::dpp::document::{Document, DocumentV0Getters, DocumentV0Setters}; +use dash_sdk::dpp::document::{Document, DocumentV0Setters}; use dash_sdk::dpp::platform_value::Value; use std::ffi::CStr; use std::os::raw::c_char; /// 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`. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_destroy( sdk_handle: *mut SDKHandle, @@ -40,6 +44,10 @@ pub unsafe extern "C" fn dash_sdk_document_destroy( } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_handle_destroy(handle: *mut DocumentHandle) { if !handle.is_null() { @@ -48,12 +56,20 @@ pub unsafe extern "C" fn dash_sdk_document_handle_destroy(handle: *mut DocumentH } /// Free a document handle (alias for destroy) +/// +/// # Safety +/// - Same as `dash_sdk_document_handle_destroy`. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_free(handle: *mut DocumentHandle) { dash_sdk_document_handle_destroy(handle); } /// Set document properties from JSON +/// +/// # 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`. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_set_properties( document_handle: *mut DocumentHandle, diff --git a/packages/rs-sdk-ffi/src/dpns/helpers.rs b/packages/rs-sdk-ffi/src/dpns/helpers.rs index 32c8d751fa..cc04a58285 100644 --- a/packages/rs-sdk-ffi/src/dpns/helpers.rs +++ b/packages/rs-sdk-ffi/src/dpns/helpers.rs @@ -33,7 +33,7 @@ pub unsafe extern "C" fn dash_sdk_dpns_normalize_username( match utils::c_string_from(normalized) { Ok(c_string) => DashSDKResult::success(c_string as *mut std::os::raw::c_void), - Err(e) => DashSDKResult::error(e.into()), + Err(e) => DashSDKResult::error(e), } } @@ -137,13 +137,13 @@ pub unsafe extern "C" fn dash_sdk_dpns_get_validation_message( } else if !name_str .chars() .next() - .map_or(false, |c| c.is_ascii_alphanumeric()) + .is_some_and(|c| c.is_ascii_alphanumeric()) { "Name must start with an alphanumeric character" } else if !name_str .chars() .last() - .map_or(false, |c| c.is_ascii_alphanumeric()) + .is_some_and(|c| c.is_ascii_alphanumeric()) { "Name must end with an alphanumeric character" } else if name_str.contains("--") { @@ -161,6 +161,6 @@ pub unsafe extern "C" fn dash_sdk_dpns_get_validation_message( match utils::c_string_from(message.to_string()) { Ok(c_string) => DashSDKResult::success(c_string as *mut std::os::raw::c_void), - Err(e) => DashSDKResult::error(e.into()), + Err(e) => DashSDKResult::error(e), } } diff --git a/packages/rs-sdk-ffi/src/dpns/mod.rs b/packages/rs-sdk-ffi/src/dpns/mod.rs index 8cef78600a..c043340fdf 100644 --- a/packages/rs-sdk-ffi/src/dpns/mod.rs +++ b/packages/rs-sdk-ffi/src/dpns/mod.rs @@ -1,7 +1,7 @@ //! DPNS (Dash Platform Name Service) operations pub mod helpers; -pub mod queries; +mod queries; pub mod register; pub use helpers::*; diff --git a/packages/rs-sdk-ffi/src/dpns/queries/availability.rs b/packages/rs-sdk-ffi/src/dpns/queries/availability.rs index d9e19d422d..c113c4fde3 100644 --- a/packages/rs-sdk-ffi/src/dpns/queries/availability.rs +++ b/packages/rs-sdk-ffi/src/dpns/queries/availability.rs @@ -22,6 +22,11 @@ use std::ffi::CString; /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_dpns_check_availability( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/dpns/queries/contested.rs b/packages/rs-sdk-ffi/src/dpns/queries/contested.rs index 13668587dd..832ec4803e 100644 --- a/packages/rs-sdk-ffi/src/dpns/queries/contested.rs +++ b/packages/rs-sdk-ffi/src/dpns/queries/contested.rs @@ -16,7 +16,9 @@ use serde_json::json; // Still used by other functions /// Get all contested DPNS usernames where an identity is a contender /// /// # Safety -/// This function is unsafe because it operates on raw pointers +/// - `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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_dpns_get_contested_usernames_by_identity( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/dpns/queries/resolve.rs b/packages/rs-sdk-ffi/src/dpns/queries/resolve.rs index 18bbba1201..4c430c1c5a 100644 --- a/packages/rs-sdk-ffi/src/dpns/queries/resolve.rs +++ b/packages/rs-sdk-ffi/src/dpns/queries/resolve.rs @@ -23,6 +23,11 @@ use serde_json::json; /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_dpns_resolve( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/dpns/queries/search.rs b/packages/rs-sdk-ffi/src/dpns/queries/search.rs index 30960d32c0..10ee6365b8 100644 --- a/packages/rs-sdk-ffi/src/dpns/queries/search.rs +++ b/packages/rs-sdk-ffi/src/dpns/queries/search.rs @@ -22,6 +22,11 @@ use std::ffi::CString; /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_dpns_search( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/dpns/queries/usernames.rs b/packages/rs-sdk-ffi/src/dpns/queries/usernames.rs index 19e96d6221..46b317c66a 100644 --- a/packages/rs-sdk-ffi/src/dpns/queries/usernames.rs +++ b/packages/rs-sdk-ffi/src/dpns/queries/usernames.rs @@ -2,14 +2,12 @@ use std::ffi::{CStr, CString}; use std::os::raw::c_char; -use std::sync::Arc; use crate::sdk::SDKWrapper; use crate::types::SDKHandle; use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; use dash_sdk::dpp::identifier::Identifier; use dash_sdk::dpp::platform_value::string_encoding::Encoding; -use dash_sdk::dpp::platform_value::Value; use serde_json::json; /// Get DPNS usernames owned by an identity @@ -28,6 +26,11 @@ use serde_json::json; /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_dpns_get_usernames( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/dpns/register.rs b/packages/rs-sdk-ffi/src/dpns/register.rs index 7ce46e6761..886d519485 100644 --- a/packages/rs-sdk-ffi/src/dpns/register.rs +++ b/packages/rs-sdk-ffi/src/dpns/register.rs @@ -26,11 +26,9 @@ pub struct DpnsRegistrationResult { /// It generates the necessary entropy, creates both documents, and submits them in order. /// /// # Safety -/// - `handle` must be a valid SDK handle -/// - `label` must be a valid null-terminated C string -/// - `identity` must be a valid identity handle -/// - `identity_public_key` must be a valid identity public key handle -/// - `signer` must be a valid signer handle +/// - `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 @@ -99,7 +97,7 @@ pub unsafe extern "C" fn dash_sdk_dpns_register_name( // Get signer from handle let signer_arc = Arc::from_raw(signer as *const VTableSigner); - let signer_clone = (*signer_arc).clone(); + let signer_clone = *signer_arc; // Don't drop the Arc, just forget it std::mem::forget(signer_arc); @@ -144,7 +142,7 @@ pub unsafe extern "C" fn dash_sdk_dpns_register_name( // Convert to C strings let preorder_cstring = match utils::c_string_from(preorder_json) { Ok(s) => s, - Err(e) => return DashSDKResult::error(e.into()), + Err(e) => return DashSDKResult::error(e), }; let domain_cstring = match utils::c_string_from(domain_json) { @@ -152,7 +150,7 @@ pub unsafe extern "C" fn dash_sdk_dpns_register_name( Err(e) => { // Clean up preorder string let _ = std::ffi::CString::from_raw(preorder_cstring); - return DashSDKResult::error(e.into()); + return DashSDKResult::error(e); } }; @@ -163,7 +161,7 @@ pub unsafe extern "C" fn dash_sdk_dpns_register_name( // Clean up previous strings let _ = std::ffi::CString::from_raw(preorder_cstring); let _ = std::ffi::CString::from_raw(domain_cstring); - return DashSDKResult::error(e.into()); + return DashSDKResult::error(e); } }; diff --git a/packages/rs-sdk-ffi/src/error.rs b/packages/rs-sdk-ffi/src/error.rs index cf9f314efc..d4788dff54 100644 --- a/packages/rs-sdk-ffi/src/error.rs +++ b/packages/rs-sdk-ffi/src/error.rs @@ -162,6 +162,10 @@ impl From for DashSDKError { } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_error_free(error: *mut DashSDKError) { if error.is_null() { diff --git a/packages/rs-sdk-ffi/src/evonode/mod.rs b/packages/rs-sdk-ffi/src/evonode/mod.rs index 3146938a04..bb8d3a682e 100644 --- a/packages/rs-sdk-ffi/src/evonode/mod.rs +++ b/packages/rs-sdk-ffi/src/evonode/mod.rs @@ -1,5 +1,5 @@ // Evonode-related modules -pub mod queries; +mod queries; // Re-export all public functions pub use queries::*; diff --git a/packages/rs-sdk-ffi/src/evonode/queries/proposed_epoch_blocks_by_ids.rs b/packages/rs-sdk-ffi/src/evonode/queries/proposed_epoch_blocks_by_ids.rs index bb260b7581..59f084d129 100644 --- a/packages/rs-sdk-ffi/src/evonode/queries/proposed_epoch_blocks_by_ids.rs +++ b/packages/rs-sdk-ffi/src/evonode/queries/proposed_epoch_blocks_by_ids.rs @@ -17,7 +17,9 @@ use std::ffi::{c_char, c_void, CStr, CString}; /// * 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_evonode_get_proposed_epoch_blocks_by_ids( sdk_handle: *const SDKHandle, @@ -122,7 +124,7 @@ fn get_evonodes_proposed_epoch_blocks_by_ids( .map(|(pro_tx_hash, count)| { format!( r#"{{"pro_tx_hash":"{}","count":{}}}"#, - hex::encode(&pro_tx_hash), + hex::encode(pro_tx_hash), count ) }) diff --git a/packages/rs-sdk-ffi/src/evonode/queries/proposed_epoch_blocks_by_range.rs b/packages/rs-sdk-ffi/src/evonode/queries/proposed_epoch_blocks_by_range.rs index c894b51013..7605cfac13 100644 --- a/packages/rs-sdk-ffi/src/evonode/queries/proposed_epoch_blocks_by_range.rs +++ b/packages/rs-sdk-ffi/src/evonode/queries/proposed_epoch_blocks_by_range.rs @@ -19,7 +19,9 @@ use std::ffi::{c_char, c_void, CStr, CString}; /// * 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_evonode_get_proposed_epoch_blocks_by_range( sdk_handle: *const SDKHandle, @@ -141,7 +143,7 @@ fn get_evonodes_proposed_epoch_blocks_by_range( .map(|(pro_tx_hash, count)| { format!( r#"{{"pro_tx_hash":"{}","count":{}}}"#, - hex::encode(&pro_tx_hash), + hex::encode(pro_tx_hash), count ) }) @@ -188,10 +190,9 @@ impl Some(Start::StartAfter( AsRef::<[u8]>::as_ref(&start_after).to_vec(), )) - } else if let Some(start_at) = self.start_at { - Some(Start::StartAt(AsRef::<[u8]>::as_ref(&start_at).to_vec())) } else { - None + self.start_at + .map(|start_at| Start::StartAt(AsRef::<[u8]>::as_ref(&start_at).to_vec())) }; let request = diff --git a/packages/rs-sdk-ffi/src/group/mod.rs b/packages/rs-sdk-ffi/src/group/mod.rs index ad6d54e3c3..404b8f4acf 100644 --- a/packages/rs-sdk-ffi/src/group/mod.rs +++ b/packages/rs-sdk-ffi/src/group/mod.rs @@ -1,5 +1,5 @@ // Group-related modules -pub mod queries; +mod queries; // Re-export all public functions pub use queries::*; diff --git a/packages/rs-sdk-ffi/src/group/queries/action_signers.rs b/packages/rs-sdk-ffi/src/group/queries/action_signers.rs index 130186ff90..e39733e4d2 100644 --- a/packages/rs-sdk-ffi/src/group/queries/action_signers.rs +++ b/packages/rs-sdk-ffi/src/group/queries/action_signers.rs @@ -19,7 +19,9 @@ use std::ffi::{c_char, c_void, CStr, CString}; /// * 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_group_get_action_signers( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/group/queries/actions.rs b/packages/rs-sdk-ffi/src/group/queries/actions.rs index 736676a6a7..d51c9071e1 100644 --- a/packages/rs-sdk-ffi/src/group/queries/actions.rs +++ b/packages/rs-sdk-ffi/src/group/queries/actions.rs @@ -20,7 +20,9 @@ use std::ffi::{c_char, c_void, CStr, CString}; /// * 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_group_get_actions( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/group/queries/info.rs b/packages/rs-sdk-ffi/src/group/queries/info.rs index 9259b3ebd1..d8c2867f36 100644 --- a/packages/rs-sdk-ffi/src/group/queries/info.rs +++ b/packages/rs-sdk-ffi/src/group/queries/info.rs @@ -16,7 +16,9 @@ use std::ffi::{c_char, c_void, CStr, CString}; /// * 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_group_get_info( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/group/queries/infos.rs b/packages/rs-sdk-ffi/src/group/queries/infos.rs index bbd1ab8e90..a7cd4db302 100644 --- a/packages/rs-sdk-ffi/src/group/queries/infos.rs +++ b/packages/rs-sdk-ffi/src/group/queries/infos.rs @@ -15,7 +15,9 @@ use std::ffi::{c_char, c_void, CStr, CString}; /// * 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_group_get_infos( sdk_handle: *const SDKHandle, @@ -92,7 +94,7 @@ fn get_group_infos( // TODO: This function needs a contract_id parameter to work properly // Group::fetch_many requires a GroupInfosQuery which needs a contract_id // For now, returning empty result - return Ok(None); + Ok(None) /* Commented out until contract_id is added as parameter let query = dash_sdk::platform::LimitQuery { diff --git a/packages/rs-sdk-ffi/src/group/queries/mod.rs b/packages/rs-sdk-ffi/src/group/queries/mod.rs index 7483fae385..172ea4c55d 100644 --- a/packages/rs-sdk-ffi/src/group/queries/mod.rs +++ b/packages/rs-sdk-ffi/src/group/queries/mod.rs @@ -1,8 +1,8 @@ // Group-related queries -pub mod action_signers; -pub mod actions; -pub mod info; -pub mod infos; +mod action_signers; +mod actions; +mod info; +mod infos; // Re-export all public functions for convenient access pub use action_signers::dash_sdk_group_get_action_signers; diff --git a/packages/rs-sdk-ffi/src/identity/create.rs b/packages/rs-sdk-ffi/src/identity/create.rs index d3ab62f0a4..d6217d778e 100644 --- a/packages/rs-sdk-ffi/src/identity/create.rs +++ b/packages/rs-sdk-ffi/src/identity/create.rs @@ -1,13 +1,18 @@ //! Identity creation operations use dash_sdk::dpp::prelude::Identity; -use dash_sdk::platform::Fetch; use crate::sdk::SDKWrapper; use crate::types::{DashSDKResultDataType, IdentityHandle, SDKHandle}; use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_create(sdk_handle: *mut SDKHandle) -> DashSDKResult { if sdk_handle.is_null() { diff --git a/packages/rs-sdk-ffi/src/identity/create_from_components.rs b/packages/rs-sdk-ffi/src/identity/create_from_components.rs index af7b0098a7..f4f906d0c1 100644 --- a/packages/rs-sdk-ffi/src/identity/create_from_components.rs +++ b/packages/rs-sdk-ffi/src/identity/create_from_components.rs @@ -45,6 +45,13 @@ pub struct DashSDKPublicKeyData { /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_create_from_components( identity_id: *const u8, diff --git a/packages/rs-sdk-ffi/src/identity/get_public_key.rs b/packages/rs-sdk-ffi/src/identity/get_public_key.rs index 67dab7992c..2a271dacb9 100644 --- a/packages/rs-sdk-ffi/src/identity/get_public_key.rs +++ b/packages/rs-sdk-ffi/src/identity/get_public_key.rs @@ -3,7 +3,6 @@ use crate::types::{DashSDKPublicKeyHandle, DashSDKResultDataType, IdentityHandle}; use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult}; use dash_sdk::dpp::identity::accessors::IdentityGettersV0; -use std::ptr; /// Get a public key from an identity by its ID /// @@ -14,6 +13,12 @@ use std::ptr; /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_get_public_key_by_id( identity: *const IdentityHandle, diff --git a/packages/rs-sdk-ffi/src/identity/helpers.rs b/packages/rs-sdk-ffi/src/identity/helpers.rs index adb2539c98..19ee74279f 100644 --- a/packages/rs-sdk-ffi/src/identity/helpers.rs +++ b/packages/rs-sdk-ffi/src/identity/helpers.rs @@ -12,6 +12,10 @@ use crate::types::DashSDKPutSettings; use crate::FFIError; /// Helper function to convert DashSDKPutSettings to PutSettings +/// +/// # Safety +/// - `put_settings` may be null; when non-null it must be a valid pointer to a `DashSDKPutSettings` structure +/// that remains valid for the duration of the call. pub unsafe fn convert_put_settings(put_settings: *const DashSDKPutSettings) -> Option { if put_settings.is_null() { None @@ -75,6 +79,10 @@ pub unsafe fn convert_put_settings(put_settings: *const DashSDKPutSettings) -> O } /// Helper function to parse private key +/// +/// # Safety +/// - `private_key_bytes` must be a valid, non-null pointer to 32 readable bytes for the duration of the call. +#[allow(clippy::result_large_err)] pub unsafe fn parse_private_key( private_key_bytes: *const [u8; 32], ) -> Result { @@ -85,6 +93,12 @@ pub unsafe fn parse_private_key( } /// Helper function to create instant asset lock proof from components +/// +/// # Safety +/// - `instant_lock_bytes` must be a valid, non-null pointer to `instant_lock_len` readable bytes. +/// - `transaction_bytes` must be a valid, non-null pointer to `transaction_len` readable bytes. +/// - The pointers must remain valid for the duration of the call. +#[allow(clippy::result_large_err)] pub unsafe fn create_instant_asset_lock_proof( instant_lock_bytes: *const u8, instant_lock_len: usize, @@ -114,6 +128,11 @@ pub unsafe fn create_instant_asset_lock_proof( } /// Helper function to create chain asset lock proof from components +/// +/// # Safety +/// - `out_point_bytes` must be a valid, non-null pointer to 36 readable bytes. +/// - The pointer must remain valid for the duration of the call. +#[allow(clippy::result_large_err)] pub unsafe fn create_chain_asset_lock_proof( core_chain_locked_height: u32, out_point_bytes: *const [u8; 36], diff --git a/packages/rs-sdk-ffi/src/identity/info.rs b/packages/rs-sdk-ffi/src/identity/info.rs index a95a63a3e5..645d43b83d 100644 --- a/packages/rs-sdk-ffi/src/identity/info.rs +++ b/packages/rs-sdk-ffi/src/identity/info.rs @@ -8,6 +8,11 @@ use std::ffi::CString; use crate::types::{DashSDKIdentityInfo, IdentityHandle}; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_get_info( identity_handle: *const IdentityHandle, @@ -26,7 +31,7 @@ pub unsafe extern "C" fn dash_sdk_identity_get_info( let info = DashSDKIdentityInfo { id: id_str, balance: identity.balance(), - revision: identity.revision() as u64, + revision: identity.revision(), public_keys_count: identity.public_keys().len() as u32, }; @@ -34,6 +39,10 @@ pub unsafe extern "C" fn dash_sdk_identity_get_info( } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_destroy(handle: *mut IdentityHandle) { if !handle.is_null() { diff --git a/packages/rs-sdk-ffi/src/identity/keys.rs b/packages/rs-sdk-ffi/src/identity/keys.rs index 1d47fce7e1..566c01e5f3 100644 --- a/packages/rs-sdk-ffi/src/identity/keys.rs +++ b/packages/rs-sdk-ffi/src/identity/keys.rs @@ -1,7 +1,7 @@ //! Identity key selection operations use crate::types::{IdentityHandle, IdentityPublicKeyHandle}; -use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; +use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult}; use dash_sdk::dpp::identity::accessors::IdentityGettersV0; use dash_sdk::dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; use dash_sdk::dpp::identity::{IdentityPublicKey, Purpose, SecurityLevel}; @@ -31,6 +31,12 @@ pub enum StateTransitionType { /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_get_signing_key_for_transition( identity_handle: *const IdentityHandle, @@ -109,11 +115,17 @@ pub unsafe extern "C" fn dash_sdk_identity_get_signing_key_for_transition( /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_get_transfer_private_key( identity_handle: *const IdentityHandle, key_index: u32, ) -> DashSDKResult { + let _ = (identity_handle, key_index); // TODO: This is a placeholder implementation // In a real implementation, this would: // 1. Verify the caller has access to the private keys @@ -128,6 +140,10 @@ pub unsafe extern "C" fn dash_sdk_identity_get_transfer_private_key( } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_public_key_get_id( key_handle: *const IdentityPublicKeyHandle, @@ -137,7 +153,7 @@ pub unsafe extern "C" fn dash_sdk_identity_public_key_get_id( } let key = &*(key_handle as *const IdentityPublicKey); - key.id().into() + key.id() } /// Create an identity public key handle from key data @@ -158,6 +174,12 @@ pub unsafe extern "C" fn dash_sdk_identity_public_key_get_id( /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_public_key_create_from_data( key_id: u32, @@ -231,7 +253,7 @@ pub unsafe extern "C" fn dash_sdk_identity_public_key_create_from_data( // Create the identity public key let public_key = IdentityPublicKey::V0(IdentityPublicKeyV0 { - id: key_id.into(), + id: key_id, key_type, purpose, security_level, @@ -251,6 +273,11 @@ pub unsafe extern "C" fn dash_sdk_identity_public_key_create_from_data( /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_public_key_to_bytes( key_handle: *const IdentityPublicKeyHandle, @@ -285,6 +312,10 @@ pub unsafe extern "C" fn dash_sdk_identity_public_key_to_bytes( } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_public_key_destroy( handle: *mut IdentityPublicKeyHandle, diff --git a/packages/rs-sdk-ffi/src/identity/mod.rs b/packages/rs-sdk-ffi/src/identity/mod.rs index fc04aec9df..33eebf2ce2 100644 --- a/packages/rs-sdk-ffi/src/identity/mod.rs +++ b/packages/rs-sdk-ffi/src/identity/mod.rs @@ -1,19 +1,19 @@ //! Identity operations -pub mod create; -pub mod create_from_components; -pub mod get_public_key; -pub mod helpers; -pub mod info; -pub mod keys; -pub mod names; -pub mod parse; -pub mod put; -pub mod queries; -pub mod test_transfer; -pub mod topup; -pub mod transfer; -pub mod withdraw; +mod create; +mod create_from_components; +mod get_public_key; +mod helpers; +mod info; +mod keys; +mod names; +mod parse; +mod put; +mod queries; +mod test_transfer; +mod topup; +mod transfer; +mod withdraw; // Re-export all public functions for convenient access pub use create::dash_sdk_identity_create; diff --git a/packages/rs-sdk-ffi/src/identity/names.rs b/packages/rs-sdk-ffi/src/identity/names.rs index a5823bd6c0..90c433c39f 100644 --- a/packages/rs-sdk-ffi/src/identity/names.rs +++ b/packages/rs-sdk-ffi/src/identity/names.rs @@ -6,6 +6,11 @@ use crate::types::{IdentityHandle, SDKHandle}; use crate::{DashSDKError, DashSDKErrorCode}; /// 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`. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_register_name( _sdk_handle: *mut SDKHandle, diff --git a/packages/rs-sdk-ffi/src/identity/parse.rs b/packages/rs-sdk-ffi/src/identity/parse.rs index 9586df629a..342c29b6d1 100644 --- a/packages/rs-sdk-ffi/src/identity/parse.rs +++ b/packages/rs-sdk-ffi/src/identity/parse.rs @@ -20,6 +20,11 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_parse_json(json_str: *const c_char) -> DashSDKResult { if json_str.is_null() { diff --git a/packages/rs-sdk-ffi/src/identity/put.rs b/packages/rs-sdk-ffi/src/identity/put.rs index e80e3e1da4..63b3cfaf55 100644 --- a/packages/rs-sdk-ffi/src/identity/put.rs +++ b/packages/rs-sdk-ffi/src/identity/put.rs @@ -13,6 +13,12 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// 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 @@ -95,6 +101,11 @@ pub unsafe extern "C" fn dash_sdk_identity_put_to_platform_with_instant_lock( /// 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 @@ -185,6 +196,12 @@ pub unsafe extern "C" fn dash_sdk_identity_put_to_platform_with_instant_lock_and /// 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) @@ -256,6 +273,11 @@ pub unsafe extern "C" fn dash_sdk_identity_put_to_platform_with_chain_lock( /// 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) diff --git a/packages/rs-sdk-ffi/src/identity/queries/balance.rs b/packages/rs-sdk-ffi/src/identity/queries/balance.rs index 6483a27265..6ae7de94b0 100644 --- a/packages/rs-sdk-ffi/src/identity/queries/balance.rs +++ b/packages/rs-sdk-ffi/src/identity/queries/balance.rs @@ -19,6 +19,11 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_fetch_balance( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/identity/queries/balance_and_revision.rs b/packages/rs-sdk-ffi/src/identity/queries/balance_and_revision.rs index bf94615427..9fefefca0f 100644 --- a/packages/rs-sdk-ffi/src/identity/queries/balance_and_revision.rs +++ b/packages/rs-sdk-ffi/src/identity/queries/balance_and_revision.rs @@ -19,6 +19,11 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_fetch_balance_and_revision( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/identity/queries/by_non_unique_public_key_hash.rs b/packages/rs-sdk-ffi/src/identity/queries/by_non_unique_public_key_hash.rs index 446292df4a..03f170597e 100644 --- a/packages/rs-sdk-ffi/src/identity/queries/by_non_unique_public_key_hash.rs +++ b/packages/rs-sdk-ffi/src/identity/queries/by_non_unique_public_key_hash.rs @@ -20,6 +20,12 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_fetch_by_non_unique_public_key_hash( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/identity/queries/by_public_key_hash.rs b/packages/rs-sdk-ffi/src/identity/queries/by_public_key_hash.rs index c970421e43..784e3883b0 100644 --- a/packages/rs-sdk-ffi/src/identity/queries/by_public_key_hash.rs +++ b/packages/rs-sdk-ffi/src/identity/queries/by_public_key_hash.rs @@ -9,9 +9,13 @@ use std::os::raw::c_char; use crate::sdk::SDKWrapper; use crate::types::SDKHandle; use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; - /// 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 diff --git a/packages/rs-sdk-ffi/src/identity/queries/contract_nonce.rs b/packages/rs-sdk-ffi/src/identity/queries/contract_nonce.rs index 1f6b753cdb..1c81cf0395 100644 --- a/packages/rs-sdk-ffi/src/identity/queries/contract_nonce.rs +++ b/packages/rs-sdk-ffi/src/identity/queries/contract_nonce.rs @@ -20,6 +20,11 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_fetch_contract_nonce( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/identity/queries/fetch.rs b/packages/rs-sdk-ffi/src/identity/queries/fetch.rs index 581d505b9b..ca348ead90 100644 --- a/packages/rs-sdk-ffi/src/identity/queries/fetch.rs +++ b/packages/rs-sdk-ffi/src/identity/queries/fetch.rs @@ -12,6 +12,11 @@ use crate::types::SDKHandle; use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_fetch( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/identity/queries/fetch_handle.rs b/packages/rs-sdk-ffi/src/identity/queries/fetch_handle.rs index 10f64449ea..b149ae64b9 100644 --- a/packages/rs-sdk-ffi/src/identity/queries/fetch_handle.rs +++ b/packages/rs-sdk-ffi/src/identity/queries/fetch_handle.rs @@ -2,7 +2,7 @@ use dash_sdk::dpp::identity::accessors::IdentityGettersV0; use dash_sdk::dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; -use dash_sdk::dpp::identity::{KeyType, Purpose, SecurityLevel}; +use dash_sdk::dpp::identity::Purpose; use dash_sdk::dpp::platform_value::string_encoding::Encoding; use dash_sdk::dpp::prelude::{Identifier, Identity}; use dash_sdk::platform::Fetch; @@ -26,6 +26,11 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_fetch_handle( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/identity/queries/identities_balances.rs b/packages/rs-sdk-ffi/src/identity/queries/identities_balances.rs index e294cd7791..6e745905c4 100644 --- a/packages/rs-sdk-ffi/src/identity/queries/identities_balances.rs +++ b/packages/rs-sdk-ffi/src/identity/queries/identities_balances.rs @@ -11,6 +11,11 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// 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) diff --git a/packages/rs-sdk-ffi/src/identity/queries/identities_contract_keys.rs b/packages/rs-sdk-ffi/src/identity/queries/identities_contract_keys.rs index d51dbc5323..960ba962e0 100644 --- a/packages/rs-sdk-ffi/src/identity/queries/identities_contract_keys.rs +++ b/packages/rs-sdk-ffi/src/identity/queries/identities_contract_keys.rs @@ -25,6 +25,11 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identities_fetch_contract_keys( sdk_handle: *const SDKHandle, @@ -166,7 +171,7 @@ pub unsafe extern "C" fn dash_sdk_identities_fetch_contract_keys( ); } - Ok(serde_json::to_string(&json_obj).map_err(|e| FFIError::InternalError(e.to_string()))?) + serde_json::to_string(&json_obj).map_err(|e| FFIError::InternalError(e.to_string())) }); match result { diff --git a/packages/rs-sdk-ffi/src/identity/queries/nonce.rs b/packages/rs-sdk-ffi/src/identity/queries/nonce.rs index 3a1539012f..a456987495 100644 --- a/packages/rs-sdk-ffi/src/identity/queries/nonce.rs +++ b/packages/rs-sdk-ffi/src/identity/queries/nonce.rs @@ -19,6 +19,11 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_fetch_nonce( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/identity/queries/public_keys.rs b/packages/rs-sdk-ffi/src/identity/queries/public_keys.rs index a93fe4312e..6cc38ddada 100644 --- a/packages/rs-sdk-ffi/src/identity/queries/public_keys.rs +++ b/packages/rs-sdk-ffi/src/identity/queries/public_keys.rs @@ -12,6 +12,11 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// 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 diff --git a/packages/rs-sdk-ffi/src/identity/queries/resolve.rs b/packages/rs-sdk-ffi/src/identity/queries/resolve.rs index 47edb65cf8..75fa4fe68b 100644 --- a/packages/rs-sdk-ffi/src/identity/queries/resolve.rs +++ b/packages/rs-sdk-ffi/src/identity/queries/resolve.rs @@ -19,6 +19,11 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult}; /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_resolve_name( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/identity/queries/resolve_test.rs b/packages/rs-sdk-ffi/src/identity/queries/resolve_test.rs index 5117c01130..83cbba8b0f 100644 --- a/packages/rs-sdk-ffi/src/identity/queries/resolve_test.rs +++ b/packages/rs-sdk-ffi/src/identity/queries/resolve_test.rs @@ -37,7 +37,7 @@ mod tests { let sdk_handle = create_mock_sdk_handle(); // Create invalid UTF-8 sequence - let invalid_utf8 = vec![0xFF, 0xFE, 0x00]; + let invalid_utf8 = [0xFF, 0xFE, 0x00]; unsafe { let result = diff --git a/packages/rs-sdk-ffi/src/identity/test_transfer.rs b/packages/rs-sdk-ffi/src/identity/test_transfer.rs index 3d679d169e..bc1113a869 100644 --- a/packages/rs-sdk-ffi/src/identity/test_transfer.rs +++ b/packages/rs-sdk-ffi/src/identity/test_transfer.rs @@ -15,6 +15,11 @@ use crate::types::SDKHandle; use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_test_identity_transfer_crash( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/identity/topup.rs b/packages/rs-sdk-ffi/src/identity/topup.rs index 56af2e8369..8a98c0053d 100644 --- a/packages/rs-sdk-ffi/src/identity/topup.rs +++ b/packages/rs-sdk-ffi/src/identity/topup.rs @@ -11,6 +11,12 @@ use crate::types::{DashSDKPutSettings, DashSDKResultDataType, IdentityHandle, SD use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_topup_with_instant_lock( sdk_handle: *mut SDKHandle, @@ -80,6 +86,11 @@ pub unsafe extern "C" fn dash_sdk_identity_topup_with_instant_lock( } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_topup_with_instant_lock_and_wait( sdk_handle: *mut SDKHandle, diff --git a/packages/rs-sdk-ffi/src/identity/transfer.rs b/packages/rs-sdk-ffi/src/identity/transfer.rs index aa0ea7f6aa..f1e8634d93 100644 --- a/packages/rs-sdk-ffi/src/identity/transfer.rs +++ b/packages/rs-sdk-ffi/src/identity/transfer.rs @@ -2,7 +2,6 @@ use dash_sdk::dpp::identity::accessors::IdentityGettersV0; use dash_sdk::dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; -use dash_sdk::dpp::identity::Purpose; use dash_sdk::dpp::platform_value::string_encoding::Encoding; use dash_sdk::dpp::prelude::{Identifier, Identity}; use std::ffi::CStr; @@ -11,8 +10,7 @@ use std::os::raw::c_char; use crate::identity::helpers::convert_put_settings; use crate::sdk::SDKWrapper; use crate::types::{DashSDKPutSettings, IdentityHandle, SDKHandle}; -use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError, VTableSigner}; -use dash_sdk::dpp::identity::signer::Signer; +use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// Result structure for credit transfer operations #[repr(C)] @@ -35,6 +33,12 @@ pub struct DashSDKTransferCreditsResult { /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_transfer_credits( sdk_handle: *mut SDKHandle, @@ -170,7 +174,7 @@ pub unsafe extern "C" fn dash_sdk_identity_transfer_credits( "🔵 dash_sdk_identity_transfer_credits: Looking for key with ID {}", public_key_id ); - match from_identity.get_public_key_by_id(public_key_id.into()) { + match from_identity.get_public_key_by_id(public_key_id) { Some(key) => { eprintln!( "🔵 dash_sdk_identity_transfer_credits: Found key with ID {}", @@ -242,7 +246,7 @@ pub unsafe extern "C" fn dash_sdk_identity_transfer_credits( eprintln!("🔵 dash_sdk_identity_transfer_credits: Defensive checks complete"); // Additional check on the signing_key if present - if let Some(ref key) = signing_key { + if let Some(key) = signing_key { eprintln!("🔵 dash_sdk_identity_transfer_credits: Signing key details:"); eprintln!(" - Key ID: {}", key.id()); eprintln!(" - Purpose: {:?}", key.purpose()); @@ -295,6 +299,10 @@ pub unsafe extern "C" fn dash_sdk_identity_transfer_credits( } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_transfer_credits_result_free( result: *mut DashSDKTransferCreditsResult, diff --git a/packages/rs-sdk-ffi/src/identity/withdraw.rs b/packages/rs-sdk-ffi/src/identity/withdraw.rs index b724e86962..bac55c6225 100644 --- a/packages/rs-sdk-ffi/src/identity/withdraw.rs +++ b/packages/rs-sdk-ffi/src/identity/withdraw.rs @@ -12,7 +12,6 @@ use crate::identity::helpers::convert_put_settings; use crate::sdk::SDKWrapper; use crate::types::{DashSDKPutSettings, IdentityHandle, SDKHandle}; use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; -use dash_sdk::dpp::identity::signer::Signer; use tracing::{debug, error, info, warn}; /// Withdraw credits from identity to a Dash address @@ -28,6 +27,12 @@ use tracing::{debug, error, info, warn}; /// /// # Returns /// The new balance of the identity after withdrawal +/// +/// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_withdraw( sdk_handle: *mut SDKHandle, @@ -142,7 +147,7 @@ pub unsafe extern "C" fn dash_sdk_identity_withdraw( public_key_id, "dash_sdk_identity_withdraw: looking for key id" ); - match identity.get_public_key_by_id(public_key_id.into()) { + match identity.get_public_key_by_id(public_key_id) { Some(key) => { debug!(found_key_id = public_key_id, purpose = ?key.purpose(), key_type = ?key.key_type(), "dash_sdk_identity_withdraw: found key"); Some(key) @@ -201,7 +206,7 @@ pub unsafe extern "C" fn dash_sdk_identity_withdraw( debug!(?withdraw_address, amount, ?core_fee, has_signing_key = signing_key.is_some(), signer_ptr = ?(signer as *const _), "dash_sdk_identity_withdraw: calling withdraw method"); // Additional defensive check on the signing_key if present - if let Some(ref key) = signing_key { + if let Some(key) = signing_key { eprintln!("🔵 dash_sdk_identity_withdraw: Signing key details:"); eprintln!(" - Key ID: {}", key.id()); eprintln!(" - Purpose: {:?}", key.purpose()); diff --git a/packages/rs-sdk-ffi/src/lib.rs b/packages/rs-sdk-ffi/src/lib.rs index 2db892ee41..c202c1dbe2 100644 --- a/packages/rs-sdk-ffi/src/lib.rs +++ b/packages/rs-sdk-ffi/src/lib.rs @@ -1,7 +1,6 @@ //! Dash Unified SDK FFI bindings -#![allow(ambiguous_glob_reexports)] -#![allow(hidden_glob_reexports)] -#![allow(unexpected_cfgs)] +#![allow(clippy::result_large_err)] +#![allow(clippy::large_enum_variant)] //! //! This crate provides C-compatible FFI bindings for both Dash Core (SPV) and Platform SDKs, //! enabling cross-platform applications to interact with the complete Dash ecosystem through C interfaces. @@ -59,7 +58,7 @@ pub use voting::*; // Re-export all Core SDK functions and types for unified access when linked #[cfg(feature = "dash_spv")] -pub use dash_spv_ffi::*; +pub use dash_spv_ffi as core_ffi; /// Initialize the FFI library. /// This should be called once at app startup before using any other functions. diff --git a/packages/rs-sdk-ffi/src/protocol_version/mod.rs b/packages/rs-sdk-ffi/src/protocol_version/mod.rs index ba0d5f2700..83d6793352 100644 --- a/packages/rs-sdk-ffi/src/protocol_version/mod.rs +++ b/packages/rs-sdk-ffi/src/protocol_version/mod.rs @@ -1,5 +1,5 @@ // Protocol version related modules -pub mod queries; +mod queries; // Re-export all public functions pub use queries::*; diff --git a/packages/rs-sdk-ffi/src/protocol_version/queries/upgrade_state.rs b/packages/rs-sdk-ffi/src/protocol_version/queries/upgrade_state.rs index 4a9ee5c4b8..6477688b92 100644 --- a/packages/rs-sdk-ffi/src/protocol_version/queries/upgrade_state.rs +++ b/packages/rs-sdk-ffi/src/protocol_version/queries/upgrade_state.rs @@ -15,7 +15,11 @@ use std::os::raw::c_void; /// * 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_protocol_version_get_upgrade_state( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/protocol_version/queries/upgrade_vote_status.rs b/packages/rs-sdk-ffi/src/protocol_version/queries/upgrade_vote_status.rs index b9aebb2916..8397f9be94 100644 --- a/packages/rs-sdk-ffi/src/protocol_version/queries/upgrade_vote_status.rs +++ b/packages/rs-sdk-ffi/src/protocol_version/queries/upgrade_vote_status.rs @@ -17,7 +17,13 @@ use std::ffi::{c_char, c_void, CStr, CString}; /// * 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_protocol_version_get_upgrade_vote_status( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/sdk.rs b/packages/rs-sdk-ffi/src/sdk.rs index 2870042929..ce1471e224 100644 --- a/packages/rs-sdk-ffi/src/sdk.rs +++ b/packages/rs-sdk-ffi/src/sdk.rs @@ -42,6 +42,7 @@ impl SDKWrapper { } } + #[allow(dead_code)] fn new_with_trusted_provider( sdk: Sdk, runtime: Runtime, @@ -89,6 +90,10 @@ fn init_or_get_runtime() -> Result, String> { } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_create(config: *const DashSDKConfig) -> DashSDKResult { if config.is_null() { @@ -170,6 +175,11 @@ pub unsafe extern "C" fn dash_sdk_create(config: *const DashSDKConfig) -> DashSD } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_create_extended( config: *const DashSDKConfigExtended, @@ -284,6 +294,9 @@ pub unsafe extern "C" fn dash_sdk_create_extended( /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_create_trusted(config: *const DashSDKConfig) -> DashSDKResult { if config.is_null() { @@ -343,7 +356,7 @@ pub unsafe extern "C" fn dash_sdk_create_trusted(config: *const DashSDKConfig) - match network { Network::Testnet => { // Use testnet addresses from WASM SDK - let default_addresses = vec![ + let default_addresses = [ "https://52.12.176.90:1443", "https://35.82.197.197:1443", "https://44.240.98.102:1443", @@ -372,7 +385,7 @@ pub unsafe extern "C" fn dash_sdk_create_trusted(config: *const DashSDKConfig) - } Network::Dash => { // Use mainnet addresses from WASM SDK - let default_addresses = vec![ + let default_addresses = [ "https://149.28.241.190:443", "https://198.7.115.48:443", "https://134.255.182.186:443", @@ -501,6 +514,9 @@ pub unsafe extern "C" fn dash_sdk_create_trusted(config: *const DashSDKConfig) - } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_destroy(handle: *mut SDKHandle) { if !handle.is_null() { @@ -586,6 +602,9 @@ pub unsafe extern "C" fn dash_sdk_create_with_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). #[no_mangle] pub unsafe extern "C" fn dash_sdk_get_network(handle: *const SDKHandle) -> DashSDKNetwork { if handle.is_null() { @@ -674,7 +693,7 @@ pub unsafe extern "C" fn dash_sdk_add_known_contracts( // Deserialize and add contracts let mut contracts = Vec::new(); - for i in 0..contract_count { + for (i, id) in ids.iter().take(contract_count).enumerate() { let contract_data = std::slice::from_raw_parts(*serialized_contracts.add(i), *contract_lengths.add(i)); @@ -683,17 +702,17 @@ pub unsafe extern "C" fn dash_sdk_add_known_contracts( match dash_sdk::dpp::data_contract::DataContract::versioned_deserialize( contract_data, false, // don't validate (we trust the data) - &platform_version, + platform_version, ) { Ok(contract) => { - eprintln!("✅ Successfully deserialized contract: {}", ids[i]); + eprintln!("✅ Successfully deserialized contract: {}", id); contracts.push(contract); } Err(e) => { - eprintln!("❌ Failed to deserialize contract {}: {}", ids[i], e); + eprintln!("❌ Failed to deserialize contract {}: {}", id, e); return DashSDKResult::error(DashSDKError::new( DashSDKErrorCode::SerializationError, - format!("Failed to deserialize contract {}: {}", ids[i], e), + format!("Failed to deserialize contract {}: {}", id, e), )); } } @@ -711,6 +730,10 @@ pub unsafe extern "C" fn dash_sdk_add_known_contracts( } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_create_handle_with_mock( dump_dir: *const std::os::raw::c_char, diff --git a/packages/rs-sdk-ffi/src/signer.rs b/packages/rs-sdk-ffi/src/signer.rs index 90d557b083..2533abfd80 100644 --- a/packages/rs-sdk-ffi/src/signer.rs +++ b/packages/rs-sdk-ffi/src/signer.rs @@ -1,7 +1,6 @@ //! Signer interface for iOS FFI use crate::types::SignerHandle; -use dash_sdk::dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; use dash_sdk::dpp::identity::signer::Signer; use dash_sdk::dpp::platform_value::BinaryData; use dash_sdk::dpp::prelude::{IdentityPublicKey, ProtocolError}; @@ -143,6 +142,9 @@ pub type DestroyCallback = Option Result DashSDKResult { tracing::info!("dash_sdk_get_status: called"); diff --git a/packages/rs-sdk-ffi/src/test_utils.rs b/packages/rs-sdk-ffi/src/test_utils.rs index 1354ff4e05..f614c35c21 100644 --- a/packages/rs-sdk-ffi/src/test_utils.rs +++ b/packages/rs-sdk-ffi/src/test_utils.rs @@ -1,4 +1,5 @@ #[cfg(test)] +#[allow(clippy::module_inception, dead_code)] pub mod test_utils { use crate::sdk::SDKWrapper; use crate::signer::VTableSigner; @@ -52,7 +53,7 @@ pub mod test_utils { _data_len: usize, result_len: *mut usize, ) -> *mut u8 { - let signature = vec![0u8; 64]; + let signature = [0u8; 64]; *result_len = signature.len(); let ptr = libc::malloc(signature.len()) as *mut u8; if !ptr.is_null() { @@ -93,7 +94,7 @@ pub mod test_utils { _data_len: usize, result_len: *mut usize, ) -> *mut u8 { - let signature = vec![0u8; 64]; + let signature = [0u8; 64]; *result_len = signature.len(); let ptr = libc::malloc(signature.len()) as *mut u8; if !ptr.is_null() { diff --git a/packages/rs-sdk-ffi/src/token/burn.rs b/packages/rs-sdk-ffi/src/token/burn.rs index 35cfb4b592..3e5c344ded 100644 --- a/packages/rs-sdk-ffi/src/token/burn.rs +++ b/packages/rs-sdk-ffi/src/token/burn.rs @@ -21,6 +21,13 @@ use std::ffi::CStr; use std::sync::Arc; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_burn( sdk_handle: *mut SDKHandle, @@ -210,8 +217,9 @@ mod tests { fn test_burn_with_null_sdk_handle() { let transition_owner_id = create_valid_transition_owner_id(); let params = create_valid_burn_params(); - let identity_public_key_handle = 1 as *const crate::types::IdentityPublicKeyHandle; - let signer_handle = 1 as *const SignerHandle; + let identity_public_key_handle = + std::ptr::dangling::(); + let signer_handle = std::ptr::dangling::(); let put_settings = create_put_settings(); let state_transition_options: *const DashSDKStateTransitionCreationOptions = ptr::null(); @@ -499,7 +507,7 @@ mod tests { #[test] fn test_burn_params_with_serialized_contract() { - let contract_data = vec![1u8, 2, 3, 4, 5]; + let contract_data = [1u8, 2, 3, 4, 5]; let params = DashSDKTokenBurnParams { token_contract_id: ptr::null(), serialized_contract: contract_data.as_ptr(), @@ -518,7 +526,7 @@ mod tests { fn test_burn_params_validation() { // Test with both contract ID and serialized contract (should be mutually exclusive) let contract_id = CString::new("GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec").unwrap(); - let contract_data = vec![1u8, 2, 3]; + let contract_data = [1u8, 2, 3]; let params = DashSDKTokenBurnParams { token_contract_id: contract_id.as_ptr(), diff --git a/packages/rs-sdk-ffi/src/token/claim.rs b/packages/rs-sdk-ffi/src/token/claim.rs index a130e33d87..c9d8b4efa5 100644 --- a/packages/rs-sdk-ffi/src/token/claim.rs +++ b/packages/rs-sdk-ffi/src/token/claim.rs @@ -20,6 +20,13 @@ use std::ffi::CStr; use std::sync::Arc; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_claim( sdk_handle: *mut SDKHandle, @@ -235,7 +242,7 @@ mod tests { result_len: *mut usize, ) -> *mut u8 { // Return a mock signature (64 bytes for ECDSA) allocated with libc::malloc - let signature = vec![0u8; 64]; + let signature = [0u8; 64]; *result_len = signature.len(); let ptr = libc::malloc(signature.len()) as *mut u8; if !ptr.is_null() { @@ -316,8 +323,9 @@ mod tests { fn test_claim_with_null_sdk_handle() { let transition_owner_id = create_valid_transition_owner_id(); let params = create_valid_claim_params(); - let identity_public_key_handle = 1 as *const crate::types::IdentityPublicKeyHandle; - let signer_handle = 1 as *const SignerHandle; + let identity_public_key_handle = + std::ptr::dangling::(); + let signer_handle = std::ptr::dangling::(); let put_settings = create_put_settings(); let state_transition_options: *const DashSDKStateTransitionCreationOptions = ptr::null(); @@ -553,7 +561,7 @@ mod tests { #[test] fn test_claim_params_with_serialized_contract() { - let contract_data = vec![1u8, 2, 3, 4, 5]; + let contract_data = [1u8, 2, 3, 4, 5]; let params = DashSDKTokenClaimParams { token_contract_id: ptr::null(), serialized_contract: contract_data.as_ptr(), diff --git a/packages/rs-sdk-ffi/src/token/config_update.rs b/packages/rs-sdk-ffi/src/token/config_update.rs index af89d294df..21806c80ef 100644 --- a/packages/rs-sdk-ffi/src/token/config_update.rs +++ b/packages/rs-sdk-ffi/src/token/config_update.rs @@ -22,6 +22,13 @@ use std::ffi::CStr; use std::sync::Arc; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_update_contract_token_configuration( sdk_handle: *mut SDKHandle, @@ -280,7 +287,7 @@ mod tests { result_len: *mut usize, ) -> *mut u8 { // Return a mock signature (64 bytes for ECDSA) allocated with libc::malloc - let signature = vec![0u8; 64]; + let signature = [0u8; 64]; *result_len = signature.len(); let ptr = libc::malloc(signature.len()) as *mut u8; if !ptr.is_null() { @@ -470,7 +477,7 @@ mod tests { let sdk_handle = create_mock_sdk_handle(); let transition_owner_id = create_valid_transition_owner_id(); let params = create_valid_config_update_params(); - let signer_handle = 1 as *const SignerHandle; + let signer_handle = std::ptr::dangling::(); let put_settings = create_put_settings(); let state_transition_options: *const DashSDKStateTransitionCreationOptions = ptr::null(); @@ -502,7 +509,8 @@ mod tests { let sdk_handle = create_mock_sdk_handle(); let transition_owner_id = create_valid_transition_owner_id(); let params = create_valid_config_update_params(); - let identity_public_key_handle = 1 as *const crate::types::IdentityPublicKeyHandle; + let identity_public_key_handle = + std::ptr::dangling::(); let put_settings = create_put_settings(); let state_transition_options: *const DashSDKStateTransitionCreationOptions = ptr::null(); @@ -661,7 +669,7 @@ mod tests { #[test] fn test_config_update_with_serialized_contract() { - let contract_data = vec![1u8, 2, 3, 4, 5]; + let contract_data = [1u8, 2, 3, 4, 5]; let params = DashSDKTokenConfigUpdateParams { token_contract_id: ptr::null(), serialized_contract: contract_data.as_ptr(), diff --git a/packages/rs-sdk-ffi/src/token/destroy_frozen_funds.rs b/packages/rs-sdk-ffi/src/token/destroy_frozen_funds.rs index 91566d1872..9a8f4e85a4 100644 --- a/packages/rs-sdk-ffi/src/token/destroy_frozen_funds.rs +++ b/packages/rs-sdk-ffi/src/token/destroy_frozen_funds.rs @@ -20,6 +20,13 @@ use std::ffi::CStr; use std::sync::Arc; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_destroy_frozen_funds( sdk_handle: *mut SDKHandle, @@ -226,7 +233,7 @@ mod tests { result_len: *mut usize, ) -> *mut u8 { // Return a mock signature (64 bytes for ECDSA) allocated with libc::malloc - let signature = vec![0u8; 64]; + let signature = [0u8; 64]; *result_len = signature.len(); let ptr = libc::malloc(signature.len()) as *mut u8; if !ptr.is_null() { @@ -419,7 +426,7 @@ mod tests { let sdk_handle = create_mock_sdk_handle(); let transition_owner_id = create_valid_transition_owner_id(); let params = create_valid_destroy_frozen_funds_params(); - let signer_handle = 1 as *const SignerHandle; + let signer_handle = std::ptr::dangling::(); let put_settings = create_put_settings(); let state_transition_options: *const DashSDKStateTransitionCreationOptions = ptr::null(); @@ -451,7 +458,8 @@ mod tests { let sdk_handle = create_mock_sdk_handle(); let transition_owner_id = create_valid_transition_owner_id(); let params = create_valid_destroy_frozen_funds_params(); - let identity_public_key_handle = 1 as *const crate::types::IdentityPublicKeyHandle; + let identity_public_key_handle = + std::ptr::dangling::(); let put_settings = create_put_settings(); let state_transition_options: *const DashSDKStateTransitionCreationOptions = ptr::null(); @@ -520,7 +528,7 @@ mod tests { #[test] fn test_destroy_frozen_funds_with_serialized_contract() { - let contract_data = vec![1u8, 2, 3, 4, 5]; + let contract_data = [1u8, 2, 3, 4, 5]; let frozen_id = create_valid_frozen_identity_id(); let params = DashSDKTokenDestroyFrozenFundsParams { diff --git a/packages/rs-sdk-ffi/src/token/emergency_action.rs b/packages/rs-sdk-ffi/src/token/emergency_action.rs index 6d7480519f..78c0ebec50 100644 --- a/packages/rs-sdk-ffi/src/token/emergency_action.rs +++ b/packages/rs-sdk-ffi/src/token/emergency_action.rs @@ -20,6 +20,13 @@ use std::ffi::CStr; use std::sync::Arc; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_emergency_action( sdk_handle: *mut SDKHandle, @@ -242,7 +249,7 @@ mod tests { result_len: *mut usize, ) -> *mut u8 { // Return a mock signature (64 bytes for ECDSA) allocated with libc::malloc - let signature = vec![0u8; 64]; + let signature = [0u8; 64]; *result_len = signature.len(); let ptr = libc::malloc(signature.len()) as *mut u8; if !ptr.is_null() { @@ -325,8 +332,9 @@ mod tests { fn test_emergency_action_with_null_sdk_handle() { let transition_owner_id = create_valid_transition_owner_id(); let params = create_valid_emergency_action_params(); - let identity_public_key_handle = 1 as *const crate::types::IdentityPublicKeyHandle; - let signer_handle = 1 as *const SignerHandle; + let identity_public_key_handle = + std::ptr::dangling::(); + let signer_handle = std::ptr::dangling::(); let put_settings = create_put_settings(); let state_transition_options: *const DashSDKStateTransitionCreationOptions = ptr::null(); @@ -595,7 +603,7 @@ mod tests { fn test_emergency_action_with_serialized_contract() { let transition_owner_id = create_valid_transition_owner_id(); let mut params = create_valid_emergency_action_params(); - let contract_data = vec![0u8; 100]; // Mock serialized contract + let contract_data = [0u8; 100]; // Mock serialized contract params.serialized_contract = contract_data.as_ptr(); params.serialized_contract_len = contract_data.len(); diff --git a/packages/rs-sdk-ffi/src/token/freeze.rs b/packages/rs-sdk-ffi/src/token/freeze.rs index 20eeb6d008..8ce2a90099 100644 --- a/packages/rs-sdk-ffi/src/token/freeze.rs +++ b/packages/rs-sdk-ffi/src/token/freeze.rs @@ -20,6 +20,13 @@ use std::ffi::CStr; use std::sync::Arc; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_freeze( sdk_handle: *mut SDKHandle, @@ -244,7 +251,7 @@ mod tests { result_len: *mut usize, ) -> *mut u8 { // Return a mock signature (64 bytes for ECDSA) allocated with libc::malloc - let signature = vec![0u8; 64]; + let signature = [0u8; 64]; *result_len = signature.len(); let ptr = libc::malloc(signature.len()) as *mut u8; if !ptr.is_null() { @@ -335,8 +342,9 @@ mod tests { fn test_freeze_with_null_sdk_handle() { let transition_owner_id = create_valid_transition_owner_id(); let params = create_valid_freeze_params(); - let identity_public_key_handle = 1 as *const crate::types::IdentityPublicKeyHandle; - let signer_handle = 1 as *const SignerHandle; + let identity_public_key_handle = + std::ptr::dangling::(); + let signer_handle = std::ptr::dangling::(); let put_settings = create_put_settings(); let state_transition_options: *const DashSDKStateTransitionCreationOptions = ptr::null(); @@ -636,7 +644,7 @@ mod tests { let transition_owner_id = create_valid_transition_owner_id(); let mut params = create_valid_freeze_params(); - let contract_data = vec![0u8; 100]; // Mock serialized contract + let contract_data = [0u8; 100]; // Mock serialized contract params.serialized_contract = contract_data.as_ptr(); params.serialized_contract_len = contract_data.len(); diff --git a/packages/rs-sdk-ffi/src/token/mint.rs b/packages/rs-sdk-ffi/src/token/mint.rs index ec983766da..ff2873c13f 100644 --- a/packages/rs-sdk-ffi/src/token/mint.rs +++ b/packages/rs-sdk-ffi/src/token/mint.rs @@ -21,6 +21,13 @@ use std::ffi::CStr; use std::sync::Arc; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_mint( sdk_handle: *mut SDKHandle, @@ -224,7 +231,7 @@ pub unsafe extern "C" fn dash_sdk_token_mint( let mut builder = TokenMintTransitionBuilder::new( Arc::new(data_contract), params.token_position as TokenContractPosition, - minter_id.clone(), + minter_id, params.amount as TokenAmount, ); tracing::debug!(position = params.token_position, %minter_id, amount = params.amount, "FFI TOKEN MINT: builder created"); @@ -324,6 +331,7 @@ mod tests { } // Mock callbacks for signer + #[allow(dead_code)] unsafe extern "C" fn mock_sign_callback( _signer: *const std::os::raw::c_void, _identity_public_key_bytes: *const u8, @@ -333,7 +341,7 @@ mod tests { result_len: *mut usize, ) -> *mut u8 { // Return a mock signature (64 bytes for ECDSA), allocated with libc::malloc - let signature = vec![0u8; 64]; + let signature = [0u8; 64]; *result_len = signature.len(); let ptr = libc::malloc(signature.len()) as *mut u8; if !ptr.is_null() { @@ -342,6 +350,7 @@ mod tests { ptr } + #[allow(dead_code)] unsafe extern "C" fn mock_can_sign_callback( _signer: *const std::os::raw::c_void, _identity_public_key_bytes: *const u8, @@ -374,7 +383,7 @@ mod tests { _data_len: usize, result_len: *mut usize, ) -> *mut u8 { - let signature = vec![0u8; 64]; + let signature = [0u8; 64]; *result_len = signature.len(); let ptr = libc::malloc(signature.len()) as *mut u8; if !ptr.is_null() { @@ -704,7 +713,7 @@ mod tests { fn test_mint_with_serialized_contract() { let transition_owner_id = create_valid_transition_owner_id(); let mut params = create_valid_mint_params(); - let contract_data = vec![0u8; 100]; // Mock serialized contract + let contract_data = [0u8; 100]; // Mock serialized contract params.serialized_contract = contract_data.as_ptr(); params.serialized_contract_len = contract_data.len(); diff --git a/packages/rs-sdk-ffi/src/token/mod.rs b/packages/rs-sdk-ffi/src/token/mod.rs index e5068f1150..aecb5263e2 100644 --- a/packages/rs-sdk-ffi/src/token/mod.rs +++ b/packages/rs-sdk-ffi/src/token/mod.rs @@ -4,25 +4,25 @@ //! Operations are organized by functionality into separate submodules. // Common types and utilities -pub mod types; -pub mod utils; +mod types; +mod utils; // Core token operations -pub mod burn; -pub mod claim; -pub mod mint; -pub mod transfer; +mod burn; +mod claim; +mod mint; +mod transfer; // Token management operations -pub mod config_update; -pub mod destroy_frozen_funds; -pub mod emergency_action; -pub mod freeze; -pub mod unfreeze; +mod config_update; +mod destroy_frozen_funds; +mod emergency_action; +mod freeze; +mod unfreeze; // Token trading operations -pub mod purchase; -pub mod set_price; +mod purchase; +mod set_price; mod queries; diff --git a/packages/rs-sdk-ffi/src/token/purchase.rs b/packages/rs-sdk-ffi/src/token/purchase.rs index 05b14396e6..71183933b2 100644 --- a/packages/rs-sdk-ffi/src/token/purchase.rs +++ b/packages/rs-sdk-ffi/src/token/purchase.rs @@ -20,6 +20,13 @@ use std::ffi::CStr; use std::sync::Arc; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_purchase( sdk_handle: *mut SDKHandle, @@ -217,7 +224,7 @@ mod tests { result_len: *mut usize, ) -> *mut u8 { // Return a mock signature (64 bytes for ECDSA) allocated with libc::malloc - let signature = vec![0u8; 64]; + let signature = [0u8; 64]; *result_len = signature.len(); let ptr = libc::malloc(signature.len()) as *mut u8; if !ptr.is_null() { @@ -556,7 +563,7 @@ mod tests { fn test_purchase_with_serialized_contract() { let transition_owner_id = create_valid_transition_owner_id(); let mut params = create_valid_purchase_params(); - let contract_data = vec![0u8; 100]; // Mock serialized contract + let contract_data = [0u8; 100]; // Mock serialized contract params.serialized_contract = contract_data.as_ptr(); params.serialized_contract_len = contract_data.len(); diff --git a/packages/rs-sdk-ffi/src/token/queries/balances.rs b/packages/rs-sdk-ffi/src/token/queries/balances.rs index 735b120791..5d34f5ddb5 100644 --- a/packages/rs-sdk-ffi/src/token/queries/balances.rs +++ b/packages/rs-sdk-ffi/src/token/queries/balances.rs @@ -24,6 +24,10 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_get_identity_balances( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/token/queries/contract_info.rs b/packages/rs-sdk-ffi/src/token/queries/contract_info.rs index 1337da685b..12c4e9fdf2 100644 --- a/packages/rs-sdk-ffi/src/token/queries/contract_info.rs +++ b/packages/rs-sdk-ffi/src/token/queries/contract_info.rs @@ -19,6 +19,10 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_get_contract_info( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/token/queries/direct_purchase_prices.rs b/packages/rs-sdk-ffi/src/token/queries/direct_purchase_prices.rs index 566a7eb4d0..aa81876d4f 100644 --- a/packages/rs-sdk-ffi/src/token/queries/direct_purchase_prices.rs +++ b/packages/rs-sdk-ffi/src/token/queries/direct_purchase_prices.rs @@ -19,6 +19,10 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_get_direct_purchase_prices( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/token/queries/identities_balances.rs b/packages/rs-sdk-ffi/src/token/queries/identities_balances.rs index 4ddf5e16a2..8627be23d7 100644 --- a/packages/rs-sdk-ffi/src/token/queries/identities_balances.rs +++ b/packages/rs-sdk-ffi/src/token/queries/identities_balances.rs @@ -22,6 +22,10 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identities_fetch_token_balances( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/token/queries/identities_token_infos.rs b/packages/rs-sdk-ffi/src/token/queries/identities_token_infos.rs index ea8607b920..d242f30a09 100644 --- a/packages/rs-sdk-ffi/src/token/queries/identities_token_infos.rs +++ b/packages/rs-sdk-ffi/src/token/queries/identities_token_infos.rs @@ -22,6 +22,10 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identities_fetch_token_infos( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/token/queries/identity_balances.rs b/packages/rs-sdk-ffi/src/token/queries/identity_balances.rs index a125a47579..fb0ea8a8f3 100644 --- a/packages/rs-sdk-ffi/src/token/queries/identity_balances.rs +++ b/packages/rs-sdk-ffi/src/token/queries/identity_balances.rs @@ -22,6 +22,10 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_fetch_token_balances( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/token/queries/identity_token_infos.rs b/packages/rs-sdk-ffi/src/token/queries/identity_token_infos.rs index cbc86d35b5..1aecfbddec 100644 --- a/packages/rs-sdk-ffi/src/token/queries/identity_token_infos.rs +++ b/packages/rs-sdk-ffi/src/token/queries/identity_token_infos.rs @@ -22,6 +22,10 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_fetch_token_infos( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/token/queries/info.rs b/packages/rs-sdk-ffi/src/token/queries/info.rs index 4ff0917f2e..dee17f7ab9 100644 --- a/packages/rs-sdk-ffi/src/token/queries/info.rs +++ b/packages/rs-sdk-ffi/src/token/queries/info.rs @@ -24,6 +24,10 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_get_identity_infos( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/token/queries/mod.rs b/packages/rs-sdk-ffi/src/token/queries/mod.rs index bf23b02e52..1552a547f7 100644 --- a/packages/rs-sdk-ffi/src/token/queries/mod.rs +++ b/packages/rs-sdk-ffi/src/token/queries/mod.rs @@ -1,16 +1,16 @@ // Token information operations -pub mod balances; -pub mod contract_info; -pub mod direct_purchase_prices; -pub mod identities_balances; -pub mod identities_token_infos; -pub mod identity_balances; -pub mod identity_token_infos; -pub mod info; -pub mod perpetual_distribution_last_claim; -pub mod pre_programmed_distributions; -pub mod status; -pub mod total_supply; +mod balances; +mod contract_info; +mod direct_purchase_prices; +mod identities_balances; +mod identities_token_infos; +mod identity_balances; +mod identity_token_infos; +mod info; +mod perpetual_distribution_last_claim; +mod pre_programmed_distributions; +mod status; +mod total_supply; // Re-export main functions for convenient access pub use balances::dash_sdk_token_get_identity_balances; diff --git a/packages/rs-sdk-ffi/src/token/queries/perpetual_distribution_last_claim.rs b/packages/rs-sdk-ffi/src/token/queries/perpetual_distribution_last_claim.rs index 24da3927a1..8f4fb50cb1 100644 --- a/packages/rs-sdk-ffi/src/token/queries/perpetual_distribution_last_claim.rs +++ b/packages/rs-sdk-ffi/src/token/queries/perpetual_distribution_last_claim.rs @@ -19,6 +19,10 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_get_perpetual_distribution_last_claim( sdk_handle: *const SDKHandle, @@ -65,12 +69,12 @@ pub unsafe extern "C" fn dash_sdk_token_get_perpetual_distribution_last_claim( }; let result: Result = wrapper.runtime.block_on(async { - use dash_sdk::platform::query::{Query, TokenLastClaimQuery}; + use dash_sdk::platform::query::TokenLastClaimQuery; use dash_sdk::platform::Fetch; let query = TokenLastClaimQuery { - token_id: token_id.clone(), - identity_id: identity_id.clone(), + token_id, + identity_id, }; let last_claim = RewardDistributionMoment::fetch(&wrapper.sdk, query) diff --git a/packages/rs-sdk-ffi/src/token/queries/status.rs b/packages/rs-sdk-ffi/src/token/queries/status.rs index 1914f08ac8..e5b4ade6a6 100644 --- a/packages/rs-sdk-ffi/src/token/queries/status.rs +++ b/packages/rs-sdk-ffi/src/token/queries/status.rs @@ -20,6 +20,10 @@ use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult, FFIError}; /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_get_statuses( sdk_handle: *const SDKHandle, diff --git a/packages/rs-sdk-ffi/src/token/set_price.rs b/packages/rs-sdk-ffi/src/token/set_price.rs index 3a5e2f8495..c454cf5916 100644 --- a/packages/rs-sdk-ffi/src/token/set_price.rs +++ b/packages/rs-sdk-ffi/src/token/set_price.rs @@ -21,6 +21,13 @@ use std::ffi::CStr; use std::sync::Arc; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_set_price( sdk_handle: *mut SDKHandle, @@ -265,7 +272,7 @@ mod tests { result_len: *mut usize, ) -> *mut u8 { // Return a mock signature (64 bytes for ECDSA) allocated with libc::malloc - let signature = vec![0u8; 64]; + let signature = [0u8; 64]; *result_len = signature.len(); let ptr = libc::malloc(signature.len()) as *mut u8; if !ptr.is_null() { @@ -649,7 +656,7 @@ mod tests { fn test_set_price_with_serialized_contract() { let transition_owner_id = create_valid_transition_owner_id(); let mut params = create_valid_set_price_params(); - let contract_data = vec![0u8; 100]; // Mock serialized contract + let contract_data = [0u8; 100]; // Mock serialized contract params.serialized_contract = contract_data.as_ptr(); params.serialized_contract_len = contract_data.len(); diff --git a/packages/rs-sdk-ffi/src/token/transfer.rs b/packages/rs-sdk-ffi/src/token/transfer.rs index 046340e0dc..d30304aaf1 100644 --- a/packages/rs-sdk-ffi/src/token/transfer.rs +++ b/packages/rs-sdk-ffi/src/token/transfer.rs @@ -21,6 +21,13 @@ use std::ffi::CStr; use std::sync::Arc; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_transfer( sdk_handle: *mut SDKHandle, @@ -234,7 +241,7 @@ mod tests { result_len: *mut usize, ) -> *mut u8 { // Return a mock signature (64 bytes for ECDSA) allocated with libc::malloc - let signature = vec![0u8; 64]; + let signature = [0u8; 64]; *result_len = signature.len(); let ptr = libc::malloc(signature.len()) as *mut u8; if !ptr.is_null() { @@ -599,7 +606,7 @@ mod tests { fn test_transfer_with_serialized_contract() { let transition_owner_id = create_valid_transition_owner_id(); let mut params = create_valid_transfer_params(); - let contract_data = vec![0u8; 100]; // Mock serialized contract + let contract_data = [0u8; 100]; // Mock serialized contract params.serialized_contract = contract_data.as_ptr(); params.serialized_contract_len = contract_data.len(); diff --git a/packages/rs-sdk-ffi/src/token/unfreeze.rs b/packages/rs-sdk-ffi/src/token/unfreeze.rs index 4e569f7333..ab339b5e5e 100644 --- a/packages/rs-sdk-ffi/src/token/unfreeze.rs +++ b/packages/rs-sdk-ffi/src/token/unfreeze.rs @@ -17,6 +17,13 @@ use std::ffi::CStr; use std::sync::Arc; /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_token_unfreeze( sdk_handle: *mut SDKHandle, @@ -225,7 +232,7 @@ mod tests { result_len: *mut usize, ) -> *mut u8 { // Return a mock signature (64 bytes for ECDSA) allocated with libc::malloc - let signature = vec![0u8; 64]; + let signature = [0u8; 64]; *result_len = signature.len(); let ptr = libc::malloc(signature.len()) as *mut u8; if !ptr.is_null() { @@ -578,7 +585,7 @@ mod tests { fn test_unfreeze_with_serialized_contract() { let transition_owner_id = create_valid_transition_owner_id(); let mut params = create_valid_unfreeze_params(); - let contract_data = vec![0u8; 100]; // Mock serialized contract + let contract_data = [0u8; 100]; // Mock serialized contract params.serialized_contract = contract_data.as_ptr(); params.serialized_contract_len = contract_data.len(); diff --git a/packages/rs-sdk-ffi/src/token/utils.rs b/packages/rs-sdk-ffi/src/token/utils.rs index db872f06bd..9f0d111b18 100644 --- a/packages/rs-sdk-ffi/src/token/utils.rs +++ b/packages/rs-sdk-ffi/src/token/utils.rs @@ -67,6 +67,7 @@ pub unsafe fn extract_user_fee_increase( } /// Validate that either contract ID or serialized contract is provided (but not both) +#[allow(clippy::result_large_err)] pub unsafe fn validate_contract_params( token_contract_id: *const c_char, serialized_contract: *const u8, @@ -91,6 +92,7 @@ pub unsafe fn validate_contract_params( } /// Parse optional public note from C string +#[allow(clippy::result_large_err)] pub unsafe fn parse_optional_note(note_ptr: *const c_char) -> Result, FFIError> { if note_ptr.is_null() { Ok(None) @@ -103,6 +105,7 @@ pub unsafe fn parse_optional_note(note_ptr: *const c_char) -> Result Result { if id_bytes.is_null() { return Err(FFIError::InternalError( diff --git a/packages/rs-sdk-ffi/src/types.rs b/packages/rs-sdk-ffi/src/types.rs index 23344b1bc7..fc12c9e431 100644 --- a/packages/rs-sdk-ffi/src/types.rs +++ b/packages/rs-sdk-ffi/src/types.rs @@ -326,6 +326,11 @@ pub struct DashSDKStateTransitionCreationOptions { } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_string_free(s: *mut c_char) { if !s.is_null() { @@ -334,6 +339,11 @@ pub unsafe extern "C" fn dash_sdk_string_free(s: *mut c_char) { } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_binary_data_free(binary_data: *mut DashSDKBinaryData) { if binary_data.is_null() { @@ -348,6 +358,11 @@ pub unsafe extern "C" fn dash_sdk_binary_data_free(binary_data: *mut DashSDKBina } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_info_free(info: *mut DashSDKIdentityInfo) { if info.is_null() { @@ -359,6 +374,11 @@ pub unsafe extern "C" fn dash_sdk_identity_info_free(info: *mut DashSDKIdentityI } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_document_info_free(info: *mut DashSDKDocumentInfo) { if info.is_null() { @@ -389,6 +409,11 @@ pub unsafe extern "C" fn dash_sdk_document_info_free(info: *mut DashSDKDocumentI } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_identity_balance_map_free(map: *mut DashSDKIdentityBalanceMap) { if map.is_null() { @@ -467,6 +492,15 @@ pub struct DashSDKNameTimestampList { } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_contender_free(contender: *mut DashSDKContender) { if contender.is_null() { @@ -478,6 +512,11 @@ pub unsafe extern "C" fn dash_sdk_contender_free(contender: *mut DashSDKContende } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_contest_info_free(info: *mut DashSDKContestInfo) { if info.is_null() { @@ -495,6 +534,11 @@ pub unsafe extern "C" fn dash_sdk_contest_info_free(info: *mut DashSDKContestInf } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_contested_name_free(name: *mut DashSDKContestedName) { if name.is_null() { @@ -519,6 +563,11 @@ pub unsafe extern "C" fn dash_sdk_contested_name_free(name: *mut DashSDKConteste } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_contested_names_list_free(list: *mut DashSDKContestedNamesList) { if list.is_null() { @@ -551,6 +600,11 @@ pub unsafe extern "C" fn dash_sdk_contested_names_list_free(list: *mut DashSDKCo } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_name_timestamp_free(entry: *mut DashSDKNameTimestamp) { if entry.is_null() { @@ -562,6 +616,11 @@ pub unsafe extern "C" fn dash_sdk_name_timestamp_free(entry: *mut DashSDKNameTim } /// 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_name_timestamp_list_free(list: *mut DashSDKNameTimestampList) { if list.is_null() { diff --git a/packages/rs-sdk-ffi/src/unified.rs b/packages/rs-sdk-ffi/src/unified.rs index 86e72bc1d7..1431a8e9fc 100644 --- a/packages/rs-sdk-ffi/src/unified.rs +++ b/packages/rs-sdk-ffi/src/unified.rs @@ -5,11 +5,9 @@ //! when both are available. It manages initialization, state synchronization, and //! cross-layer operations. -use std::ffi::{c_char, CStr}; +use std::ffi::c_char; use std::sync::atomic::{AtomicBool, Ordering}; -use crate::{DashSDKError, DashSDKErrorCode, FFIError}; - use crate::types::{DashSDKConfig, SDKHandle}; use dash_spv_ffi::{FFIClientConfig, FFIDashSpvClient}; @@ -131,6 +129,7 @@ pub unsafe extern "C" fn dash_unified_sdk_start(handle: *mut UnifiedSDKHandle) - return -1; } + #[cfg(feature = "core")] let handle = &*handle; // Start Core SDK if available @@ -158,6 +157,7 @@ pub unsafe extern "C" fn dash_unified_sdk_stop(handle: *mut UnifiedSDKHandle) -> return -1; } + #[cfg(feature = "core")] let handle = &*handle; // Stop Core SDK if available @@ -338,7 +338,7 @@ pub extern "C" fn dash_unified_sdk_has_core_support() -> bool { #[cfg(test)] mod tests { use super::*; - use crate::types::DashSDKNetwork; + use std::ptr; /// Test the basic lifecycle of the unified SDK with core feature enabled diff --git a/packages/rs-sdk-ffi/src/utils.rs b/packages/rs-sdk-ffi/src/utils.rs index 50a966314d..02c70b760c 100644 --- a/packages/rs-sdk-ffi/src/utils.rs +++ b/packages/rs-sdk-ffi/src/utils.rs @@ -14,6 +14,11 @@ use std::os::raw::c_char; /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_utils_hex_to_base58(hex_string: *const c_char) -> DashSDKResult { if hex_string.is_null() { @@ -79,6 +84,10 @@ pub unsafe extern "C" fn dash_sdk_utils_hex_to_base58(hex_string: *const c_char) /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_utils_base58_to_hex( base58_string: *const c_char, @@ -128,6 +137,9 @@ pub unsafe extern "C" fn dash_sdk_utils_base58_to_hex( /// /// # 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. #[no_mangle] pub unsafe extern "C" fn dash_sdk_utils_is_valid_base58(string: *const c_char) -> u8 { if string.is_null() { diff --git a/packages/rs-sdk-ffi/src/voting/mod.rs b/packages/rs-sdk-ffi/src/voting/mod.rs index 87776312a9..f6736c90d6 100644 --- a/packages/rs-sdk-ffi/src/voting/mod.rs +++ b/packages/rs-sdk-ffi/src/voting/mod.rs @@ -1,5 +1,5 @@ // Voting-related modules -pub mod queries; +mod queries; // Re-export all public functions pub use queries::*; diff --git a/packages/rs-sdk-ffi/src/voting/queries/vote_polls_by_end_date.rs b/packages/rs-sdk-ffi/src/voting/queries/vote_polls_by_end_date.rs index cfb454d7cb..861e83e6f3 100644 --- a/packages/rs-sdk-ffi/src/voting/queries/vote_polls_by_end_date.rs +++ b/packages/rs-sdk-ffi/src/voting/queries/vote_polls_by_end_date.rs @@ -80,6 +80,7 @@ pub unsafe extern "C" fn dash_sdk_voting_get_vote_polls_by_end_date( } } +#[allow(clippy::too_many_arguments)] fn get_vote_polls_by_end_date( sdk_handle: *const SDKHandle, start_time_ms: u64, diff --git a/packages/rs-sdk-ffi/tests/context_provider_test.rs b/packages/rs-sdk-ffi/tests/context_provider_test.rs index 22ca2560fa..f4fba6d3a6 100644 --- a/packages/rs-sdk-ffi/tests/context_provider_test.rs +++ b/packages/rs-sdk-ffi/tests/context_provider_test.rs @@ -49,7 +49,7 @@ mod tests { } let callbacks = ContextProviderCallbacks { - core_handle: 1 as *mut core::ffi::c_void, + core_handle: std::ptr::dangling_mut::(), get_platform_activation_height: get_height_cb, get_quorum_public_key: get_quorum_pk_cb, }; @@ -75,7 +75,7 @@ mod tests { unsafe { // Create a mock Core SDK handle using an opaque pointer // In real usage, this would come from the Core SDK - let core_handle_ptr = 1 as *mut CoreSDKHandle; + let core_handle_ptr = std::ptr::dangling_mut::(); // Create base config let dapi_addresses = CString::new("https://testnet.dash.org:3000").unwrap(); diff --git a/packages/rs-sdk-ffi/tests/integration_tests/config.rs b/packages/rs-sdk-ffi/tests/integration_tests/config.rs index 21b304a091..492c2f5030 100644 --- a/packages/rs-sdk-ffi/tests/integration_tests/config.rs +++ b/packages/rs-sdk-ffi/tests/integration_tests/config.rs @@ -1,3 +1,4 @@ +#![allow(unexpected_cfgs, unused_variables, dead_code)] //! Configuration helpers for testing of rs-sdk-ffi. //! //! This module contains [Config] struct that can be used to configure tests. @@ -144,3 +145,4 @@ impl Default for Config { Self::new() } } +// per-file allows are set at the top diff --git a/packages/rs-sdk-ffi/tests/integration_tests/contested_resource.rs b/packages/rs-sdk-ffi/tests/integration_tests/contested_resource.rs index e9f62d83ff..489f0ebedd 100644 --- a/packages/rs-sdk-ffi/tests/integration_tests/contested_resource.rs +++ b/packages/rs-sdk-ffi/tests/integration_tests/contested_resource.rs @@ -1,3 +1,4 @@ +#![allow(unused_variables)] //! Contested resource tests for rs-sdk-ffi use crate::config::Config; diff --git a/packages/rs-sdk-ffi/tests/integration_tests/data_contract.rs b/packages/rs-sdk-ffi/tests/integration_tests/data_contract.rs index e92b6abb5f..3e381a9da1 100644 --- a/packages/rs-sdk-ffi/tests/integration_tests/data_contract.rs +++ b/packages/rs-sdk-ffi/tests/integration_tests/data_contract.rs @@ -1,3 +1,4 @@ +#![allow(unused_variables)] //! Data contract tests for rs-sdk-ffi use crate::config::Config; diff --git a/packages/rs-sdk-ffi/tests/integration_tests/document.rs b/packages/rs-sdk-ffi/tests/integration_tests/document.rs index 2a9112566f..d9ca85e5a0 100644 --- a/packages/rs-sdk-ffi/tests/integration_tests/document.rs +++ b/packages/rs-sdk-ffi/tests/integration_tests/document.rs @@ -3,7 +3,6 @@ use crate::config::Config; use crate::ffi_utils::*; use rs_sdk_ffi::*; -use std::ptr; /// Test fetching a non-existent document #[test] @@ -96,7 +95,7 @@ fn test_document_read() { /// Test searching documents with a simple query — removed due to lack of matching vectors /// Test searching documents with startsWith — removed due to lack of matching vectors - +/// /// Test searching documents with complex query including order by #[test] fn test_document_search_with_order_by() { diff --git a/packages/rs-sdk-ffi/tests/integration_tests/ffi_utils.rs b/packages/rs-sdk-ffi/tests/integration_tests/ffi_utils.rs index dd8b249cbd..1137f8cc78 100644 --- a/packages/rs-sdk-ffi/tests/integration_tests/ffi_utils.rs +++ b/packages/rs-sdk-ffi/tests/integration_tests/ffi_utils.rs @@ -7,7 +7,6 @@ use std::ffi::{CStr, CString}; use std::fs; use std::os::raw::c_char; use std::path::PathBuf; -use std::ptr; /// Create an SDK handle for testing using the mock mode with offline test vectors pub fn create_test_sdk_handle(namespace: &str) -> *const SDKHandle { @@ -178,10 +177,9 @@ pub fn parse_json_result(json: &str) -> Result { /// Test helper to assert that a result is successful and contains data pub unsafe fn assert_success_with_data(result: DashSDKResult) -> String { - let data = parse_string_result(result) + parse_string_result(result) .expect("Result should be successful") - .expect("Result should contain data"); - data + .expect("Result should contain data") } /// Test helper to assert that a result is successful but contains no data (None) @@ -191,6 +189,7 @@ pub unsafe fn assert_success_none(result: DashSDKResult) { } /// Test helper to assert that a result is an error +#[allow(dead_code)] pub unsafe fn assert_error(result: DashSDKResult) { assert!( parse_string_result(result).is_err(), diff --git a/packages/rs-sdk-ffi/tests/integration_tests/identity.rs b/packages/rs-sdk-ffi/tests/integration_tests/identity.rs index c0c71b4785..165c92ccda 100644 --- a/packages/rs-sdk-ffi/tests/integration_tests/identity.rs +++ b/packages/rs-sdk-ffi/tests/integration_tests/identity.rs @@ -1,3 +1,4 @@ +#![allow(unused_variables)] //! Identity tests for rs-sdk-ffi use crate::config::Config; diff --git a/packages/rs-sdk-ffi/tests/integration_tests/system.rs b/packages/rs-sdk-ffi/tests/integration_tests/system.rs index 0d37803290..0d922bc6bd 100644 --- a/packages/rs-sdk-ffi/tests/integration_tests/system.rs +++ b/packages/rs-sdk-ffi/tests/integration_tests/system.rs @@ -2,7 +2,6 @@ use crate::ffi_utils::*; use rs_sdk_ffi::*; -use std::ptr; /// Test fetching epochs info #[test] diff --git a/packages/rs-sdk-ffi/tests/integration_tests/token.rs b/packages/rs-sdk-ffi/tests/integration_tests/token.rs index 4faf4c422b..5f00d41b99 100644 --- a/packages/rs-sdk-ffi/tests/integration_tests/token.rs +++ b/packages/rs-sdk-ffi/tests/integration_tests/token.rs @@ -1,3 +1,4 @@ +#![allow(unused_variables)] //! Token tests for rs-sdk-ffi use crate::config::Config; @@ -51,9 +52,9 @@ fn test_token_identities_balances() { Ok(Some(json_str)) => { let json = parse_json_result(&json_str).expect("valid JSON"); assert!(json.is_object(), "Expected object, got: {:?}", json); - assert!(json.get(&base58_from_bytes(1)).is_some()); - assert!(json.get(&base58_from_bytes(2)).is_some()); - assert!(json.get(&base58_from_bytes(3)).is_some()); + assert!(json.get(base58_from_bytes(1)).is_some()); + assert!(json.get(base58_from_bytes(2)).is_some()); + assert!(json.get(base58_from_bytes(3)).is_some()); } Ok(None) => {} Err(_e) => { @@ -123,7 +124,7 @@ fn test_token_status() { let json = parse_json_result(&json_str).expect("valid JSON"); assert!(json.is_object(), "Expected object, got: {:?}", json); // Expect mapping by token ID - assert!(json.get(&token0_id_b58()).is_some()); + assert!(json.get(token0_id_b58()).is_some()); } Ok(None) => { // Token might not exist diff --git a/packages/rs-sdk/src/error.rs b/packages/rs-sdk/src/error.rs index 545334e877..cb1b79dd7e 100644 --- a/packages/rs-sdk/src/error.rs +++ b/packages/rs-sdk/src/error.rs @@ -14,6 +14,7 @@ use std::time::Duration; /// Error type for the SDK // TODO: Propagate server address and retry information so that the user can retrieve it +#[allow(clippy::large_enum_variant)] #[derive(Debug, thiserror::Error)] pub enum Error { /// SDK is not configured properly diff --git a/packages/rs-sdk/src/lib.rs b/packages/rs-sdk/src/lib.rs index 05a6eb0696..582d44c291 100644 --- a/packages/rs-sdk/src/lib.rs +++ b/packages/rs-sdk/src/lib.rs @@ -60,6 +60,7 @@ // TODO re-enable when docs are complete // #![warn(missing_docs)] #![allow(rustdoc::private_intra_doc_links)] +#![allow(clippy::result_large_err)] pub mod core; pub mod error; diff --git a/packages/rs-sdk/src/mock/requests.rs b/packages/rs-sdk/src/mock/requests.rs index e942c0fc32..7c79273f15 100644 --- a/packages/rs-sdk/src/mock/requests.rs +++ b/packages/rs-sdk/src/mock/requests.rs @@ -193,7 +193,7 @@ impl MockResponse for DataContract { // FIXME: Seems that DataContract doesn't implement PlatformVersionedDecode + PlatformVersionEncode, // so we just use some methods implemented directly on these objects. impl MockResponse for (DataContract, Vec) { - fn mock_serialize(&self, sdk: &MockDashPlatformSdk) -> Vec { + fn mock_serialize(&self, _sdk: &MockDashPlatformSdk) -> Vec { self.1.clone() } diff --git a/packages/rs-sdk/src/platform/dpns_usernames/contested_queries.rs b/packages/rs-sdk/src/platform/dpns_usernames/contested_queries.rs index b815b47f39..da3f86fcf4 100644 --- a/packages/rs-sdk/src/platform/dpns_usernames/contested_queries.rs +++ b/packages/rs-sdk/src/platform/dpns_usernames/contested_queries.rs @@ -18,7 +18,7 @@ use drive::query::vote_poll_vote_state_query::{ use drive::query::vote_polls_by_document_type_query::VotePollsByDocumentTypeQuery; use drive::query::VotePollsByEndDateDriveQuery; use drive_proof_verifier::types::{Contenders, ContestedResource, VotePollsGroupedByTimestamp}; -use std::collections::{BTreeMap, HashSet}; +use std::collections::BTreeMap; // DPNS parent domain constant const DPNS_PARENT_DOMAIN: &str = "dash"; @@ -50,7 +50,7 @@ impl Sdk { /// /// * `limit` - Maximum number of results to return /// * `start_after` - Optional name to start after - /// (for pagination) + /// (for pagination) /// /// # Returns /// @@ -262,11 +262,7 @@ impl Sdk { .any(|(contender_id, _)| contender_id == &identity_id); if is_contender { - let contenders = vote_state - .contenders - .into_iter() - .map(|(id, _)| id) - .collect(); + let contenders = vote_state.contenders.into_keys().collect(); usernames_with_identity.push(ContestedDpnsUsername { label: contested_label.clone(), normalized_label: contested_label.to_lowercase(), @@ -301,6 +297,7 @@ impl Sdk { } // Helper function to extract label from index values + #[allow(dead_code)] fn extract_label_from_index_values(index_values: &[Vec]) -> Option { if index_values.len() >= 2 { String::from_utf8(index_values[1].clone()).ok() @@ -455,18 +452,15 @@ impl Sdk { for (timestamp, polls) in result.0 { let mut dpns_polls_count = 0; - for poll in polls { - // Check if this is a DPNS contest - if let VotePoll::ContestedDocumentResourceVotePoll(contested_poll) = poll { - if contested_poll.contract_id == dpns_contract_id - && contested_poll.document_type_name == "domain" - { - // Extract the contested name from index_values - if contested_poll.index_values.len() >= 2 { - if let Value::Text(label) = &contested_poll.index_values[1] { - name_to_end_time.insert(label.clone(), timestamp); - dpns_polls_count += 1; - } + for VotePoll::ContestedDocumentResourceVotePoll(contested_poll) in polls { + if contested_poll.contract_id == dpns_contract_id + && contested_poll.document_type_name == "domain" + { + // Extract the contested name from index_values + if contested_poll.index_values.len() >= 2 { + if let Value::Text(label) = &contested_poll.index_values[1] { + name_to_end_time.insert(label.clone(), timestamp); + dpns_polls_count += 1; } } } @@ -831,7 +825,7 @@ mod tests { // If we got results, verify no duplicate names let names: Vec<_> = contests.keys().cloned().collect(); - let unique_names: HashSet<_> = names.iter().cloned().collect(); + let unique_names: std::collections::HashSet<_> = names.iter().cloned().collect(); assert_eq!( names.len(), unique_names.len(), @@ -988,7 +982,7 @@ mod tests { if let (Ok(non_resolved), Ok(contests)) = (&non_resolved_names, ¤t_contests) { // Get names from current contests map - let contest_names: HashSet<_> = contests.keys().cloned().collect(); + let contest_names: std::collections::HashSet<_> = contests.keys().cloned().collect(); println!(" Names from current contests: {}", contest_names.len()); println!(" Names from non-resolved query: {}", non_resolved.len()); diff --git a/packages/rs-sdk/src/platform/dpns_usernames/queries.rs b/packages/rs-sdk/src/platform/dpns_usernames/queries.rs index ee0e046963..ebee7a41fc 100644 --- a/packages/rs-sdk/src/platform/dpns_usernames/queries.rs +++ b/packages/rs-sdk/src/platform/dpns_usernames/queries.rs @@ -190,7 +190,6 @@ impl Sdk { #[cfg(test)] mod tests { - use super::*; use crate::SdkBuilder; use dpp::dashcore::Network; diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index 3908aa89f6..ed0e13374f 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -357,7 +357,7 @@ impl Sdk { /// * the `self` instance is not a `Mock` variant, /// * the `self` instance is in use by another thread. #[cfg(feature = "mocks")] - pub fn mock(&mut self) -> MutexGuard { + pub fn mock(&mut self) -> MutexGuard<'_, MockDashPlatformSdk> { if let Sdk { inner: SdkInstance::Mock { ref mock, .. }, .. @@ -577,7 +577,7 @@ impl Sdk { } /// Returns a future that resolves when the Sdk is cancelled (e.g. shutdown was requested). - pub fn cancelled(&self) -> WaitForCancellationFuture { + pub fn cancelled(&self) -> WaitForCancellationFuture<'_> { self.cancel_token.cancelled() } diff --git a/packages/swift-sdk/Package.swift b/packages/swift-sdk/Package.swift index f4329e8a4d..6e30c9ca9c 100644 --- a/packages/swift-sdk/Package.swift +++ b/packages/swift-sdk/Package.swift @@ -26,4 +26,4 @@ let package = Package( path: "Sources/SwiftDashSDK" ), ] -) \ No newline at end of file +) diff --git a/packages/wasm-sdk/src/sdk.rs b/packages/wasm-sdk/src/sdk.rs index f08df76766..91652e0025 100644 --- a/packages/wasm-sdk/src/sdk.rs +++ b/packages/wasm-sdk/src/sdk.rs @@ -786,7 +786,7 @@ pub async fn identity_put(sdk: &WasmSdk) { let asset_lock_proof = AssetLockProof::default(); let asset_lock_proof_private_key = - PrivateKey::from_slice(&[0; 32], Network::Testnet).expect("create private key"); + PrivateKey::from_byte_array(&[0; 32], Network::Testnet).expect("create private key"); let signer = MockSigner; let _pushed: Identity = identity diff --git a/packages/wasm-sdk/src/state_transitions/identity/mod.rs b/packages/wasm-sdk/src/state_transitions/identity/mod.rs index 0b21433ee4..2b51dc7dda 100644 --- a/packages/wasm-sdk/src/state_transitions/identity/mod.rs +++ b/packages/wasm-sdk/src/state_transitions/identity/mod.rs @@ -1015,7 +1015,11 @@ impl WasmSdk { if key_bytes.len() != 32 { return Err(JsValue::from_str("Private key must be 32 bytes")); } - PrivateKey::from_slice(&key_bytes, self.network()) + let key_array: [u8; 32] = key_bytes + .as_slice() + .try_into() + .map_err(|_| JsValue::from_str("Private key must be 32 bytes"))?; + PrivateKey::from_byte_array(&key_array, self.network()) .map_err(|e| JsValue::from_str(&format!("Invalid private key bytes: {}", e)))? } else { // Try WIF @@ -1107,4 +1111,4 @@ impl WasmSdk { Ok(result_obj.into()) } -} \ No newline at end of file +} diff --git a/packages/wasm-sdk/src/wallet/key_derivation.rs b/packages/wasm-sdk/src/wallet/key_derivation.rs index eb6afd59c9..0506bb0902 100644 --- a/packages/wasm-sdk/src/wallet/key_derivation.rs +++ b/packages/wasm-sdk/src/wallet/key_derivation.rs @@ -226,7 +226,8 @@ pub fn derive_key_from_seed_phrase(mnemonic: &str, passphrase: Option, n }; // Create private key from seed bytes - let private_key = dashcore::PrivateKey::from_slice(key_bytes, net) + let key_array: [u8; 32] = key_bytes.try_into().map_err(|_| JsError::new("Seed must be 32 bytes"))?; + let private_key = dashcore::PrivateKey::from_byte_array(&key_array, net) .map_err(|e| JsError::new(&format!("Failed to create private key: {}", e)))?; // Get public key diff --git a/packages/wasm-sdk/src/wallet/key_generation.rs b/packages/wasm-sdk/src/wallet/key_generation.rs index 2bc5613ad0..2b11149d8c 100644 --- a/packages/wasm-sdk/src/wallet/key_generation.rs +++ b/packages/wasm-sdk/src/wallet/key_generation.rs @@ -40,7 +40,7 @@ pub fn generate_key_pair(network: &str) -> Result { .map_err(|e| JsError::new(&format!("Failed to generate random bytes: {}", e)))?; // Create private key - let private_key = PrivateKey::from_slice(&key_bytes, net) + let private_key = PrivateKey::from_byte_array(&key_bytes, net) .map_err(|e| JsError::new(&format!("Failed to create private key: {}", e)))?; // Get public key @@ -132,7 +132,10 @@ pub fn key_pair_from_hex(private_key_hex: &str, network: &str) -> Result Result