Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
057046f
feat(swift-sdk): add BLAST address sync for iOS (#3079)
QuantumExplorer Mar 17, 2026
a04b890
chore: cargo fmt
QuantumExplorer Mar 17, 2026
eb41d36
merge: resolve conflict with v3.1-dev in CoreWalletManager
QuantumExplorer Mar 17, 2026
e33556c
fix: address CodeRabbit review feedback
QuantumExplorer Mar 17, 2026
04aedca
fix(swift-sdk): validate Core addresses via Rust FFI before parsing
QuantumExplorer Mar 17, 2026
fb93ef8
fix(sdk): fix clippy warning for compacted loop condition
QuantumExplorer Mar 17, 2026
a32e3df
fix: outKeyLen capacity bug and restore compacted catch-up
QuantumExplorer Mar 18, 2026
a97e642
merge: resolve v3.1-dev conflicts and fix optional API changes
QuantumExplorer Mar 18, 2026
bc1720d
fix(rs-sdk-ffi): use Network::Mainnet instead of Network::Dash
QuantumExplorer Mar 18, 2026
6e8cf0c
fix(rs-sdk-ffi): fix clippy needless_range_loop warnings
QuantumExplorer Mar 18, 2026
fc1e8fb
feat(sdk): rewrite incremental catch-up and document sync flow
QuantumExplorer Mar 18, 2026
28c256b
test(drive-abci): add BLAST sync full flow strategy test
QuantumExplorer Mar 18, 2026
f78fef7
fix(test): fix BLAST sync strategy test signer issue
QuantumExplorer Mar 18, 2026
3c4698e
feat(sdk): skip compacted queries via key_exists_as_boundary
QuantumExplorer Mar 18, 2026
5c6052b
fix(swift-sdk): wrap ShieldedPoolClient handle in Sendable wrapper
QuantumExplorer Mar 18, 2026
b282f5a
docs(sdk): add full BLAST sync flowchart to book
QuantumExplorer Mar 18, 2026
73f6bf5
docs(sdk): replace ASCII flowchart with Mermaid diagram
QuantumExplorer Mar 18, 2026
675e53b
ci: add book preview deployment for PRs
QuantumExplorer Mar 18, 2026
c4b10b9
ci: auto-cleanup book preview on PR close/merge
QuantumExplorer Mar 18, 2026
3d5d73c
fix(ci): use artifacts instead of Pages for book PR previews
QuantumExplorer Mar 18, 2026
7c1847f
docs(sdk): improve BLAST sync book with mermaid, privacy, performance
QuantumExplorer Mar 18, 2026
429a8c9
fix(ci): remove nonisolated deinit and add SDK test coverage
QuantumExplorer Mar 18, 2026
ea9f3e3
feat(sdk): implement RangeAfter-based compaction detection
QuantumExplorer Mar 18, 2026
a69150a
fix(swift-sdk): replace Timer with async Task loop for periodic sync
QuantumExplorer Mar 18, 2026
ad080ae
fix(swift-sdk): add Last Recent Block to sync UI for debugging
QuantumExplorer Mar 18, 2026
ccaf832
fix(sdk): revert last_known_recent_block fallback to metadata tip
QuantumExplorer Mar 18, 2026
eda02b1
feat(sdk): add entry count metrics for recent/compacted queries
QuantumExplorer Mar 18, 2026
3510e5c
feat(sdk): skip compacted when recent tree is empty, fix sync loop
QuantumExplorer Mar 18, 2026
934972a
fix(sdk): simplify compacted skip logic
QuantumExplorer Mar 18, 2026
cef977f
docs(sdk): update BLAST sync flowchart and docs for RangeAfter
QuantumExplorer Mar 18, 2026
49fbbb1
fix(swift-sdk): always show Last Recent Block field in sync UI
QuantumExplorer Mar 18, 2026
717e58e
feat(sdk): return GroveDB proof bytes from address sync
QuantumExplorer Mar 18, 2026
5ec3a81
fix(swift-sdk): use onTapGesture for proof detail instead of Navigati…
QuantumExplorer Mar 18, 2026
584a5c2
feat(sdk): add formatted GroveDB proof viewer
QuantumExplorer Mar 18, 2026
1aaaf36
merge: resolve v3.1-dev conflict in CoreContentView
QuantumExplorer Mar 18, 2026
95c0810
feat(sdk): use boundaries() for smarter compaction detection
QuantumExplorer Mar 18, 2026
8dc1714
feat(sdk): simplify compaction detection using boundaries()
QuantumExplorer Mar 18, 2026
778aeb4
feat(sdk): persist platform balances across app launches and reduce s…
QuantumExplorer Mar 20, 2026
7b93f7e
fix(sdk): fix broken compaction tests and add compaction detection co…
QuantumExplorer Mar 20, 2026
f9f9c57
fix(ffi): address review feedback — catch_unwind, expect, checked_mul…
QuantumExplorer Mar 20, 2026
a1fec8b
fix(ffi): use unwrap_or_default for catch_unwind bool result (clippy)
QuantumExplorer Mar 20, 2026
50a201b
test(sdk): improve BLAST address sync test coverage across drive and sdk
QuantumExplorer Mar 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added build_rs_cov.profraw
Binary file not shown.
3 changes: 3 additions & 0 deletions packages/rs-sdk-ffi/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ fn main() {
autogen_warning: Some(
"/* This file is auto-generated. Do not modify manually. */\n/* Unified Dash SDK - includes both Core (SPV) and Platform functionality */".to_string(),
),
after_includes: Some(
"/* Forward declarations for opaque types */\nstruct ShieldedPoolClient;\n".to_string(),
),
includes: vec![],
sys_includes: vec!["stdint.h".to_string(), "stdbool.h".to_string()],
no_includes: false,
Expand Down
2 changes: 2 additions & 0 deletions packages/rs-sdk-ffi/build_ios.sh
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ typedef struct DocumentHandle { unsigned char _private[0]; } DocumentHandle;
typedef struct IdentityHandle { unsigned char _private[0]; } IdentityHandle;
typedef struct IdentityPublicKeyHandle { unsigned char _private[0]; } IdentityPublicKeyHandle;
typedef struct SignerHandle { unsigned char _private[0]; } SignerHandle;
// Shielded pool opaque handle
typedef struct ShieldedPoolClient { unsigned char _private[0]; } ShieldedPoolClient;

// ============================================================================
// Key Wallet FFI Functions and Types
Expand Down
119 changes: 119 additions & 0 deletions packages/rs-sdk-ffi/src/address/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,122 @@ pub use queries::*;

// Re-export transition functions
pub use transitions::*;

use crate::{DashSDKError, DashSDKErrorCode, DashSDKResult};
use dash_sdk::dpp::address_funds::PlatformAddress;
use dash_sdk::dpp::dashcore::blockdata::script::Script;
use std::ffi::CString;

/// Encode a P2PKH script pubkey as a bech32m platform address string (DIP-18).
///
/// Takes a 25-byte P2PKH scriptPubKey (OP_DUP OP_HASH160 <20-byte-hash> OP_EQUALVERIFY OP_CHECKSIG)
/// and returns the bech32m-encoded platform address (e.g. "tdash1..." on testnet).
///
/// # Safety
/// - `script_pubkey` must point to `script_len` bytes
/// - `network`: 0 = mainnet, 1 = testnet, 2 = regtest, 3 = devnet
/// - Returns a DashSDKResult whose `data` field is a heap-allocated C string.
/// Free it with `dash_sdk_string_free`.
#[no_mangle]
pub unsafe extern "C" fn dash_sdk_encode_platform_address(
script_pubkey: *const u8,
script_len: u32,
network: u32,
) -> DashSDKResult {
if script_pubkey.is_null() {
return DashSDKResult::error(DashSDKError::new(
DashSDKErrorCode::InvalidParameter,
"script_pubkey is null".to_string(),
));
}

let script = std::slice::from_raw_parts(script_pubkey, script_len as usize);

// Parse P2PKH script: 76 a9 14 <20-byte-hash> 88 ac
if script.len() != 25
|| script[0] != 0x76
|| script[1] != 0xa9
|| script[2] != 0x14
|| script[23] != 0x88
|| script[24] != 0xac
{
return DashSDKResult::error(DashSDKError::new(
DashSDKErrorCode::InvalidParameter,
format!(
"Invalid P2PKH scriptPubKey: expected 25 bytes (76 a9 14 ... 88 ac), got {} bytes",
script.len()
),
));
}

let hash: [u8; 20] = script[3..23].try_into().unwrap();
Comment thread
QuantumExplorer marked this conversation as resolved.
Outdated
let platform_addr = PlatformAddress::P2pkh(hash);

let dash_network = match network {
0 => dash_sdk::dpp::dashcore::Network::Dash,
Comment thread
QuantumExplorer marked this conversation as resolved.
Outdated
1 => dash_sdk::dpp::dashcore::Network::Testnet,
2 => dash_sdk::dpp::dashcore::Network::Regtest,
3 => dash_sdk::dpp::dashcore::Network::Devnet,
_ => {
return DashSDKResult::error(DashSDKError::new(
DashSDKErrorCode::InvalidParameter,
format!("Unknown network code: {}. Expected 0 (mainnet), 1 (testnet), 2 (regtest), or 3 (devnet)", network),
));
}
};

let encoded = platform_addr.to_bech32m_string(dash_network);

match CString::new(encoded) {
Ok(c_str) => DashSDKResult::success(c_str.into_raw() as *mut std::os::raw::c_void),
Err(_) => DashSDKResult::error(DashSDKError::new(
Comment thread
QuantumExplorer marked this conversation as resolved.
Outdated
DashSDKErrorCode::InternalError,
"Failed to create C string from encoded address".to_string(),
)),
}
}

/// Convert a P2PKH scriptPubKey to the GroveDB storage key format for platform addresses.
///
/// Takes a 25-byte P2PKH scriptPubKey and returns 21-byte storage key
/// (0x00 type byte + 20-byte pubkey hash) used as the key in the platform
/// address funds tree.
///
/// # Safety
/// - `script_pubkey` must point to `script_len` bytes (expected 25 for P2PKH)
/// - `out_key` must point to a buffer of at least 21 bytes
/// - Returns true on success, false on error
#[no_mangle]
pub unsafe extern "C" fn dash_sdk_script_to_platform_address_key(
script_pubkey: *const u8,
script_len: u32,
out_key: *mut u8,
out_key_len: *mut u32,
) -> bool {
if script_pubkey.is_null() || out_key.is_null() || out_key_len.is_null() {
return false;
}

let script_bytes = std::slice::from_raw_parts(script_pubkey, script_len as usize);
let script = Script::from_bytes(script_bytes);

// Read the caller-supplied capacity before writing
let capacity = *out_key_len as usize;

// Extract the pubkey hash from the P2PKH script
if let Some(hash_bytes) = script.p2pkh_public_key_hash_bytes() {
if hash_bytes.len() == 20 {
let hash: [u8; 20] = hash_bytes.try_into().unwrap();
let platform_addr = PlatformAddress::P2pkh(hash);
let storage_bytes = platform_addr.to_bytes();
if storage_bytes.len() > capacity {
return false;
}
std::ptr::copy_nonoverlapping(storage_bytes.as_ptr(), out_key, storage_bytes.len());
*out_key_len = storage_bytes.len() as u32;
return true;
}
}

false
}
Loading
Loading