diff --git a/packages/rs-platform-wallet-ffi/src/dashpay.rs b/packages/rs-platform-wallet-ffi/src/dashpay.rs index 785ee47db52..166e84630af 100644 --- a/packages/rs-platform-wallet-ffi/src/dashpay.rs +++ b/packages/rs-platform-wallet-ffi/src/dashpay.rs @@ -543,6 +543,7 @@ pub unsafe extern "C" fn platform_wallet_send_dashpay_payment( memo: *const c_char, core_signer_handle: *mut MnemonicResolverHandle, out_txid: *mut [u8; 32], + out_fee_duffs: *mut u64, ) -> PlatformWalletFFIResult { check_ptr!(core_signer_handle); check_ptr!(out_txid); @@ -592,7 +593,13 @@ pub unsafe extern "C" fn platform_wallet_send_dashpay_payment( }) }); let result = unwrap_option_or_return!(option); - let (txid, _entry) = unwrap_result_or_return!(result); + let (txid, _entry, fee_duffs) = unwrap_result_or_return!(result); + // Exact network fee of the broadcast transaction (inputs − outputs), + // straight from the builder — nullable so callers that don't care + // can pass NULL. + if !out_fee_duffs.is_null() { + unsafe { *out_fee_duffs = fee_duffs }; + } use dashcore::hashes::Hash; let bytes = txid.to_raw_hash().to_byte_array(); unsafe { diff --git a/packages/rs-platform-wallet/src/wallet/identity/network/payments.rs b/packages/rs-platform-wallet/src/wallet/identity/network/payments.rs index 0d77468dae3..f542ab62e0e 100644 --- a/packages/rs-platform-wallet/src/wallet/identity/network/payments.rs +++ b/packages/rs-platform-wallet/src/wallet/identity/network/payments.rs @@ -552,6 +552,7 @@ impl DashPayView<'_, B> { ( dashcore::Txid, crate::wallet::identity::types::dashpay::payment::PaymentEntry, + u64, // network fee in duffs, from the broadcast transaction ), PlatformWalletError, > @@ -575,7 +576,7 @@ impl DashPayView<'_, B> { // re-acquires that (non-reentrant) lock internally. self.drain_pending_contact_crypto(provider).await; - let (payment_address, tx) = { + let (payment_address, tx, fee) = { let mut wm = self.wallet_manager.write().await; // Resolve the external account's xpub so we can derive addresses. @@ -664,14 +665,14 @@ impl DashPayView<'_, B> { // `impl TransactionSigner for S`) rather than the // resident `wallet`, so funding-input signatures are produced // from Keychain-derived keys without a resident seed. - let (tx, _fee) = builder + let (tx, fee) = builder .build_signed(signer, |addr| { managed_account.address_derivation_path(&addr) }) .await .map_err(|e| PlatformWalletError::TransactionBuild(e.to_string()))?; - (payment_address, tx) + (payment_address, tx, fee) }; // --- 3. Broadcast the transaction, releasing the build's UTXO @@ -726,7 +727,7 @@ impl DashPayView<'_, B> { })?; } - Ok((txid, entry)) + Ok((txid, entry, fee)) } } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ManagedPlatformWallet.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ManagedPlatformWallet.swift index f5dec496d55..972875a2bda 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ManagedPlatformWallet.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ManagedPlatformWallet.swift @@ -2101,7 +2101,8 @@ extension ManagedPlatformWallet { /// Send a Dash payment to an established DashPay contact. /// `amountDuffs` is in duffs (1 DASH = 100_000_000 duffs). - /// Returns the 32-byte transaction id. + /// Returns the 32-byte transaction id plus the exact network fee + /// (duffs) of the broadcast transaction, straight from the builder. /// /// Prerequisite: `register_external_contact_account` must have /// run for the `(fromIdentityId, toContactIdentityId)` pair on @@ -2113,7 +2114,7 @@ extension ManagedPlatformWallet { toContactIdentityId: Identifier, amountDuffs: UInt64, memo: String? = nil - ) async throws -> Data { + ) async throws -> (txid: Data, feeDuffs: UInt64) { let handle = self.handle let fromBytes: [UInt8] = fromIdentityId.withFFIBytes { ptr in Array(UnsafeBufferPointer(start: ptr, count: 32)) @@ -2128,7 +2129,8 @@ extension ManagedPlatformWallet { // derived, digest signed, buffers zeroed) — the seed never becomes // resident and no private key leaves Swift. let coreSigner = MnemonicResolver() - return try await Task.detached(priority: .userInitiated) { () -> Data in + return try await Task.detached(priority: .userInitiated) { () -> (txid: Data, feeDuffs: UInt64) in + var feeDuffs: UInt64 = 0 var txidTuple: ( UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, @@ -2153,7 +2155,8 @@ extension ManagedPlatformWallet { amountDuffs, memoPtr, coreSigner.handle, - &txidTuple + &txidTuple, + &feeDuffs ) } if let memoCopy { @@ -2165,7 +2168,8 @@ extension ManagedPlatformWallet { } } try result.check() - return Swift.withUnsafeBytes(of: &txidTuple) { Data($0) } + let txid = Swift.withUnsafeBytes(of: &txidTuple) { Data($0) } + return (txid: txid, feeDuffs: feeDuffs) }.value } } diff --git a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/DashPay/SendDashPayPaymentSheet.swift b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/DashPay/SendDashPayPaymentSheet.swift index 23d1af6e8e5..8b2b56f03b5 100644 --- a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/DashPay/SendDashPayPaymentSheet.swift +++ b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/DashPay/SendDashPayPaymentSheet.swift @@ -364,7 +364,7 @@ struct SendDashPayPaymentSheet: View { // useful to pass. The Rust-side // `PaymentEntry.memo` slot stays available for // future local-note wiring. - let txid = try await wallet.sendDashPayPayment( + let (txid, _) = try await wallet.sendDashPayPayment( fromIdentityId: senderIdentity.identityId, toContactIdentityId: contact.identityId, amountDuffs: duffs,