Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/rs-dapi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ prometheus = "0.14"
once_cell = "1.19"

# Dash Core RPC client
dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04" }
dash-spv = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04" }
dashcore-rpc = { path = "../../../rust-dashcore/rpc-client" }
dash-spv = { path = "../../../rust-dashcore/dash-spv" }

rs-dash-event-bus = { path = "../rs-dash-event-bus" }

Expand Down
10 changes: 5 additions & 5 deletions packages/rs-dpp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@ chrono = { version = "0.4.35", default-features = false, features = [
] }
chrono-tz = { version = "0.8", optional = true }
ciborium = { version = "0.2.2", optional = true }
dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04", features = [
dashcore = { path = "../../../rust-dashcore/dash", features = [
"std",
"secp-recovery",
"rand",
"signer",
"serde",
"eddsa",
], default-features = false }
key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04", optional = true }
key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04", optional = true }
dash-spv = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04", optional = true }
dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04", optional = true }
key-wallet = { path = "../../../rust-dashcore/key-wallet", optional = true }
key-wallet-manager = { path = "../../../rust-dashcore/key-wallet-manager", optional = true }
dash-spv = { path = "../../../rust-dashcore/dash-spv", optional = true }
dashcore-rpc = { path = "../../../rust-dashcore/rpc-client", optional = true }

env_logger = { version = "0.11" }
getrandom = { version = "0.2", features = ["js"] }
Expand Down
2 changes: 1 addition & 1 deletion packages/rs-platform-encryption/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ description = "Cryptographic utilities for Dash Platform (DIP-15 DashPay encrypt

[dependencies]
# Cryptography
dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04" }
dashcore = { path = "../../../rust-dashcore/dash" }
aes = "0.8"
cbc = "0.1"
sha2 = "0.10"
Expand Down
4 changes: 2 additions & 2 deletions packages/rs-platform-wallet-ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

# Core dependencies (for Network type)
dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04" }
key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04" }
dashcore = { path = "../../../rust-dashcore/dash" }
key-wallet = { path = "../../../rust-dashcore/key-wallet" }

# Error handling
thiserror = "1.0"
Expand Down
6 changes: 3 additions & 3 deletions packages/rs-platform-wallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ dash-sdk = { path = "../rs-sdk", default-features = false, features = ["dashpay-
platform-encryption = { path = "../rs-platform-encryption" }

# Key wallet dependencies (from rust-dashcore)
key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04" }
key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04", optional = true }
key-wallet = { path = "../../../rust-dashcore/key-wallet" }
key-wallet-manager = { path = "../../../rust-dashcore/key-wallet-manager", optional = true }

# Core dependencies
dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04" }
dashcore = { path = "../../../rust-dashcore/dash" }

# Standard dependencies
thiserror = "1.0"
Expand Down
2 changes: 1 addition & 1 deletion packages/rs-sdk-ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ simple-signer = { path = "../simple-signer" }


# Core SDK integration (always included for unified SDK)
dash-spv-ffi = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04", optional = true }
dash-spv-ffi = { path = "../../../rust-dashcore/dash-spv-ffi", optional = true }

# Platform Wallet integration for DashPay support
platform-wallet-ffi = { path = "../rs-platform-wallet-ffi" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,13 @@ public class Wallet {
self.ownsHandle = false
}

/// Owning initializer for wallets returned by FFI functions that allocate a new Box<FFIWallet>.
/// The caller transfers ownership — deinit will call wallet_free().
internal init(owningHandle handle: UnsafeRawPointer) {
self.handle = UnsafeMutablePointer<FFIWallet>(mutating: handle.bindMemory(to: FFIWallet.self, capacity: 1))
self.ownsHandle = true
}


deinit {
if ownsHandle {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,9 @@ public class WalletManager {
}
throw KeyWalletError(ffiError: error)
}
// Wrap as non-owning wallet; the manager retains ownership
let wallet = Wallet(nonOwningHandle: UnsafeRawPointer(ptr))
// The FFI function allocates a new Box<FFIWallet> via Box::into_raw —
// we own it and must free it via wallet_free() when done.
let wallet = Wallet(owningHandle: UnsafeRawPointer(ptr))
return wallet
}

Expand Down Expand Up @@ -397,48 +398,61 @@ public class WalletManager {
guard !outputs.isEmpty else {
throw KeyWalletError.invalidInput("Transaction must have at least one output")
}

var error = FFIError()
var txBytesPtr: UnsafeMutablePointer<UInt8>?
var txLen: size_t = 0

var fee: UInt64 = 0;

let wallet = try self.getWallet(id: wallet.walletId)!

let ffiOutputs = outputs.map { $0.toFFI() }

let success = ffiOutputs.withUnsafeBufferPointer { outputsPtr in
wallet_build_and_sign_transaction(
self.handle,
wallet.ffiHandle,
accIndex,
outputsPtr.baseAddress,
outputs.count,
feeRate.intoFFI(),
&fee,
&txBytesPtr,
&txLen,
&error)
}

defer {
if error.message != nil {8
error_message_free(error.message)
let ffiWallet = try self.getWallet(id: wallet.walletId)!

// withExtendedLifetime keeps ffiWallet alive for the entire duration of
// the closure. Without this, Swift's ARC optimizer may release the
// Wallet object (and call wallet_free) after extracting the raw
// ffiHandle pointer but BEFORE the Rust FFI call finishes — causing a
// use-after-free / EXC_BAD_ACCESS in the Rust code.
return try withExtendedLifetime(ffiWallet) {
var error = FFIError()
var txBytesPtr: UnsafeMutablePointer<UInt8>?
var txLen: size_t = 0
var fee: UInt64 = 0

let ffiOutputs = outputs.map { $0.toFFI() }

// Free strdup'd C strings after the FFI call completes
defer {
for output in ffiOutputs {
free(UnsafeMutablePointer(mutating: output.address))
}
}
if let ptr = txBytesPtr {
transaction_bytes_free(ptr)

let success = ffiOutputs.withUnsafeBufferPointer { outputsPtr in
wallet_build_and_sign_transaction(
self.handle,
ffiWallet.ffiHandle,
accIndex,
outputsPtr.baseAddress,
outputs.count,
feeRate.intoFFI(),
&fee,
&txBytesPtr,
&txLen,
&error)
}

defer {
if error.message != nil {
error_message_free(error.message)
}
if let ptr = txBytesPtr {
transaction_bytes_free(ptr)
}
}

guard success, let ptr = txBytesPtr else {
throw KeyWalletError(ffiError: error)
}

// Copy the transaction data before freeing
let txData = Data(bytes: ptr, count: txLen)

return (txData, fee)
}

guard success, let ptr = txBytesPtr else {
throw KeyWalletError(ffiError: error)
}

// Copy the transaction data before freeing
let txData = Data(bytes: ptr, count: txLen)

return (txData, fee)
}

// MARK: - Block Height Management
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ struct SendTransactionView: View {
self.fee = fee
self.tx = tx
} catch {
self.error = error
self.fee = 0
self.tx = nil
}
Expand Down Expand Up @@ -169,4 +170,4 @@ struct SendTransactionView: View {
let decimalPart = dash % 100_000_000
return String(format: "~%llu.%08llu DASH", dashPart, decimalPart)
}
}
}
Loading