From 4aa999b8118725efb966e4bb2cb083435d4b28b8 Mon Sep 17 00:00:00 2001 From: Borja Castellano Date: Thu, 2 Apr 2026 14:25:28 -0700 Subject: [PATCH] bump rust-dashcore to commit dda1db7a7367bb7a6a48de7f4ed79da708266460 --- Cargo.lock | 20 +++---- Cargo.toml | 16 ++--- .../wallet_info_interface.rs | 6 +- .../SwiftDashSDK/Core/SPV/SPVClient.swift | 1 - .../Core/SPV/SPVEventHandler.swift | 25 ++++---- .../Core/Services/WalletService.swift | 4 +- .../Core/Wallet/CoreWalletManager.swift | 56 ++++++++++-------- .../KeyWallet/KeyWalletTypes.swift | 40 ------------- .../KeyWallet/ManagedAccount.swift | 17 ++---- .../KeyWallet/ManagedWallet.swift | 57 ------------------ .../Sources/SwiftDashSDK/KeyWallet/README.md | 13 ----- .../SwiftDashSDK/KeyWallet/Transaction.swift | 58 +------------------ .../KeyWallet/TransactionContext.swift | 45 ++++++++++++++ .../KeyWallet/TransactionRecord.swift | 28 +++++++++ .../KeyWallet/WalletManager.swift | 36 ------------ .../Core/Views/AccountDetailView.swift | 55 ++++++++++-------- .../Core/Views/TransactionDetailView.swift | 3 +- packages/swift-sdk/build_ios.sh | 17 +++--- 18 files changed, 184 insertions(+), 313 deletions(-) create mode 100644 packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/TransactionContext.swift create mode 100644 packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/TransactionRecord.swift diff --git a/Cargo.lock b/Cargo.lock index 33bcc76f18c..9dd457f7278 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1607,7 +1607,7 @@ dependencies = [ [[package]] name = "dash-spv" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=6638745c27119778d4c78959003955f00bad373c#6638745c27119778d4c78959003955f00bad373c" +source = "git+https://github.com/dashpay/rust-dashcore?rev=dda1db7a7367bb7a6a48de7f4ed79da708266460#dda1db7a7367bb7a6a48de7f4ed79da708266460" dependencies = [ "anyhow", "async-trait", @@ -1640,7 +1640,7 @@ dependencies = [ [[package]] name = "dash-spv-ffi" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=6638745c27119778d4c78959003955f00bad373c#6638745c27119778d4c78959003955f00bad373c" +source = "git+https://github.com/dashpay/rust-dashcore?rev=dda1db7a7367bb7a6a48de7f4ed79da708266460#dda1db7a7367bb7a6a48de7f4ed79da708266460" dependencies = [ "cbindgen 0.29.2", "clap", @@ -1665,7 +1665,7 @@ dependencies = [ [[package]] name = "dashcore" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=6638745c27119778d4c78959003955f00bad373c#6638745c27119778d4c78959003955f00bad373c" +source = "git+https://github.com/dashpay/rust-dashcore?rev=dda1db7a7367bb7a6a48de7f4ed79da708266460#dda1db7a7367bb7a6a48de7f4ed79da708266460" dependencies = [ "anyhow", "base64-compat", @@ -1690,12 +1690,12 @@ dependencies = [ [[package]] name = "dashcore-private" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=6638745c27119778d4c78959003955f00bad373c#6638745c27119778d4c78959003955f00bad373c" +source = "git+https://github.com/dashpay/rust-dashcore?rev=dda1db7a7367bb7a6a48de7f4ed79da708266460#dda1db7a7367bb7a6a48de7f4ed79da708266460" [[package]] name = "dashcore-rpc" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=6638745c27119778d4c78959003955f00bad373c#6638745c27119778d4c78959003955f00bad373c" +source = "git+https://github.com/dashpay/rust-dashcore?rev=dda1db7a7367bb7a6a48de7f4ed79da708266460#dda1db7a7367bb7a6a48de7f4ed79da708266460" dependencies = [ "dashcore-rpc-json", "hex", @@ -1708,7 +1708,7 @@ dependencies = [ [[package]] name = "dashcore-rpc-json" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=6638745c27119778d4c78959003955f00bad373c#6638745c27119778d4c78959003955f00bad373c" +source = "git+https://github.com/dashpay/rust-dashcore?rev=dda1db7a7367bb7a6a48de7f4ed79da708266460#dda1db7a7367bb7a6a48de7f4ed79da708266460" dependencies = [ "bincode", "dashcore", @@ -1723,7 +1723,7 @@ dependencies = [ [[package]] name = "dashcore_hashes" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=6638745c27119778d4c78959003955f00bad373c#6638745c27119778d4c78959003955f00bad373c" +source = "git+https://github.com/dashpay/rust-dashcore?rev=dda1db7a7367bb7a6a48de7f4ed79da708266460#dda1db7a7367bb7a6a48de7f4ed79da708266460" dependencies = [ "bincode", "dashcore-private", @@ -3832,7 +3832,7 @@ dependencies = [ [[package]] name = "key-wallet" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=6638745c27119778d4c78959003955f00bad373c#6638745c27119778d4c78959003955f00bad373c" +source = "git+https://github.com/dashpay/rust-dashcore?rev=dda1db7a7367bb7a6a48de7f4ed79da708266460#dda1db7a7367bb7a6a48de7f4ed79da708266460" dependencies = [ "aes", "async-trait", @@ -3860,7 +3860,7 @@ dependencies = [ [[package]] name = "key-wallet-ffi" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=6638745c27119778d4c78959003955f00bad373c#6638745c27119778d4c78959003955f00bad373c" +source = "git+https://github.com/dashpay/rust-dashcore?rev=dda1db7a7367bb7a6a48de7f4ed79da708266460#dda1db7a7367bb7a6a48de7f4ed79da708266460" dependencies = [ "cbindgen 0.29.2", "dashcore", @@ -3875,7 +3875,7 @@ dependencies = [ [[package]] name = "key-wallet-manager" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=6638745c27119778d4c78959003955f00bad373c#6638745c27119778d4c78959003955f00bad373c" +source = "git+https://github.com/dashpay/rust-dashcore?rev=dda1db7a7367bb7a6a48de7f4ed79da708266460#dda1db7a7367bb7a6a48de7f4ed79da708266460" dependencies = [ "async-trait", "bincode", diff --git a/Cargo.toml b/Cargo.toml index fe1346cea97..4ad2e2ca872 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,19 +43,19 @@ members = [ "packages/rs-platform-wallet", "packages/rs-platform-wallet-ffi", "packages/rs-platform-encryption", - "packages/wasm-sdk", + "packages/wasm-sdk", "packages/rs-unified-sdk-ffi", "packages/rs-scripts", ] [workspace.dependencies] -dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "6638745c27119778d4c78959003955f00bad373c" } -dash-spv = { git = "https://github.com/dashpay/rust-dashcore", rev = "6638745c27119778d4c78959003955f00bad373c" } -dash-spv-ffi = { git = "https://github.com/dashpay/rust-dashcore", rev = "6638745c27119778d4c78959003955f00bad373c" } -key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "6638745c27119778d4c78959003955f00bad373c" } -key-wallet-ffi = { git = "https://github.com/dashpay/rust-dashcore", rev = "6638745c27119778d4c78959003955f00bad373c" } -key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", rev = "6638745c27119778d4c78959003955f00bad373c" } -dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", rev = "6638745c27119778d4c78959003955f00bad373c" } +dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "dda1db7a7367bb7a6a48de7f4ed79da708266460" } +dash-spv = { git = "https://github.com/dashpay/rust-dashcore", rev = "dda1db7a7367bb7a6a48de7f4ed79da708266460" } +dash-spv-ffi = { git = "https://github.com/dashpay/rust-dashcore", rev = "dda1db7a7367bb7a6a48de7f4ed79da708266460" } +key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "dda1db7a7367bb7a6a48de7f4ed79da708266460" } +key-wallet-ffi = { git = "https://github.com/dashpay/rust-dashcore", rev = "dda1db7a7367bb7a6a48de7f4ed79da708266460" } +key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", rev = "dda1db7a7367bb7a6a48de7f4ed79da708266460" } +dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", rev = "dda1db7a7367bb7a6a48de7f4ed79da708266460" } # Optimize heavy crypto crates even in dev/test builds so that # Halo 2 proof generation and verification run at near-release speed. diff --git a/packages/rs-platform-wallet/src/platform_wallet_info/wallet_info_interface.rs b/packages/rs-platform-wallet/src/platform_wallet_info/wallet_info_interface.rs index 272b6b58e91..9770cf58fa9 100644 --- a/packages/rs-platform-wallet/src/platform_wallet_info/wallet_info_interface.rs +++ b/packages/rs-platform-wallet/src/platform_wallet_info/wallet_info_interface.rs @@ -1,6 +1,6 @@ use crate::platform_wallet_info::PlatformWalletInfo; use crate::IdentityManager; -use dashcore::{Address as DashAddress, Network, Transaction, Txid}; +use dashcore::{Address as DashAddress, InstantLock, Network, Transaction, Txid}; use dpp::prelude::CoreBlockHeight; use key_wallet::account::{ManagedAccountCollection, TransactionRecord}; use key_wallet::wallet::managed_wallet_info::wallet_info_interface::WalletInfoInterface; @@ -112,8 +112,8 @@ impl WalletInfoInterface for PlatformWalletInfo { self.wallet_info.update_synced_height(current_height) } - fn mark_instant_send_utxos(&mut self, txid: &Txid) -> bool { - self.wallet_info.mark_instant_send_utxos(txid) + fn mark_instant_send_utxos(&mut self, txid: &Txid, is_lock: &InstantLock) -> bool { + self.wallet_info.mark_instant_send_utxos(txid, is_lock) } fn monitor_revision(&self) -> u64 { diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/Core/SPV/SPVClient.swift b/packages/swift-sdk/Sources/SwiftDashSDK/Core/SPV/SPVClient.swift index 5f56aaa8dfd..a2691a40843 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/Core/SPV/SPVClient.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/Core/SPV/SPVClient.swift @@ -100,7 +100,6 @@ class SPVClient: @unchecked Sendable { dash_spv_ffi_config_set_mempool_tracking(configPtr, true) dash_spv_ffi_config_set_mempool_strategy(configPtr, FFIMempoolStrategy(rawValue: 0)) // FetchAll _ = dash_spv_ffi_config_set_fetch_mempool_transactions(configPtr, true) - _ = dash_spv_ffi_config_set_persist_mempool(configPtr, true) // Set user agent to include SwiftDashSDK version from the framework bundle do { diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/Core/SPV/SPVEventHandler.swift b/packages/swift-sdk/Sources/SwiftDashSDK/Core/SPV/SPVEventHandler.swift index 27d103634f0..13e4e86df3e 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/Core/SPV/SPVEventHandler.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/Core/SPV/SPVEventHandler.swift @@ -471,9 +471,7 @@ protocol SPVWalletEventsHandler: AnyObject { func onTransactionReceived( _ walletId: String, _ accountIndex: UInt32, - _ txid: Data, - _ amount: Int64, - _ addresses: [String] + _ record: NotOwnedTransactionRecord ) func onBalanceUpdated( @@ -500,11 +498,8 @@ extension SPVWalletEventsHandler { private func onSpvTransactionReceivedCallbackC( walletIdPtr: UnsafePointer?, - status: FFITransactionContext, accountIndex: UInt32, - txidPtr: UnsafePointer?, - amount: Int64, - addressesPtr: UnsafePointer?, + recordPtr: UnsafePointer?, userData: UnsafeMutableRawPointer? ) { let handler = rawPtrIntoSpvWalletEventsHandler(userData) @@ -514,16 +509,18 @@ private func onSpvTransactionReceivedCallbackC( return } + guard let recordPtr else { + assertionFailure("TransactionReceived record pointer is nil") + return + } + let walletId = String(cString: walletIdPtr) - let txid = bytePtrIntoData(txidPtr, 32) - let addresses = addressesPtrIntoString(addressesPtr) + let record = NotOwnedTransactionRecord(handle: recordPtr) handler.onTransactionReceived( walletId, accountIndex, - txid, - amount, - addresses + record ) } @@ -570,9 +567,7 @@ private final class DummySPVWalletEventsHandler: SPVWalletEventsHandler { func onTransactionReceived( _: String, _: UInt32, - _: Data, - _: Int64, - _: [String] + _: NotOwnedTransactionRecord, ) {} func onBalanceUpdated( diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/Core/Services/WalletService.swift b/packages/swift-sdk/Sources/SwiftDashSDK/Core/Services/WalletService.swift index aea6a23924d..f2f2d179047 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/Core/Services/WalletService.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/Core/Services/WalletService.swift @@ -372,9 +372,7 @@ public class WalletService: ObservableObject { func onTransactionReceived( _ walletId: String, _ accountIndex: UInt32, - _ txid: Data, - _ amount: Int64, - _ addresses: [String] + _ record: NotOwnedTransactionRecord ) {} func onBalanceUpdated( diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/CoreWalletManager.swift b/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/CoreWalletManager.swift index a51ee7dab6c..c99e70a5d64 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/CoreWalletManager.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/CoreWalletManager.swift @@ -149,16 +149,16 @@ public class CoreWalletManager: ObservableObject { /// - Parameters: /// - wallet: The wallet to fund from. /// - accountIndex: BIP44 account index (typically 0). - /// - fundingType: The type of asset lock funding account for key derivation. - /// - identityIndex: Identity index for key derivation (0 for new). + /// - fundingTypes: Array of funding account types for key derivation, one per credit output. + /// - identityIndices: Array of identity indices for key derivation, one per credit output. /// - creditOutputs: Array of (scriptPubKey, amount) pairs for platform credit outputs. /// - feePerKb: Fee rate in duffs per kilobyte (0 for default). /// - Returns: `AssetLockTransactionResult` with tx bytes, output index, private key, and fee. public func buildAssetLockTransaction( for wallet: HDWallet, accountIndex: UInt32 = 0, - fundingType: AssetLockFundingType = .assetLockAddressTopUp, - identityIndex: UInt32 = 0, + fundingTypes: [AssetLockFundingType] = [.assetLockAddressTopUp], + identityIndices: [UInt32] = [0], creditOutputs: [(scriptPubKey: Data, amount: UInt64)], feePerKb: UInt64 = 1000 ) throws -> AssetLockTransactionResult { @@ -170,11 +170,16 @@ public class CoreWalletManager: ObservableObject { guard count > 0 else { throw WalletError.walletError("At least one credit output required") } + guard fundingTypes.count == count, identityIndices.count == count else { + throw WalletError.walletError("fundingTypes and identityIndices must have the same length as creditOutputs") + } // Concatenate all scripts into a single contiguous buffer // and build an array of pointers into it var scriptLens: [Int] = creditOutputs.map { $0.scriptPubKey.count } var amounts: [UInt64] = creditOutputs.map { $0.amount } + var fundingTypesRaw: [FFIAssetLockFundingType] = fundingTypes.map { FFIAssetLockFundingType(rawValue: $0.rawValue) } + var identityIndicesRaw: [UInt32] = identityIndices var concatenatedScripts = Data() for output in creditOutputs { concatenatedScripts.append(output.scriptPubKey) @@ -183,7 +188,7 @@ public class CoreWalletManager: ObservableObject { var feeOut: UInt64 = 0 var txBytesOut: UnsafeMutablePointer? = nil var txLenOut: Int = 0 - var outputIndexOut: UInt32 = 0 + let outputIndexOut: UInt32 = 0 var privateKeyOut: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, @@ -207,28 +212,31 @@ public class CoreWalletManager: ObservableObject { return scriptPtrs.withUnsafeMutableBufferPointer { scriptPtrsBuffer in scriptLens.withUnsafeMutableBufferPointer { scriptLensBuffer in amounts.withUnsafeMutableBufferPointer { amountsBuffer in - wallet_build_and_sign_asset_lock_transaction( - sdkWalletManager.handle, - sdkWallet.handle, - accountIndex, - fundingType.rawValue, - identityIndex, - scriptPtrsBuffer.baseAddress, - scriptLensBuffer.baseAddress, - amountsBuffer.baseAddress, - count, - feePerKb, - &feeOut, - &txBytesOut, - &txLenOut, - &outputIndexOut, - &privateKeyOut, - &ffiError - ) + fundingTypesRaw.withUnsafeMutableBufferPointer { fundingTypesBuffer in + identityIndicesRaw.withUnsafeMutableBufferPointer { identityIndicesBuffer in + wallet_build_and_sign_asset_lock_transaction( + sdkWalletManager.handle, + sdkWallet.handle, + accountIndex, + fundingTypesBuffer.baseAddress, + identityIndicesBuffer.baseAddress, + scriptPtrsBuffer.baseAddress, + scriptLensBuffer.baseAddress, + amountsBuffer.baseAddress, + count, + feePerKb, + &feeOut, + &txBytesOut, + &txLenOut, + &privateKeyOut, + &ffiError + ) + } + } + } } } } - } guard success else { let msg = ffiError.message != nil ? String(cString: ffiError.message!) : "Unknown error" diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift index a1da7ca8528..c6daff80fcb 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift @@ -75,23 +75,6 @@ public enum AddressPoolType: UInt32 { } } -// MARK: - Transaction Context - -/// Transaction context for checking -public enum TransactionContext: UInt32 { - case mempool = 0 - case inBlock = 1 - case inChainLockedBlock = 2 - - var ffiValue: FFITransactionContext { - FFITransactionContext(rawValue: self.rawValue) - } - - init(ffiContext: FFITransactionContext) { - self = TransactionContext(rawValue: ffiContext.rawValue) ?? .mempool - } -} - // MARK: - Mnemonic Language /// Language for mnemonic generation @@ -254,29 +237,6 @@ public struct TransactionCheckResult { } } -/// Transaction context details -public struct TransactionContextDetails { - public let context: TransactionContext - public let height: UInt32 - public let blockHash: Data? - public let timestamp: UInt32 - - func toFFI() -> FFITransactionContextDetails { - var details = FFITransactionContextDetails() - details.context_type = context.ffiValue - details.height = height - details.timestamp = timestamp - - if let hash = blockHash { - hash.withUnsafeBytes { bytes in - details.block_hash = bytes.bindMemory(to: UInt8.self).baseAddress - } - } - - return details - } -} - /// UTXO information public struct UTXO: Identifiable, Equatable, Sendable { public let txid: Data diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedAccount.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedAccount.swift index da24764a13c..eb3883a1c0e 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedAccount.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedAccount.swift @@ -89,8 +89,8 @@ public class ManagedAccount { // Convert block hash if present let blockHashHex: String? - if ffiTx.height > 0 { - blockHashHex = withUnsafeBytes(of: ffiTx.block_hash) { buffer in + if ffiTx.context.block_info.height > 0 { + blockHashHex = withUnsafeBytes(of: ffiTx.context.block_info.block_hash) { buffer in buffer.map { String(format: "%02x", $0) }.joined() } } else { @@ -100,11 +100,10 @@ public class ManagedAccount { let transaction = WalletTransaction( txid: txidHex, netAmount: ffiTx.net_amount, - height: ffiTx.height, + height: ffiTx.context.block_info.height, blockHash: blockHashHex, - timestamp: ffiTx.timestamp, + timestamp: ffiTx.context.block_info.timestamp, fee: ffiTx.fee > 0 ? ffiTx.fee : nil, - isOurs: ffiTx.is_ours ) transactions.append(transaction) @@ -170,20 +169,17 @@ public struct WalletTransaction: Identifiable { /// Block hash if confirmed (hex string) public let blockHash: String? /// Unix timestamp - public let timestamp: UInt64 + public let timestamp: UInt32 /// Fee if known public let fee: UInt64? - /// Whether this is our transaction - public let isOurs: Bool public init( txid: String, netAmount: Int64, height: UInt32, blockHash: String?, - timestamp: UInt64, + timestamp: UInt32, fee: UInt64?, - isOurs: Bool ) { self.txid = txid self.netAmount = netAmount @@ -191,7 +187,6 @@ public struct WalletTransaction: Identifiable { self.blockHash = blockHash self.timestamp = timestamp self.fee = fee - self.isOurs = isOurs } /// Transaction date diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift index b4454aebcab..0dfeda0de5e 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift @@ -288,63 +288,6 @@ public class ManagedWallet { } } - // MARK: - Transaction Checking - - /// Check if a transaction belongs to the wallet - /// - Parameters: - /// - wallet: The wallet to check against - /// - transactionData: The transaction bytes - /// - context: The transaction context - /// - blockHeight: The block height (0 for mempool) - /// - blockHash: The block hash (nil for mempool) - /// - timestamp: The timestamp - /// - updateState: Whether to update wallet state if transaction is relevant - /// - Returns: Transaction check result - public func checkTransaction(wallet: Wallet, transactionData: Data, - context: TransactionContext = .mempool, - blockHeight: UInt32 = 0, - blockHash: Data? = nil, - timestamp: UInt32 = 0, - updateState: Bool = true) throws -> TransactionCheckResult { - var error = FFIError() - var result = FFITransactionCheckResult() - - let success = transactionData.withUnsafeBytes { txBytes in - let txPtr = txBytes.bindMemory(to: UInt8.self).baseAddress - - if let hash = blockHash { - return hash.withUnsafeBytes { hashBytes in - let hashPtr = hashBytes.bindMemory(to: UInt8.self).baseAddress - - return managed_wallet_check_transaction( - handle, wallet.ffiHandle, - txPtr, transactionData.count, - context.ffiValue, blockHeight, hashPtr, - UInt64(timestamp), updateState, &result, &error) - } - } else { - return managed_wallet_check_transaction( - handle, wallet.ffiHandle, - txPtr, transactionData.count, - context.ffiValue, blockHeight, nil, - UInt64(timestamp), updateState, &result, &error) - } - } - - defer { - if error.message != nil { - error_message_free(error.message) - } - transaction_check_result_free(&result) - } - - guard success else { - throw KeyWalletError(ffiError: error) - } - - return TransactionCheckResult(ffiResult: result) - } - // MARK: - Balance and UTXOs /// Get the wallet balance from managed wallet info diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/README.md b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/README.md index 3b063782799..1042cc97197 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/README.md +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/README.md @@ -165,19 +165,6 @@ let address = try manager.getReceiveAddress( network: .mainnet, accountIndex: 0 ) - -// Process transaction across all wallets -let isRelevant = try manager.processTransaction( - txData, - network: .mainnet, - contextDetails: TransactionContextDetails( - context: .inBlock, - height: 1000000, - blockHash: blockHashData, - timestamp: UInt32(Date().timeIntervalSince1970) - ), - updateStateIfFound: true -) ``` ### Managed Accounts (New API) diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Transaction.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Transaction.swift index e7d8f7b3875..21f5c0f9fcf 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Transaction.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Transaction.swift @@ -23,62 +23,6 @@ public class Transaction { } } - /// Check if a transaction belongs to a wallet - /// - Parameters: - /// - wallet: The wallet to check against - /// - transactionData: The transaction bytes - /// - context: The transaction context - /// - blockHeight: The block height (0 for mempool) - /// - blockHash: The block hash (nil for mempool) - /// - timestamp: The timestamp - /// - updateState: Whether to update wallet state if transaction is relevant - /// - Returns: Transaction check result - public static func check(wallet: Wallet, - transactionData: Data, - context: TransactionContext = .mempool, - blockHeight: UInt32 = 0, - blockHash: Data? = nil, - timestamp: UInt64 = 0, - updateState: Bool = true) throws -> TransactionCheckResult { - var error = FFIError() - var result = FFITransactionCheckResult() - - let success = transactionData.withUnsafeBytes { txBytes in - let txPtr = txBytes.bindMemory(to: UInt8.self).baseAddress - - if let hash = blockHash { - return hash.withUnsafeBytes { hashBytes in - let hashPtr = hashBytes.bindMemory(to: UInt8.self).baseAddress - - return wallet_check_transaction( - wallet.ffiHandle, - txPtr, transactionData.count, - context.ffiValue, blockHeight, hashPtr, - timestamp, updateState, &result, &error) - } - } else { - return wallet_check_transaction( - wallet.ffiHandle, - txPtr, transactionData.count, - context.ffiValue, blockHeight, nil, - timestamp, updateState, &result, &error) - } - } - - defer { - if error.message != nil { - error_message_free(error.message) - } - transaction_check_result_free(&result) - } - - guard success else { - throw KeyWalletError(ffiError: error) - } - - return TransactionCheckResult(ffiResult: result) - } - /// Classify a transaction for routing /// - Parameter transactionData: The transaction bytes /// - Returns: A string describing the transaction type @@ -105,4 +49,4 @@ public class Transaction { return classification } -} +} \ No newline at end of file diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/TransactionContext.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/TransactionContext.swift new file mode 100644 index 00000000000..b5bfbcb01c2 --- /dev/null +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/TransactionContext.swift @@ -0,0 +1,45 @@ +import Foundation +import DashSDKFFI + +public enum TransactionContextType: UInt32 { + case mempool = 0 + case instantSend = 1 + case inBlock = 2 + case inChainLockedBlock = 3 + + var ffiValue: FFITransactionContextType { + FFITransactionContextType(rawValue: self.rawValue) + } + + init(ffiContext: FFITransactionContextType) { + self = TransactionContextType(rawValue: ffiContext.rawValue) ?? .mempool + } +} + +public class BlockInfo { + let height: UInt32 + let block_hash: Data + let timestamp: UInt32 + + init(ffi: FFIBlockInfo) { + self.height = ffi.height + self.block_hash = withUnsafeBytes(of: ffi.block_hash) { Data($0) } + self.timestamp = ffi.timestamp + } +} + +public class TransactionContext { + let context_type: TransactionContextType + let block_info: BlockInfo + let islock_data: Data + + init(ffi: FFITransactionContext) { + self.context_type = TransactionContextType(ffiContext: ffi.context_type) + self.block_info = BlockInfo(ffi: ffi.block_info) + if let islockPtr = ffi.islock_data, ffi.islock_len > 0 { + self.islock_data = Data(bytes: islockPtr, count: ffi.islock_len) + } else { + self.islock_data = Data() + } + } +} \ No newline at end of file diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/TransactionRecord.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/TransactionRecord.swift new file mode 100644 index 00000000000..8ca9513c76d --- /dev/null +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/TransactionRecord.swift @@ -0,0 +1,28 @@ +import Foundation +import DashSDKFFI + +// This struct is not mapping all fields of FFITransactionRecord +// for the lack of wrappers +public struct NotOwnedTransactionRecord { + let txid: Data + let net_amount: Int64 + let context: TransactionContext + let fee: UInt64 + let tx_data: Data + let label: String? + + public init(handle: UnsafePointer) { + let p = handle.pointee + + self.txid = withUnsafeBytes(of: p.txid) { Data($0) } + self.net_amount = p.net_amount + self.fee = p.fee + self.tx_data = p.tx_data != nil + ? Data(bytes: p.tx_data, count: p.tx_len) + : Data() + self.label = p.label != nil + ? String(cString: p.label) + : nil + self.context = TransactionContext(ffi: p.context) + } +} diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift index a1407da6040..40f186ed22e 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift @@ -351,42 +351,6 @@ public class WalletManager { return (confirmed: confirmed, unconfirmed: unconfirmed) } - // MARK: - Transaction Processing - - /// Process a transaction through all wallets - /// - Parameters: - /// - transactionData: The transaction bytes - /// - contextDetails: Transaction context details - /// - updateStateIfFound: Whether to update wallet state if transaction is relevant - /// - Returns: True if transaction was relevant to at least one wallet - @discardableResult - public func processTransaction(_ transactionData: Data, - contextDetails: TransactionContextDetails, - updateStateIfFound: Bool = true) throws -> Bool { - var error = FFIError() - var ffiContext = contextDetails.toFFI() - - let success = transactionData.withUnsafeBytes { txBytes in - let txPtr = txBytes.bindMemory(to: UInt8.self).baseAddress - return wallet_manager_process_transaction( - handle, txPtr, transactionData.count, - &ffiContext, - updateStateIfFound, &error) - } - - defer { - if error.message != nil { - error_message_free(error.message) - } - } - - guard success else { - throw KeyWalletError(ffiError: error) - } - - return success - } - /// Build a signed transaction /// - Parameters: /// - accIndex: The account index to use diff --git a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/AccountDetailView.swift b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/AccountDetailView.swift index 5bc7e2a3b37..fe2faf236de 100644 --- a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/AccountDetailView.swift +++ b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/AccountDetailView.swift @@ -487,7 +487,7 @@ struct AccountDetailView: View { private var hasInternalExternalAddresses: Bool { guard let info = detailInfo else { return false } switch info.accountType { - case STANDARD_BIP44, STANDARD_BIP32: + case FFI_ACCOUNT_TYPE_STANDARD_BIP44, FFI_ACCOUNT_TYPE_STANDARD_BIP32: return true default: return false @@ -497,11 +497,17 @@ struct AccountDetailView: View { private var shouldShowPrivateKeyButton: Bool { guard let info = detailInfo else { return false } switch info.accountType { - case STANDARD_BIP44, STANDARD_BIP32, COIN_JOIN: + case FFI_ACCOUNT_TYPE_STANDARD_BIP44, FFI_ACCOUNT_TYPE_STANDARD_BIP32, FFI_ACCOUNT_TYPE_COIN_JOIN: // These account types use HD derivation, don't show individual private keys return false - case IDENTITY_REGISTRATION, IDENTITY_TOP_UP, IDENTITY_TOP_UP_NOT_BOUND_TO_IDENTITY, IDENTITY_INVITATION, - PROVIDER_VOTING_KEYS, PROVIDER_OWNER_KEYS, PROVIDER_OPERATOR_KEYS, PROVIDER_PLATFORM_KEYS: + case FFI_ACCOUNT_TYPE_IDENTITY_REGISTRATION, + FFI_ACCOUNT_TYPE_IDENTITY_TOP_UP, + FFI_ACCOUNT_TYPE_IDENTITY_TOP_UP_NOT_BOUND_TO_IDENTITY, + FFI_ACCOUNT_TYPE_IDENTITY_INVITATION, + FFI_ACCOUNT_TYPE_PROVIDER_VOTING_KEYS, + FFI_ACCOUNT_TYPE_PROVIDER_OWNER_KEYS, + FFI_ACCOUNT_TYPE_PROVIDER_OPERATOR_KEYS, + FFI_ACCOUNT_TYPE_PROVIDER_PLATFORM_KEYS: // These special accounts have single keys that can be shown return true default: @@ -512,27 +518,27 @@ struct AccountDetailView: View { private var accountTypeName: String { guard let info = detailInfo else { return "Unknown Account" } switch info.accountType { - case STANDARD_BIP44: + case FFI_ACCOUNT_TYPE_STANDARD_BIP44: return account.index == 0 ? "Main Account" : "BIP44 Account" - case STANDARD_BIP32: + case FFI_ACCOUNT_TYPE_STANDARD_BIP32: return "BIP32 Account" - case COIN_JOIN: + case FFI_ACCOUNT_TYPE_COIN_JOIN: return "CoinJoin Account" - case IDENTITY_REGISTRATION: + case FFI_ACCOUNT_TYPE_IDENTITY_REGISTRATION: return "Identity Registration" - case IDENTITY_TOP_UP: + case FFI_ACCOUNT_TYPE_IDENTITY_TOP_UP: return "Identity Top-up" - case IDENTITY_TOP_UP_NOT_BOUND_TO_IDENTITY: + case FFI_ACCOUNT_TYPE_IDENTITY_TOP_UP_NOT_BOUND_TO_IDENTITY: return "Identity Top-up (Not Bound)" - case IDENTITY_INVITATION: + case FFI_ACCOUNT_TYPE_IDENTITY_INVITATION: return "Identity Invitation" - case PROVIDER_VOTING_KEYS: + case FFI_ACCOUNT_TYPE_PROVIDER_VOTING_KEYS: return "Provider Voting Keys" - case PROVIDER_OWNER_KEYS: + case FFI_ACCOUNT_TYPE_PROVIDER_OWNER_KEYS: return "Provider Owner Keys" - case PROVIDER_OPERATOR_KEYS: + case FFI_ACCOUNT_TYPE_PROVIDER_OPERATOR_KEYS: return "Provider Operator Keys (BLS)" - case PROVIDER_PLATFORM_KEYS: + case FFI_ACCOUNT_TYPE_PROVIDER_PLATFORM_KEYS: return "Provider Platform Keys (EdDSA)" default: return "Special Account" @@ -542,21 +548,24 @@ struct AccountDetailView: View { private var accountTypeColor: Color { guard let info = detailInfo else { return .gray } switch info.accountType { - case STANDARD_BIP44: + case FFI_ACCOUNT_TYPE_STANDARD_BIP44: return account.index == 0 ? .green : .blue - case STANDARD_BIP32: + case FFI_ACCOUNT_TYPE_STANDARD_BIP32: return .teal - case COIN_JOIN: + case FFI_ACCOUNT_TYPE_COIN_JOIN: return .orange - case IDENTITY_REGISTRATION, IDENTITY_TOP_UP, IDENTITY_TOP_UP_NOT_BOUND_TO_IDENTITY, IDENTITY_INVITATION: + case FFI_ACCOUNT_TYPE_IDENTITY_REGISTRATION, + FFI_ACCOUNT_TYPE_IDENTITY_TOP_UP, + FFI_ACCOUNT_TYPE_IDENTITY_TOP_UP_NOT_BOUND_TO_IDENTITY, + FFI_ACCOUNT_TYPE_IDENTITY_INVITATION: return .purple - case PROVIDER_VOTING_KEYS: + case FFI_ACCOUNT_TYPE_PROVIDER_VOTING_KEYS: return .red - case PROVIDER_OWNER_KEYS: + case FFI_ACCOUNT_TYPE_PROVIDER_OWNER_KEYS: return .pink - case PROVIDER_OPERATOR_KEYS: + case FFI_ACCOUNT_TYPE_PROVIDER_OPERATOR_KEYS: return .indigo - case PROVIDER_PLATFORM_KEYS: + case FFI_ACCOUNT_TYPE_PROVIDER_PLATFORM_KEYS: return .cyan default: return .gray diff --git a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/TransactionDetailView.swift b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/TransactionDetailView.swift index 92be902d335..1264eaea0d9 100644 --- a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/TransactionDetailView.swift +++ b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/TransactionDetailView.swift @@ -229,9 +229,8 @@ struct TransactionDetailRow: View { netAmount: 50000000, height: 12345, blockHash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", - timestamp: UInt64(Date().timeIntervalSince1970), + timestamp: UInt32(Date().timeIntervalSince1970), fee: 226, - isOurs: false ) ) } diff --git a/packages/swift-sdk/build_ios.sh b/packages/swift-sdk/build_ios.sh index 0449969e477..bd482c8a723 100755 --- a/packages/swift-sdk/build_ios.sh +++ b/packages/swift-sdk/build_ios.sh @@ -156,16 +156,6 @@ module DashSDKFFI { EOF log_info " → module.modulemap + umbrella header injected in $HEADERS_DIR" - # TODO(build_ios): Quick fix — upstream headers from rust-dashcore emit FFIAssetLockFundingType - # with bare enumerator names (IDENTITY_REGISTRATION, IDENTITY_TOP_UP, etc.) that collide with - # FFIAccountType, which is invalid C (enum constants share the global namespace). - # The proper fix belongs in rust-dashcore's cbindgen config (prefix or namespace the variants). - # Until that fix lands, we strip the enum typedef and replace the type with uint32_t. - for h in "$HEADERS_DIR"/*/*.h; do - perl -i -0777 -pe 's{/\*\*?\s*\n\s*The type of funding account.*?\n\s*\*/\s*\ntypedef enum \{.*?\} FFIAssetLockFundingType;\n}{}s' "$h" - sed -i '' 's/FFIAssetLockFundingType/uint32_t/g' "$h" - done - # Give opaque struct forward declarations a body so Swift can use UnsafeMutablePointer. # Skip types that already have a full definition in another header to avoid redefinition. local defined @@ -244,6 +234,10 @@ SWIFT_SCHEME="SwiftExampleApp" SWIFT_DESTINATION="generic/platform=iOS Simulator" EXCLUDED_ARCHS="x86_64" +OTHER_SWIFT_FLAGS="-warnings-as-errors" +SWIFT_TREAT_WARNINGS_AS_ERRORS=YES +SWIFT_SUPPRESS_WARNINGS=NO + if command -v xcodebuild >/dev/null 2>&1; then set +e xcodebuild -project "$SWIFT_PROJECT" \ @@ -251,6 +245,9 @@ if command -v xcodebuild >/dev/null 2>&1; then -sdk iphonesimulator \ -destination "$SWIFT_DESTINATION" \ EXCLUDED_ARCHS="$EXCLUDED_ARCHS" \ + OTHER_SWIFT_FLAGS="$OTHER_SWIFT_FLAGS" \ + SWIFT_TREAT_WARNINGS_AS_ERRORS=$SWIFT_TREAT_WARNINGS_AS_ERRORS \ + SWIFT_SUPPRESS_WARNINGS=$SWIFT_SUPPRESS_WARNINGS \ build XC_STATUS=$? set -e