diff --git a/CHANGELOG.md b/CHANGELOG.md index 72f9674ff..941f689f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,12 @@ -# 0.7.0-rc.31 (Synonym Fork) +# 0.7.0-rc.32 (Synonym Fork) ## Bug Fixes +- Fixed cumulative change-address derivation index leak during fee estimation and dry-run + transaction builds. BDK's `TxBuilder::finish()` advances the internal (change) keychain index + each time it's called; repeated fee estimations would burn through change addresses without + broadcasting any transaction. All dry-run and error-after-`finish()` paths now cancel the PSBT + to unmark the change address for reuse. - Bumped `FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS` and `TX_BROADCAST_TIMEOUT_SECS` from 5s to 15s. The 5s node-level timeout fires before Electrum can complete a request (10s timeout), causing `FeerateEstimationUpdateTimeout` on node start. diff --git a/Cargo.toml b/Cargo.toml index 50445bd04..287898216 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ exclude = ["bindings/uniffi-bindgen"] [package] name = "ldk-node" -version = "0.7.0-rc.31" +version = "0.7.0-rc.32" authors = ["Elias Rohrer "] homepage = "https://lightningdevkit.org/" license = "MIT OR Apache-2.0" diff --git a/Package.swift b/Package.swift index a8f2a3dcd..8cd6e0cfc 100644 --- a/Package.swift +++ b/Package.swift @@ -3,8 +3,8 @@ import PackageDescription -let tag = "v0.7.0-rc.31" -let checksum = "aa189d355dc048664652832747f9236eddd97cdf78eb1659d7def06eae72b9b4" +let tag = "v0.7.0-rc.32" +let checksum = "5a9ac761833dd2aad0a88da7da8887923fc6ac8b33a14035b95c7d3a9d0d2b3c" let url = "https://github.com/synonymdev/ldk-node/releases/download/\(tag)/LDKNodeFFI.xcframework.zip" let package = Package( diff --git a/bindings/kotlin/ldk-node-android/gradle.properties b/bindings/kotlin/ldk-node-android/gradle.properties index a16d6b110..63a32f40e 100644 --- a/bindings/kotlin/ldk-node-android/gradle.properties +++ b/bindings/kotlin/ldk-node-android/gradle.properties @@ -3,4 +3,4 @@ android.useAndroidX=true android.enableJetifier=true kotlin.code.style=official group=com.synonym -version=0.7.0-rc.31 +version=0.7.0-rc.32 diff --git a/bindings/kotlin/ldk-node-jvm/gradle.properties b/bindings/kotlin/ldk-node-jvm/gradle.properties index 01ee19bb5..d4c9d344c 100644 --- a/bindings/kotlin/ldk-node-jvm/gradle.properties +++ b/bindings/kotlin/ldk-node-jvm/gradle.properties @@ -1,4 +1,4 @@ org.gradle.jvmargs=-Xmx1536m kotlin.code.style=official group=com.synonym -version=0.7.0-rc.31 +version=0.7.0-rc.32 diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib index 28a3c5876..190d3dd6a 100644 Binary files a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib and b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib differ diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib index ba108bd44..a46cd9a18 100644 Binary files a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib and b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib differ diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index 76d69df9f..b71180742 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "ldk_node" -version = "0.7.0-rc.31" +version = "0.7.0-rc.32" authors = [ { name="Elias Rohrer", email="dev@tnull.de" }, ] diff --git a/bindings/swift/Sources/LDKNode/LDKNode.swift b/bindings/swift/Sources/LDKNode/LDKNode.swift index f679967d9..ef5cbbca6 100644 --- a/bindings/swift/Sources/LDKNode/LDKNode.swift +++ b/bindings/swift/Sources/LDKNode/LDKNode.swift @@ -13,7 +13,7 @@ import Foundation #endif private extension RustBuffer { - /// Allocate a new buffer, copying the contents of a `UInt8` array. + // Allocate a new buffer, copying the contents of a `UInt8` array. init(bytes: [UInt8]) { let rbuf = bytes.withUnsafeBufferPointer { ptr in RustBuffer.from(ptr) @@ -29,8 +29,8 @@ private extension RustBuffer { try! rustCall { ffi_ldk_node_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } } - /// Frees the buffer in place. - /// The buffer must not be used after this is called. + // Frees the buffer in place. + // The buffer must not be used after this is called. func deallocate() { try! rustCall { ffi_ldk_node_rustbuffer_free(self, $0) } } @@ -77,9 +77,9 @@ private func createReader(data: Data) -> (data: Data, offset: Data.Index) { (data: data, offset: 0) } -/// Reads an integer at the current offset, in big-endian order, and advances -/// the offset on success. Throws if reading the integer would move the -/// offset past the end of the buffer. +// Reads an integer at the current offset, in big-endian order, and advances +// the offset on success. Throws if reading the integer would move the +// offset past the end of the buffer. private func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { let range = reader.offset ..< reader.offset + MemoryLayout.size guard reader.data.count >= range.upperBound else { @@ -96,8 +96,8 @@ private func readInt(_ reader: inout (data: Data, offset: return value.bigEndian } -/// Reads an arbitrary number of bytes, to be used to read -/// raw bytes, this is useful when lifting strings +// Reads an arbitrary number of bytes, to be used to read +// raw bytes, this is useful when lifting strings private func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> [UInt8] { let range = reader.offset ..< (reader.offset + count) guard reader.data.count >= range.upperBound else { @@ -111,17 +111,17 @@ private func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: return value } -/// Reads a float at the current offset. +// Reads a float at the current offset. private func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { return try Float(bitPattern: readInt(&reader)) } -/// Reads a float at the current offset. +// Reads a float at the current offset. private func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { return try Double(bitPattern: readInt(&reader)) } -/// Indicates if the offset has reached the end of the buffer. +// Indicates if the offset has reached the end of the buffer. private func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { return reader.offset < reader.data.count } @@ -134,14 +134,14 @@ private func createWriter() -> [UInt8] { return [] } -private func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S.Element == UInt8 { +private func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { writer.append(contentsOf: byteArr) } -/// Writes an integer in big-endian order. -/// -/// Warning: make sure what you are trying to write -/// is in the correct type! +// Writes an integer in big-endian order. +// +// Warning: make sure what you are trying to write +// is in the correct type! private func writeInt(_ writer: inout [UInt8], _ value: T) { var value = value.bigEndian withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } @@ -155,8 +155,8 @@ private func writeDouble(_ writer: inout [UInt8], _ value: Double) { writeInt(&writer, value.bitPattern) } -/// Protocol for types that transfer other types across the FFI. This is -/// analogous to the Rust trait of the same name. +// Protocol for types that transfer other types across the FFI. This is +// analogous to the Rust trait of the same name. private protocol FfiConverter { associatedtype FfiType associatedtype SwiftType @@ -167,7 +167,7 @@ private protocol FfiConverter { static func write(_ value: SwiftType, into buf: inout [UInt8]) } -/// Types conforming to `Primitive` pass themselves directly over the FFI. +// Types conforming to `Primitive` pass themselves directly over the FFI. private protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType {} extension FfiConverterPrimitive { @@ -186,8 +186,8 @@ extension FfiConverterPrimitive { } } -/// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. -/// Used for complex types where it's hard to write a custom lift/lower. +// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. +// Used for complex types where it's hard to write a custom lift/lower. private protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} extension FfiConverterRustBuffer { @@ -214,8 +214,8 @@ extension FfiConverterRustBuffer { } } -/// An error type for FFI errors. These errors occur at the UniFFI level, not -/// the library level. +// An error type for FFI errors. These errors occur at the UniFFI level, not +// the library level. private enum UniffiInternalError: LocalizedError { case bufferOverflow case incompleteData @@ -601,7 +601,7 @@ open class Bolt11Invoice: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -862,7 +862,7 @@ open class Bolt11Payment: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -906,13 +906,12 @@ open class Bolt11Payment: try! rustCall { uniffi_ldk_node_fn_free_bolt11payment(pointer, $0) } } - open func claimForHash(paymentHash: PaymentHash, claimableAmountMsat: UInt64, preimage: PaymentPreimage) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_claim_for_hash(self.uniffiClonePointer(), - FfiConverterTypePaymentHash.lower(paymentHash), - FfiConverterUInt64.lower(claimableAmountMsat), - FfiConverterTypePaymentPreimage.lower(preimage), $0) - } + open func claimForHash(paymentHash: PaymentHash, claimableAmountMsat: UInt64, preimage: PaymentPreimage) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_claim_for_hash(self.uniffiClonePointer(), + FfiConverterTypePaymentHash.lower(paymentHash), + FfiConverterUInt64.lower(claimableAmountMsat), + FfiConverterTypePaymentPreimage.lower(preimage), $0) + } } open func estimateRoutingFees(invoice: Bolt11Invoice) throws -> UInt64 { @@ -930,11 +929,10 @@ open class Bolt11Payment: }) } - open func failForHash(paymentHash: PaymentHash) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_fail_for_hash(self.uniffiClonePointer(), - FfiConverterTypePaymentHash.lower(paymentHash), $0) - } + open func failForHash(paymentHash: PaymentHash) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_fail_for_hash(self.uniffiClonePointer(), + FfiConverterTypePaymentHash.lower(paymentHash), $0) + } } open func receive(amountMsat: UInt64, description: Bolt11InvoiceDescription, expirySecs: UInt32) throws -> Bolt11Invoice { @@ -1021,21 +1019,19 @@ open class Bolt11Payment: }) } - open func sendProbes(invoice: Bolt11Invoice, routeParameters: RouteParametersConfig?) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_send_probes(self.uniffiClonePointer(), - FfiConverterTypeBolt11Invoice.lower(invoice), - FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) - } + open func sendProbes(invoice: Bolt11Invoice, routeParameters: RouteParametersConfig?) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_send_probes(self.uniffiClonePointer(), + FfiConverterTypeBolt11Invoice.lower(invoice), + FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) + } } - open func sendProbesUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64, routeParameters: RouteParametersConfig?) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount(self.uniffiClonePointer(), - FfiConverterTypeBolt11Invoice.lower(invoice), - FfiConverterUInt64.lower(amountMsat), - FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) - } + open func sendProbesUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64, routeParameters: RouteParametersConfig?) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount(self.uniffiClonePointer(), + FfiConverterTypeBolt11Invoice.lower(invoice), + FfiConverterUInt64.lower(amountMsat), + FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) + } } open func sendUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64, routeParameters: RouteParametersConfig?) throws -> PaymentId { @@ -1142,7 +1138,7 @@ open class Bolt12Invoice: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -1387,7 +1383,7 @@ open class Bolt12Payment: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -1501,11 +1497,10 @@ open class Bolt12Payment: }) } - open func setPathsToStaticInvoiceServer(paths: Data) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt12payment_set_paths_to_static_invoice_server(self.uniffiClonePointer(), - FfiConverterData.lower(paths), $0) - } + open func setPathsToStaticInvoiceServer(paths: Data) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt12payment_set_paths_to_static_invoice_server(self.uniffiClonePointer(), + FfiConverterData.lower(paths), $0) + } } } @@ -1621,7 +1616,7 @@ open class Builder: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -1658,7 +1653,8 @@ open class Builder: public convenience init() { let pointer = try! rustCall { - uniffi_ldk_node_fn_constructor_builder_new($0) + uniffi_ldk_node_fn_constructor_builder_new($0 + ) } self.init(unsafeFromRawPointer: pointer) } @@ -1719,186 +1715,162 @@ open class Builder: }) } - open func setAddressType(addressType: AddressType) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_address_type(self.uniffiClonePointer(), - FfiConverterTypeAddressType.lower(addressType), $0) - } + open func setAddressType(addressType: AddressType) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_address_type(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), $0) + } } - open func setAddressTypesToMonitor(addressTypesToMonitor: [AddressType]) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_address_types_to_monitor(self.uniffiClonePointer(), - FfiConverterSequenceTypeAddressType.lower(addressTypesToMonitor), $0) - } + open func setAddressTypesToMonitor(addressTypesToMonitor: [AddressType]) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_address_types_to_monitor(self.uniffiClonePointer(), + FfiConverterSequenceTypeAddressType.lower(addressTypesToMonitor), $0) + } } - open func setAnnouncementAddresses(announcementAddresses: [SocketAddress]) throws { - try rustCallWithError(FfiConverterTypeBuildError.lift) { - uniffi_ldk_node_fn_method_builder_set_announcement_addresses(self.uniffiClonePointer(), - FfiConverterSequenceTypeSocketAddress.lower(announcementAddresses), $0) - } + open func setAnnouncementAddresses(announcementAddresses: [SocketAddress]) throws { try rustCallWithError(FfiConverterTypeBuildError.lift) { + uniffi_ldk_node_fn_method_builder_set_announcement_addresses(self.uniffiClonePointer(), + FfiConverterSequenceTypeSocketAddress.lower(announcementAddresses), $0) + } } - open func setAsyncPaymentsRole(role: AsyncPaymentsRole?) throws { - try rustCallWithError(FfiConverterTypeBuildError.lift) { - uniffi_ldk_node_fn_method_builder_set_async_payments_role(self.uniffiClonePointer(), - FfiConverterOptionTypeAsyncPaymentsRole.lower(role), $0) - } + open func setAsyncPaymentsRole(role: AsyncPaymentsRole?) throws { try rustCallWithError(FfiConverterTypeBuildError.lift) { + uniffi_ldk_node_fn_method_builder_set_async_payments_role(self.uniffiClonePointer(), + FfiConverterOptionTypeAsyncPaymentsRole.lower(role), $0) + } } - open func setChainSourceBitcoindRest(restHost: String, restPort: UInt16, rpcHost: String, rpcPort: UInt16, rpcUser: String, rpcPassword: String) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rest(self.uniffiClonePointer(), - FfiConverterString.lower(restHost), - FfiConverterUInt16.lower(restPort), - FfiConverterString.lower(rpcHost), - FfiConverterUInt16.lower(rpcPort), - FfiConverterString.lower(rpcUser), - FfiConverterString.lower(rpcPassword), $0) - } + open func setChainSourceBitcoindRest(restHost: String, restPort: UInt16, rpcHost: String, rpcPort: UInt16, rpcUser: String, rpcPassword: String) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rest(self.uniffiClonePointer(), + FfiConverterString.lower(restHost), + FfiConverterUInt16.lower(restPort), + FfiConverterString.lower(rpcHost), + FfiConverterUInt16.lower(rpcPort), + FfiConverterString.lower(rpcUser), + FfiConverterString.lower(rpcPassword), $0) + } } - open func setChainSourceBitcoindRpc(rpcHost: String, rpcPort: UInt16, rpcUser: String, rpcPassword: String) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rpc(self.uniffiClonePointer(), - FfiConverterString.lower(rpcHost), - FfiConverterUInt16.lower(rpcPort), - FfiConverterString.lower(rpcUser), - FfiConverterString.lower(rpcPassword), $0) - } + open func setChainSourceBitcoindRpc(rpcHost: String, rpcPort: UInt16, rpcUser: String, rpcPassword: String) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rpc(self.uniffiClonePointer(), + FfiConverterString.lower(rpcHost), + FfiConverterUInt16.lower(rpcPort), + FfiConverterString.lower(rpcUser), + FfiConverterString.lower(rpcPassword), $0) + } } - open func setChainSourceElectrum(serverUrl: String, config: ElectrumSyncConfig?) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_chain_source_electrum(self.uniffiClonePointer(), - FfiConverterString.lower(serverUrl), - FfiConverterOptionTypeElectrumSyncConfig.lower(config), $0) - } + open func setChainSourceElectrum(serverUrl: String, config: ElectrumSyncConfig?) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_chain_source_electrum(self.uniffiClonePointer(), + FfiConverterString.lower(serverUrl), + FfiConverterOptionTypeElectrumSyncConfig.lower(config), $0) + } } - open func setChainSourceEsplora(serverUrl: String, config: EsploraSyncConfig?) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_chain_source_esplora(self.uniffiClonePointer(), - FfiConverterString.lower(serverUrl), - FfiConverterOptionTypeEsploraSyncConfig.lower(config), $0) - } + open func setChainSourceEsplora(serverUrl: String, config: EsploraSyncConfig?) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_chain_source_esplora(self.uniffiClonePointer(), + FfiConverterString.lower(serverUrl), + FfiConverterOptionTypeEsploraSyncConfig.lower(config), $0) + } } - open func setChannelDataMigration(migration: ChannelDataMigration) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_channel_data_migration(self.uniffiClonePointer(), - FfiConverterTypeChannelDataMigration.lower(migration), $0) - } + open func setChannelDataMigration(migration: ChannelDataMigration) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_channel_data_migration(self.uniffiClonePointer(), + FfiConverterTypeChannelDataMigration.lower(migration), $0) + } } - open func setCustomLogger(logWriter: LogWriter) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_custom_logger(self.uniffiClonePointer(), - FfiConverterTypeLogWriter.lower(logWriter), $0) - } + open func setCustomLogger(logWriter: LogWriter) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_custom_logger(self.uniffiClonePointer(), + FfiConverterTypeLogWriter.lower(logWriter), $0) + } } - open func setEntropyBip39Mnemonic(mnemonic: Mnemonic, passphrase: String?) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_entropy_bip39_mnemonic(self.uniffiClonePointer(), - FfiConverterTypeMnemonic.lower(mnemonic), - FfiConverterOptionString.lower(passphrase), $0) - } + open func setEntropyBip39Mnemonic(mnemonic: Mnemonic, passphrase: String?) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_entropy_bip39_mnemonic(self.uniffiClonePointer(), + FfiConverterTypeMnemonic.lower(mnemonic), + FfiConverterOptionString.lower(passphrase), $0) + } } - open func setEntropySeedBytes(seedBytes: [UInt8]) throws { - try rustCallWithError(FfiConverterTypeBuildError.lift) { - uniffi_ldk_node_fn_method_builder_set_entropy_seed_bytes(self.uniffiClonePointer(), - FfiConverterSequenceUInt8.lower(seedBytes), $0) - } + open func setEntropySeedBytes(seedBytes: [UInt8]) throws { try rustCallWithError(FfiConverterTypeBuildError.lift) { + uniffi_ldk_node_fn_method_builder_set_entropy_seed_bytes(self.uniffiClonePointer(), + FfiConverterSequenceUInt8.lower(seedBytes), $0) + } } - open func setEntropySeedPath(seedPath: String) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_entropy_seed_path(self.uniffiClonePointer(), - FfiConverterString.lower(seedPath), $0) - } + open func setEntropySeedPath(seedPath: String) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_entropy_seed_path(self.uniffiClonePointer(), + FfiConverterString.lower(seedPath), $0) + } } - open func setFilesystemLogger(logFilePath: String?, maxLogLevel: LogLevel?) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_filesystem_logger(self.uniffiClonePointer(), - FfiConverterOptionString.lower(logFilePath), - FfiConverterOptionTypeLogLevel.lower(maxLogLevel), $0) - } + open func setFilesystemLogger(logFilePath: String?, maxLogLevel: LogLevel?) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_filesystem_logger(self.uniffiClonePointer(), + FfiConverterOptionString.lower(logFilePath), + FfiConverterOptionTypeLogLevel.lower(maxLogLevel), $0) + } } - open func setGossipSourceP2p() { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_gossip_source_p2p(self.uniffiClonePointer(), $0) - } + open func setGossipSourceP2p() { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_gossip_source_p2p(self.uniffiClonePointer(), $0) + } } - open func setGossipSourceRgs(rgsServerUrl: String) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_gossip_source_rgs(self.uniffiClonePointer(), - FfiConverterString.lower(rgsServerUrl), $0) - } + open func setGossipSourceRgs(rgsServerUrl: String) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_gossip_source_rgs(self.uniffiClonePointer(), + FfiConverterString.lower(rgsServerUrl), $0) + } } - open func setLiquiditySourceLsps1(nodeId: PublicKey, address: SocketAddress, token: String?) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps1(self.uniffiClonePointer(), - FfiConverterTypePublicKey.lower(nodeId), - FfiConverterTypeSocketAddress.lower(address), - FfiConverterOptionString.lower(token), $0) - } + open func setLiquiditySourceLsps1(nodeId: PublicKey, address: SocketAddress, token: String?) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps1(self.uniffiClonePointer(), + FfiConverterTypePublicKey.lower(nodeId), + FfiConverterTypeSocketAddress.lower(address), + FfiConverterOptionString.lower(token), $0) + } } - open func setLiquiditySourceLsps2(nodeId: PublicKey, address: SocketAddress, token: String?) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps2(self.uniffiClonePointer(), - FfiConverterTypePublicKey.lower(nodeId), - FfiConverterTypeSocketAddress.lower(address), - FfiConverterOptionString.lower(token), $0) - } + open func setLiquiditySourceLsps2(nodeId: PublicKey, address: SocketAddress, token: String?) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps2(self.uniffiClonePointer(), + FfiConverterTypePublicKey.lower(nodeId), + FfiConverterTypeSocketAddress.lower(address), + FfiConverterOptionString.lower(token), $0) + } } - open func setListeningAddresses(listeningAddresses: [SocketAddress]) throws { - try rustCallWithError(FfiConverterTypeBuildError.lift) { - uniffi_ldk_node_fn_method_builder_set_listening_addresses(self.uniffiClonePointer(), - FfiConverterSequenceTypeSocketAddress.lower(listeningAddresses), $0) - } + open func setListeningAddresses(listeningAddresses: [SocketAddress]) throws { try rustCallWithError(FfiConverterTypeBuildError.lift) { + uniffi_ldk_node_fn_method_builder_set_listening_addresses(self.uniffiClonePointer(), + FfiConverterSequenceTypeSocketAddress.lower(listeningAddresses), $0) + } } - open func setLogFacadeLogger() { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_log_facade_logger(self.uniffiClonePointer(), $0) - } + open func setLogFacadeLogger() { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_log_facade_logger(self.uniffiClonePointer(), $0) + } } - open func setNetwork(network: Network) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_network(self.uniffiClonePointer(), - FfiConverterTypeNetwork.lower(network), $0) - } + open func setNetwork(network: Network) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_network(self.uniffiClonePointer(), + FfiConverterTypeNetwork.lower(network), $0) + } } - open func setNodeAlias(nodeAlias: String) throws { - try rustCallWithError(FfiConverterTypeBuildError.lift) { - uniffi_ldk_node_fn_method_builder_set_node_alias(self.uniffiClonePointer(), - FfiConverterString.lower(nodeAlias), $0) - } + open func setNodeAlias(nodeAlias: String) throws { try rustCallWithError(FfiConverterTypeBuildError.lift) { + uniffi_ldk_node_fn_method_builder_set_node_alias(self.uniffiClonePointer(), + FfiConverterString.lower(nodeAlias), $0) + } } - open func setPathfindingScoresSource(url: String) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_pathfinding_scores_source(self.uniffiClonePointer(), - FfiConverterString.lower(url), $0) - } + open func setPathfindingScoresSource(url: String) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_pathfinding_scores_source(self.uniffiClonePointer(), + FfiConverterString.lower(url), $0) + } } - open func setStorageDirPath(storageDirPath: String) { - try! rustCall { - uniffi_ldk_node_fn_method_builder_set_storage_dir_path(self.uniffiClonePointer(), - FfiConverterString.lower(storageDirPath), $0) - } + open func setStorageDirPath(storageDirPath: String) { try! rustCall { + uniffi_ldk_node_fn_method_builder_set_storage_dir_path(self.uniffiClonePointer(), + FfiConverterString.lower(storageDirPath), $0) + } } } @@ -1962,7 +1934,7 @@ open class FeeRate: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -2099,7 +2071,7 @@ open class Lsps1Liquidity: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -2217,7 +2189,7 @@ open class LogWriterImpl: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -2261,26 +2233,25 @@ open class LogWriterImpl: try! rustCall { uniffi_ldk_node_fn_free_logwriter(pointer, $0) } } - open func log(record: LogRecord) { - try! rustCall { - uniffi_ldk_node_fn_method_logwriter_log(self.uniffiClonePointer(), - FfiConverterTypeLogRecord.lower(record), $0) - } + open func log(record: LogRecord) { try! rustCall { + uniffi_ldk_node_fn_method_logwriter_log(self.uniffiClonePointer(), + FfiConverterTypeLogRecord.lower(record), $0) + } } } -/// Magic number for the Rust proxy to call using the same mechanism as every other method, -/// to free the callback once it's dropped by Rust. +// Magic number for the Rust proxy to call using the same mechanism as every other method, +// to free the callback once it's dropped by Rust. private let IDX_CALLBACK_FREE: Int32 = 0 // Callback return codes private let UNIFFI_CALLBACK_SUCCESS: Int32 = 0 private let UNIFFI_CALLBACK_ERROR: Int32 = 1 private let UNIFFI_CALLBACK_UNEXPECTED_ERROR: Int32 = 2 -/// Put the implementation in a struct so we don't pollute the top-level namespace +// Put the implementation in a struct so we don't pollute the top-level namespace private enum UniffiCallbackInterfaceLogWriter { - /// Create the VTable using a series of closures. - /// Swift automatically converts these into C callback functions. + // Create the VTable using a series of closures. + // Swift automatically converts these into C callback functions. static var vtable: UniffiVTableCallbackInterfaceLogWriter = .init( log: { ( uniffiHandle: UInt64, @@ -2385,7 +2356,7 @@ open class NetworkGraph: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -2608,7 +2579,7 @@ open class Node: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -2652,21 +2623,19 @@ open class Node: try! rustCall { uniffi_ldk_node_fn_free_node(pointer, $0) } } - open func addAddressTypeToMonitor(addressType: AddressType, seedBytes: [UInt8]) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_add_address_type_to_monitor(self.uniffiClonePointer(), - FfiConverterTypeAddressType.lower(addressType), - FfiConverterSequenceUInt8.lower(seedBytes), $0) - } + open func addAddressTypeToMonitor(addressType: AddressType, seedBytes: [UInt8]) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_add_address_type_to_monitor(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterSequenceUInt8.lower(seedBytes), $0) + } } - open func addAddressTypeToMonitorWithMnemonic(addressType: AddressType, mnemonic: Mnemonic, passphrase: String?) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_add_address_type_to_monitor_with_mnemonic(self.uniffiClonePointer(), - FfiConverterTypeAddressType.lower(addressType), - FfiConverterTypeMnemonic.lower(mnemonic), - FfiConverterOptionString.lower(passphrase), $0) - } + open func addAddressTypeToMonitorWithMnemonic(addressType: AddressType, mnemonic: Mnemonic, passphrase: String?) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_add_address_type_to_monitor_with_mnemonic(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterTypeMnemonic.lower(mnemonic), + FfiConverterOptionString.lower(passphrase), $0) + } } open func announcementAddresses() -> [SocketAddress]? { @@ -2687,12 +2656,11 @@ open class Node: }) } - open func closeChannel(userChannelId: UserChannelId, counterpartyNodeId: PublicKey) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_close_channel(self.uniffiClonePointer(), - FfiConverterTypeUserChannelId.lower(userChannelId), - FfiConverterTypePublicKey.lower(counterpartyNodeId), $0) - } + open func closeChannel(userChannelId: UserChannelId, counterpartyNodeId: PublicKey) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_close_channel(self.uniffiClonePointer(), + FfiConverterTypeUserChannelId.lower(userChannelId), + FfiConverterTypePublicKey.lower(counterpartyNodeId), $0) + } } open func config() -> Config { @@ -2701,13 +2669,12 @@ open class Node: }) } - open func connect(nodeId: PublicKey, address: SocketAddress, persist: Bool) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_connect(self.uniffiClonePointer(), - FfiConverterTypePublicKey.lower(nodeId), - FfiConverterTypeSocketAddress.lower(address), - FfiConverterBool.lower(persist), $0) - } + open func connect(nodeId: PublicKey, address: SocketAddress, persist: Bool) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_connect(self.uniffiClonePointer(), + FfiConverterTypePublicKey.lower(nodeId), + FfiConverterTypeSocketAddress.lower(address), + FfiConverterBool.lower(persist), $0) + } } open func currentSyncIntervals() -> RuntimeSyncIntervals { @@ -2716,17 +2683,15 @@ open class Node: }) } - open func disconnect(nodeId: PublicKey) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_disconnect(self.uniffiClonePointer(), - FfiConverterTypePublicKey.lower(nodeId), $0) - } + open func disconnect(nodeId: PublicKey) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_disconnect(self.uniffiClonePointer(), + FfiConverterTypePublicKey.lower(nodeId), $0) + } } - open func eventHandled() throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_event_handled(self.uniffiClonePointer(), $0) - } + open func eventHandled() throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_event_handled(self.uniffiClonePointer(), $0) + } } open func exportPathfindingScores() throws -> Data { @@ -2735,13 +2700,12 @@ open class Node: }) } - open func forceCloseChannel(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, reason: String?) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_force_close_channel(self.uniffiClonePointer(), - FfiConverterTypeUserChannelId.lower(userChannelId), - FfiConverterTypePublicKey.lower(counterpartyNodeId), - FfiConverterOptionString.lower(reason), $0) - } + open func forceCloseChannel(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, reason: String?) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_force_close_channel(self.uniffiClonePointer(), + FfiConverterTypeUserChannelId.lower(userChannelId), + FfiConverterTypePublicKey.lower(counterpartyNodeId), + FfiConverterOptionString.lower(reason), $0) + } } open func getAddressBalance(addressStr: String) throws -> UInt64 { @@ -2882,35 +2846,31 @@ open class Node: }) } - open func removeAddressTypeFromMonitor(addressType: AddressType) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_remove_address_type_from_monitor(self.uniffiClonePointer(), - FfiConverterTypeAddressType.lower(addressType), $0) - } + open func removeAddressTypeFromMonitor(addressType: AddressType) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_remove_address_type_from_monitor(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), $0) + } } - open func removePayment(paymentId: PaymentId) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_remove_payment(self.uniffiClonePointer(), - FfiConverterTypePaymentId.lower(paymentId), $0) - } + open func removePayment(paymentId: PaymentId) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_remove_payment(self.uniffiClonePointer(), + FfiConverterTypePaymentId.lower(paymentId), $0) + } } - open func setPrimaryAddressType(addressType: AddressType, seedBytes: [UInt8]) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_set_primary_address_type(self.uniffiClonePointer(), - FfiConverterTypeAddressType.lower(addressType), - FfiConverterSequenceUInt8.lower(seedBytes), $0) - } + open func setPrimaryAddressType(addressType: AddressType, seedBytes: [UInt8]) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_set_primary_address_type(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterSequenceUInt8.lower(seedBytes), $0) + } } - open func setPrimaryAddressTypeWithMnemonic(addressType: AddressType, mnemonic: Mnemonic, passphrase: String?) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_set_primary_address_type_with_mnemonic(self.uniffiClonePointer(), - FfiConverterTypeAddressType.lower(addressType), - FfiConverterTypeMnemonic.lower(mnemonic), - FfiConverterOptionString.lower(passphrase), $0) - } + open func setPrimaryAddressTypeWithMnemonic(addressType: AddressType, mnemonic: Mnemonic, passphrase: String?) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_set_primary_address_type_with_mnemonic(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterTypeMnemonic.lower(mnemonic), + FfiConverterOptionString.lower(passphrase), $0) + } } open func signMessage(msg: [UInt8]) -> String { @@ -2920,23 +2880,21 @@ open class Node: }) } - open func spliceIn(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, spliceAmountSats: UInt64) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_splice_in(self.uniffiClonePointer(), - FfiConverterTypeUserChannelId.lower(userChannelId), - FfiConverterTypePublicKey.lower(counterpartyNodeId), - FfiConverterUInt64.lower(spliceAmountSats), $0) - } + open func spliceIn(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, spliceAmountSats: UInt64) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_splice_in(self.uniffiClonePointer(), + FfiConverterTypeUserChannelId.lower(userChannelId), + FfiConverterTypePublicKey.lower(counterpartyNodeId), + FfiConverterUInt64.lower(spliceAmountSats), $0) + } } - open func spliceOut(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, address: Address, spliceAmountSats: UInt64) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_splice_out(self.uniffiClonePointer(), - FfiConverterTypeUserChannelId.lower(userChannelId), - FfiConverterTypePublicKey.lower(counterpartyNodeId), - FfiConverterTypeAddress.lower(address), - FfiConverterUInt64.lower(spliceAmountSats), $0) - } + open func spliceOut(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, address: Address, spliceAmountSats: UInt64) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_splice_out(self.uniffiClonePointer(), + FfiConverterTypeUserChannelId.lower(userChannelId), + FfiConverterTypePublicKey.lower(counterpartyNodeId), + FfiConverterTypeAddress.lower(address), + FfiConverterUInt64.lower(spliceAmountSats), $0) + } } open func spontaneousPayment() -> SpontaneousPayment { @@ -2945,10 +2903,9 @@ open class Node: }) } - open func start() throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_start(self.uniffiClonePointer(), $0) - } + open func start() throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_start(self.uniffiClonePointer(), $0) + } } open func status() -> NodeStatus { @@ -2957,16 +2914,14 @@ open class Node: }) } - open func stop() throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_stop(self.uniffiClonePointer(), $0) - } + open func stop() throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_stop(self.uniffiClonePointer(), $0) + } } - open func syncWallets() throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_sync_wallets(self.uniffiClonePointer(), $0) - } + open func syncWallets() throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_sync_wallets(self.uniffiClonePointer(), $0) + } } open func unifiedQrPayment() -> UnifiedQrPayment { @@ -2975,20 +2930,18 @@ open class Node: }) } - open func updateChannelConfig(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, channelConfig: ChannelConfig) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_update_channel_config(self.uniffiClonePointer(), - FfiConverterTypeUserChannelId.lower(userChannelId), - FfiConverterTypePublicKey.lower(counterpartyNodeId), - FfiConverterTypeChannelConfig.lower(channelConfig), $0) - } + open func updateChannelConfig(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, channelConfig: ChannelConfig) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_update_channel_config(self.uniffiClonePointer(), + FfiConverterTypeUserChannelId.lower(userChannelId), + FfiConverterTypePublicKey.lower(counterpartyNodeId), + FfiConverterTypeChannelConfig.lower(channelConfig), $0) + } } - open func updateSyncIntervals(intervals: RuntimeSyncIntervals) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_update_sync_intervals(self.uniffiClonePointer(), - FfiConverterTypeRuntimeSyncIntervals.lower(intervals), $0) - } + open func updateSyncIntervals(intervals: RuntimeSyncIntervals) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_update_sync_intervals(self.uniffiClonePointer(), + FfiConverterTypeRuntimeSyncIntervals.lower(intervals), $0) + } } open func verifySignature(msg: [UInt8], sig: String, pkey: PublicKey) -> Bool { @@ -3088,7 +3041,7 @@ open class Offer: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -3316,7 +3269,7 @@ open class OnchainPayment: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -3530,7 +3483,7 @@ open class Refund: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -3732,7 +3685,7 @@ open class SpontaneousPayment: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -3785,12 +3738,11 @@ open class SpontaneousPayment: }) } - open func sendProbes(amountMsat: UInt64, nodeId: PublicKey) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_spontaneouspayment_send_probes(self.uniffiClonePointer(), - FfiConverterUInt64.lower(amountMsat), - FfiConverterTypePublicKey.lower(nodeId), $0) - } + open func sendProbes(amountMsat: UInt64, nodeId: PublicKey) throws { try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_spontaneouspayment_send_probes(self.uniffiClonePointer(), + FfiConverterUInt64.lower(amountMsat), + FfiConverterTypePublicKey.lower(nodeId), $0) + } } open func sendWithCustomTlvs(amountMsat: UInt64, nodeId: PublicKey, routeParameters: RouteParametersConfig?, customTlvs: [CustomTlvRecord]) throws -> PaymentId { @@ -3883,7 +3835,7 @@ open class UnifiedQrPayment: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -4001,7 +3953,7 @@ open class VssHeaderProvider: { fileprivate let pointer: UnsafeMutableRawPointer! - // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -4114,8 +4066,8 @@ public struct AddressTypeBalance { public var totalSats: UInt64 public var spendableSats: UInt64 - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(totalSats: UInt64, spendableSats: UInt64) { self.totalSats = totalSats self.spendableSats = spendableSats @@ -4175,8 +4127,8 @@ public struct AnchorChannelsConfig { public var trustedPeersNoReserve: [PublicKey] public var perChannelReserveSats: UInt64 - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(trustedPeersNoReserve: [PublicKey], perChannelReserveSats: UInt64) { self.trustedPeersNoReserve = trustedPeersNoReserve self.perChannelReserveSats = perChannelReserveSats @@ -4237,8 +4189,8 @@ public struct BackgroundSyncConfig { public var lightningWalletSyncIntervalSecs: UInt64 public var feeRateCacheUpdateIntervalSecs: UInt64 - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(onchainWalletSyncIntervalSecs: UInt64, lightningWalletSyncIntervalSecs: UInt64, feeRateCacheUpdateIntervalSecs: UInt64) { self.onchainWalletSyncIntervalSecs = onchainWalletSyncIntervalSecs self.lightningWalletSyncIntervalSecs = lightningWalletSyncIntervalSecs @@ -4309,8 +4261,8 @@ public struct BalanceDetails { public var lightningBalances: [LightningBalance] public var pendingBalancesFromChannelClosures: [PendingSweepBalance] - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(totalOnchainBalanceSats: UInt64, spendableOnchainBalanceSats: UInt64, totalAnchorChannelsReserveSats: UInt64, totalLightningBalanceSats: UInt64, lightningBalances: [LightningBalance], pendingBalancesFromChannelClosures: [PendingSweepBalance]) { self.totalOnchainBalanceSats = totalOnchainBalanceSats self.spendableOnchainBalanceSats = spendableOnchainBalanceSats @@ -4398,8 +4350,8 @@ public struct BestBlock { public var blockHash: BlockHash public var height: UInt32 - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(blockHash: BlockHash, height: UInt32) { self.blockHash = blockHash self.height = height @@ -4463,8 +4415,8 @@ public struct ChannelConfig { public var forceCloseAvoidanceMaxFeeSatoshis: UInt64 public var acceptUnderpayingHtlcs: Bool - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(forwardingFeeProportionalMillionths: UInt32, forwardingFeeBaseMsat: UInt32, cltvExpiryDelta: UInt16, maxDustHtlcExposure: MaxDustHtlcExposure, forceCloseAvoidanceMaxFeeSatoshis: UInt64, acceptUnderpayingHtlcs: Bool) { self.forwardingFeeProportionalMillionths = forwardingFeeProportionalMillionths self.forwardingFeeBaseMsat = forwardingFeeBaseMsat @@ -4552,8 +4504,8 @@ public struct ChannelDataMigration { public var channelManager: [UInt8]? public var channelMonitors: [[UInt8]] - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(channelManager: [UInt8]?, channelMonitors: [[UInt8]]) { self.channelManager = channelManager self.channelMonitors = channelMonitors @@ -4643,8 +4595,8 @@ public struct ChannelDetails { public var config: ChannelConfig public var claimableOnCloseSats: UInt64? - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(channelId: ChannelId, counterpartyNodeId: PublicKey, fundingTxo: OutPoint?, shortChannelId: UInt64?, outboundScidAlias: UInt64?, inboundScidAlias: UInt64?, channelValueSats: UInt64, unspendablePunishmentReserve: UInt64?, userChannelId: UserChannelId, feerateSatPer1000Weight: UInt32, outboundCapacityMsat: UInt64, inboundCapacityMsat: UInt64, confirmationsRequired: UInt32?, confirmations: UInt32?, isOutbound: Bool, isChannelReady: Bool, isUsable: Bool, isAnnounced: Bool, cltvExpiryDelta: UInt16?, counterpartyUnspendablePunishmentReserve: UInt64, counterpartyOutboundHtlcMinimumMsat: UInt64?, counterpartyOutboundHtlcMaximumMsat: UInt64?, counterpartyForwardingInfoFeeBaseMsat: UInt32?, counterpartyForwardingInfoFeeProportionalMillionths: UInt32?, counterpartyForwardingInfoCltvExpiryDelta: UInt16?, nextOutboundHtlcLimitMsat: UInt64, nextOutboundHtlcMinimumMsat: UInt64, forceCloseSpendDelay: UInt16?, inboundHtlcMinimumMsat: UInt64, inboundHtlcMaximumMsat: UInt64?, config: ChannelConfig, claimableOnCloseSats: UInt64?) { self.channelId = channelId self.counterpartyNodeId = counterpartyNodeId @@ -4917,8 +4869,8 @@ public struct ChannelInfo { public var twoToOne: ChannelUpdateInfo? public var capacitySats: UInt64? - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(nodeOne: NodeId, oneToTwo: ChannelUpdateInfo?, nodeTwo: NodeId, twoToOne: ChannelUpdateInfo?, capacitySats: UInt64?) { self.nodeOne = nodeOne self.oneToTwo = oneToTwo @@ -5003,8 +4955,8 @@ public struct ChannelUpdateInfo { public var htlcMaximumMsat: UInt64 public var fees: RoutingFees - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(lastUpdate: UInt32, enabled: Bool, cltvExpiryDelta: UInt16, htlcMinimumMsat: UInt64, htlcMaximumMsat: UInt64, fees: RoutingFees) { self.lastUpdate = lastUpdate self.enabled = enabled @@ -5102,8 +5054,8 @@ public struct Config { public var addressType: AddressType public var addressTypesToMonitor: [AddressType] - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(storageDirPath: String, network: Network, listeningAddresses: [SocketAddress]?, announcementAddresses: [SocketAddress]?, nodeAlias: NodeAlias?, trustedPeers0conf: [PublicKey], probingLiquidityLimitMultiplier: UInt64, anchorChannelsConfig: AnchorChannelsConfig?, routeParameters: RouteParametersConfig?, includeUntrustedPendingInSpendable: Bool, addressType: AddressType, addressTypesToMonitor: [AddressType]) { self.storageDirPath = storageDirPath self.network = network @@ -5233,8 +5185,8 @@ public struct CustomTlvRecord { public var typeNum: UInt64 public var value: [UInt8] - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(typeNum: UInt64, value: [UInt8]) { self.typeNum = typeNum self.value = value @@ -5293,8 +5245,8 @@ public func FfiConverterTypeCustomTlvRecord_lower(_ value: CustomTlvRecord) -> R public struct ElectrumSyncConfig { public var backgroundSyncConfig: BackgroundSyncConfig? - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(backgroundSyncConfig: BackgroundSyncConfig?) { self.backgroundSyncConfig = backgroundSyncConfig } @@ -5346,8 +5298,8 @@ public func FfiConverterTypeElectrumSyncConfig_lower(_ value: ElectrumSyncConfig public struct EsploraSyncConfig { public var backgroundSyncConfig: BackgroundSyncConfig? - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(backgroundSyncConfig: BackgroundSyncConfig?) { self.backgroundSyncConfig = backgroundSyncConfig } @@ -5400,8 +5352,8 @@ public struct LspFeeLimits { public var maxTotalOpeningFeeMsat: UInt64? public var maxProportionalOpeningFeePpmMsat: UInt64? - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(maxTotalOpeningFeeMsat: UInt64?, maxProportionalOpeningFeePpmMsat: UInt64?) { self.maxTotalOpeningFeeMsat = maxTotalOpeningFeeMsat self.maxProportionalOpeningFeePpmMsat = maxProportionalOpeningFeePpmMsat @@ -5464,8 +5416,8 @@ public struct Lsps1Bolt11PaymentInfo { public var orderTotalSat: UInt64 public var invoice: Bolt11Invoice - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(state: Lsps1PaymentState, expiresAt: LspsDateTime, feeTotalSat: UInt64, orderTotalSat: UInt64, invoice: Bolt11Invoice) { self.state = state self.expiresAt = expiresAt @@ -5518,8 +5470,8 @@ public struct Lsps1ChannelInfo { public var fundingOutpoint: OutPoint public var expiresAt: LspsDateTime - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(fundedAt: LspsDateTime, fundingOutpoint: OutPoint, expiresAt: LspsDateTime) { self.fundedAt = fundedAt self.fundingOutpoint = fundingOutpoint @@ -5592,8 +5544,8 @@ public struct Lsps1OnchainPaymentInfo { public var minFeeFor0conf: FeeRate public var refundOnchainAddress: Address? - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(state: Lsps1PaymentState, expiresAt: LspsDateTime, feeTotalSat: UInt64, orderTotalSat: UInt64, address: Address, minOnchainPaymentConfirmations: UInt16?, minFeeFor0conf: FeeRate, refundOnchainAddress: Address?) { self.state = state self.expiresAt = expiresAt @@ -5659,8 +5611,8 @@ public struct Lsps1OrderParams { public var token: String? public var announceChannel: Bool - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(lspBalanceSat: UInt64, clientBalanceSat: UInt64, requiredChannelConfirmations: UInt16, fundingConfirmsWithinBlocks: UInt16, channelExpiryBlocks: UInt32, token: String?, announceChannel: Bool) { self.lspBalanceSat = lspBalanceSat self.clientBalanceSat = clientBalanceSat @@ -5757,8 +5709,8 @@ public struct Lsps1OrderStatus { public var paymentOptions: Lsps1PaymentInfo public var channelState: Lsps1ChannelInfo? - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(orderId: Lsps1OrderId, orderParams: Lsps1OrderParams, paymentOptions: Lsps1PaymentInfo, channelState: Lsps1ChannelInfo?) { self.orderId = orderId self.orderParams = orderParams @@ -5807,8 +5759,8 @@ public struct Lsps1PaymentInfo { public var bolt11: Lsps1Bolt11PaymentInfo? public var onchain: Lsps1OnchainPaymentInfo? - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(bolt11: Lsps1Bolt11PaymentInfo?, onchain: Lsps1OnchainPaymentInfo?) { self.bolt11 = bolt11 self.onchain = onchain @@ -5859,8 +5811,8 @@ public struct Lsps2ServiceConfig { public var maxPaymentSizeMsat: UInt64 public var clientTrustsLsp: Bool - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(requireToken: String?, advertiseService: Bool, channelOpeningFeePpm: UInt32, channelOverProvisioningPpm: UInt32, minChannelOpeningFeeMsat: UInt64, minChannelLifetime: UInt32, maxClientToSelfDelay: UInt32, minPaymentSizeMsat: UInt64, maxPaymentSizeMsat: UInt64, clientTrustsLsp: Bool) { self.requireToken = requireToken self.advertiseService = advertiseService @@ -5978,8 +5930,8 @@ public struct LogRecord { public var modulePath: String public var line: UInt32 - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(level: LogLevel, args: String, modulePath: String, line: UInt32) { self.level = level self.args = args @@ -6054,8 +6006,8 @@ public struct NodeAnnouncementInfo { public var alias: String public var addresses: [SocketAddress] - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(lastUpdate: UInt32, alias: String, addresses: [SocketAddress]) { self.lastUpdate = lastUpdate self.alias = alias @@ -6122,8 +6074,8 @@ public struct NodeInfo { public var channels: [UInt64] public var announcementInfo: NodeAnnouncementInfo? - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(channels: [UInt64], announcementInfo: NodeAnnouncementInfo?) { self.channels = channels self.announcementInfo = announcementInfo @@ -6190,8 +6142,8 @@ public struct NodeStatus { public var latestNodeAnnouncementBroadcastTimestamp: UInt64? public var latestChannelMonitorArchivalHeight: UInt32? - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(isRunning: Bool, currentBestBlock: BestBlock, latestLightningWalletSyncTimestamp: UInt64?, latestOnchainWalletSyncTimestamp: UInt64?, latestFeeRateCacheUpdateTimestamp: UInt64?, latestRgsSnapshotTimestamp: UInt64?, latestPathfindingScoresSyncTimestamp: UInt64?, latestNodeAnnouncementBroadcastTimestamp: UInt64?, latestChannelMonitorArchivalHeight: UInt32?) { self.isRunning = isRunning self.currentBestBlock = currentBestBlock @@ -6300,8 +6252,8 @@ public struct OutPoint { public var txid: Txid public var vout: UInt32 - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(txid: Txid, vout: UInt32) { self.txid = txid self.vout = vout @@ -6366,8 +6318,8 @@ public struct PaymentDetails { public var status: PaymentStatus public var latestUpdateTimestamp: UInt64 - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(id: PaymentId, kind: PaymentKind, amountMsat: UInt64?, feePaidMsat: UInt64?, direction: PaymentDirection, status: PaymentStatus, latestUpdateTimestamp: UInt64) { self.id = id self.kind = kind @@ -6464,8 +6416,8 @@ public struct PeerDetails { public var isPersisted: Bool public var isConnected: Bool - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(nodeId: PublicKey, address: SocketAddress, isPersisted: Bool, isConnected: Bool) { self.nodeId = nodeId self.address = address @@ -6543,8 +6495,8 @@ public struct RouteHintHop { public var htlcMaximumMsat: UInt64? public var fees: RoutingFees - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(srcNodeId: PublicKey, shortChannelId: UInt64, cltvExpiryDelta: UInt16, htlcMinimumMsat: UInt64?, htlcMaximumMsat: UInt64?, fees: RoutingFees) { self.srcNodeId = srcNodeId self.shortChannelId = shortChannelId @@ -6634,8 +6586,8 @@ public struct RouteParametersConfig { public var maxPathCount: UInt8 public var maxChannelSaturationPowerOfHalf: UInt8 - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(maxTotalRoutingFeeMsat: UInt64?, maxTotalCltvExpiryDelta: UInt32, maxPathCount: UInt8, maxChannelSaturationPowerOfHalf: UInt8) { self.maxTotalRoutingFeeMsat = maxTotalRoutingFeeMsat self.maxTotalCltvExpiryDelta = maxTotalCltvExpiryDelta @@ -6709,8 +6661,8 @@ public struct RoutingFees { public var baseMsat: UInt32 public var proportionalMillionths: UInt32 - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(baseMsat: UInt32, proportionalMillionths: UInt32) { self.baseMsat = baseMsat self.proportionalMillionths = proportionalMillionths @@ -6771,8 +6723,8 @@ public struct RuntimeSyncIntervals { public var lightningWalletSyncIntervalSecs: UInt64 public var feeRateCacheUpdateIntervalSecs: UInt64 - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(onchainWalletSyncIntervalSecs: UInt64, lightningWalletSyncIntervalSecs: UInt64, feeRateCacheUpdateIntervalSecs: UInt64) { self.onchainWalletSyncIntervalSecs = onchainWalletSyncIntervalSecs self.lightningWalletSyncIntervalSecs = lightningWalletSyncIntervalSecs @@ -6839,8 +6791,8 @@ public struct SpendableUtxo { public var outpoint: OutPoint public var valueSats: UInt64 - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(outpoint: OutPoint, valueSats: UInt64) { self.outpoint = outpoint self.valueSats = valueSats @@ -6901,8 +6853,8 @@ public struct TransactionDetails { public var inputs: [TxInput] public var outputs: [TxOutput] - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(amountSats: Int64, inputs: [TxInput], outputs: [TxOutput]) { self.amountSats = amountSats self.inputs = inputs @@ -6972,8 +6924,8 @@ public struct TxInput { public var witness: [String] public var sequence: UInt32 - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(txid: Txid, vout: UInt32, scriptsig: String, witness: [String], sequence: UInt32) { self.txid = txid self.vout = vout @@ -7057,8 +7009,8 @@ public struct TxOutput { public var value: Int64 public var n: UInt32 - /// Default memberwise initializers are never public by default, so we - /// declare one manually. + // Default memberwise initializers are never public by default, so we + // declare one manually. public init(scriptpubkey: String, scriptpubkeyType: String?, scriptpubkeyAddress: String?, value: Int64, n: UInt32) { self.scriptpubkey = scriptpubkey self.scriptpubkeyType = scriptpubkeyType @@ -7319,8 +7271,10 @@ extension BalanceSource: Equatable, Hashable {} // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum Bolt11InvoiceDescription { - case hash(hash: String) - case direct(description: String) + case hash(hash: String + ) + case direct(description: String + ) } #if swift(>=5.8) @@ -7332,9 +7286,11 @@ public struct FfiConverterTypeBolt11InvoiceDescription: FfiConverterRustBuffer { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Bolt11InvoiceDescription { let variant: Int32 = try readInt(&buf) switch variant { - case 1: return try .hash(hash: FfiConverterString.read(from: &buf)) + case 1: return try .hash(hash: FfiConverterString.read(from: &buf) + ) - case 2: return try .direct(description: FfiConverterString.read(from: &buf)) + case 2: return try .direct(description: FfiConverterString.read(from: &buf) + ) default: throw UniffiInternalError.unexpectedEnumCase } @@ -7530,20 +7486,23 @@ extension BuildError: Foundation.LocalizedError { // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum ClosureReason { - case counterpartyForceClosed(peerMsg: UntrustedString) + case counterpartyForceClosed(peerMsg: UntrustedString + ) case holderForceClosed(broadcastedLatestTxn: Bool?, message: String) case legacyCooperativeClosure case counterpartyInitiatedCooperativeClosure case locallyInitiatedCooperativeClosure case commitmentTxConfirmed case fundingTimedOut - case processingError(err: String) + case processingError(err: String + ) case disconnectedPeer case outdatedChannelManager case counterpartyCoopClosedUnfundedChannel case locallyCoopClosedUnfundedChannel case fundingBatchClosure - case htlCsTimedOut(paymentHash: PaymentHash?) + case htlCsTimedOut(paymentHash: PaymentHash? + ) case peerFeerateTooLow(peerFeerateSatPerKw: UInt32, requiredFeerateSatPerKw: UInt32) } @@ -7556,7 +7515,8 @@ public struct FfiConverterTypeClosureReason: FfiConverterRustBuffer { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ClosureReason { let variant: Int32 = try readInt(&buf) switch variant { - case 1: return try .counterpartyForceClosed(peerMsg: FfiConverterTypeUntrustedString.read(from: &buf)) + case 1: return try .counterpartyForceClosed(peerMsg: FfiConverterTypeUntrustedString.read(from: &buf) + ) case 2: return try .holderForceClosed(broadcastedLatestTxn: FfiConverterOptionBool.read(from: &buf), message: FfiConverterString.read(from: &buf)) @@ -7570,7 +7530,8 @@ public struct FfiConverterTypeClosureReason: FfiConverterRustBuffer { case 7: return .fundingTimedOut - case 8: return try .processingError(err: FfiConverterString.read(from: &buf)) + case 8: return try .processingError(err: FfiConverterString.read(from: &buf) + ) case 9: return .disconnectedPeer @@ -7582,7 +7543,8 @@ public struct FfiConverterTypeClosureReason: FfiConverterRustBuffer { case 13: return .fundingBatchClosure - case 14: return try .htlCsTimedOut(paymentHash: FfiConverterOptionTypePaymentHash.read(from: &buf)) + case 14: return try .htlCsTimedOut(paymentHash: FfiConverterOptionTypePaymentHash.read(from: &buf) + ) case 15: return try .peerFeerateTooLow(peerFeerateSatPerKw: FfiConverterUInt32.read(from: &buf), requiredFeerateSatPerKw: FfiConverterUInt32.read(from: &buf)) @@ -7869,8 +7831,10 @@ public enum Event { case onchainTransactionConfirmed(txid: Txid, blockHash: BlockHash, blockHeight: UInt32, confirmationTime: UInt64, details: TransactionDetails) case onchainTransactionReceived(txid: Txid, details: TransactionDetails) case onchainTransactionReplaced(txid: Txid, conflicts: [Txid]) - case onchainTransactionReorged(txid: Txid) - case onchainTransactionEvicted(txid: Txid) + case onchainTransactionReorged(txid: Txid + ) + case onchainTransactionEvicted(txid: Txid + ) case syncProgress(syncType: SyncType, progressPercent: UInt8, currentBlockHeight: UInt32, targetBlockHeight: UInt32) case syncCompleted(syncType: SyncType, syncedBlockHeight: UInt32) case balanceChanged(oldSpendableOnchainBalanceSats: UInt64, newSpendableOnchainBalanceSats: UInt64, oldTotalOnchainBalanceSats: UInt64, newTotalOnchainBalanceSats: UInt64, oldTotalLightningBalanceSats: UInt64, newTotalLightningBalanceSats: UInt64) @@ -7911,9 +7875,11 @@ public struct FfiConverterTypeEvent: FfiConverterRustBuffer { case 13: return try .onchainTransactionReplaced(txid: FfiConverterTypeTxid.read(from: &buf), conflicts: FfiConverterSequenceTypeTxid.read(from: &buf)) - case 14: return try .onchainTransactionReorged(txid: FfiConverterTypeTxid.read(from: &buf)) + case 14: return try .onchainTransactionReorged(txid: FfiConverterTypeTxid.read(from: &buf) + ) - case 15: return try .onchainTransactionEvicted(txid: FfiConverterTypeTxid.read(from: &buf)) + case 15: return try .onchainTransactionEvicted(txid: FfiConverterTypeTxid.read(from: &buf) + ) case 16: return try .syncProgress(syncType: FfiConverterTypeSyncType.read(from: &buf), progressPercent: FfiConverterUInt8.read(from: &buf), currentBlockHeight: FfiConverterUInt32.read(from: &buf), targetBlockHeight: FfiConverterUInt32.read(from: &buf)) @@ -8317,8 +8283,10 @@ extension LogLevel: Equatable, Hashable {} // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum MaxDustHtlcExposure { - case fixedLimit(limitMsat: UInt64) - case feeRateMultiplier(multiplier: UInt64) + case fixedLimit(limitMsat: UInt64 + ) + case feeRateMultiplier(multiplier: UInt64 + ) } #if swift(>=5.8) @@ -8330,9 +8298,11 @@ public struct FfiConverterTypeMaxDustHTLCExposure: FfiConverterRustBuffer { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MaxDustHtlcExposure { let variant: Int32 = try readInt(&buf) switch variant { - case 1: return try .fixedLimit(limitMsat: FfiConverterUInt64.read(from: &buf)) + case 1: return try .fixedLimit(limitMsat: FfiConverterUInt64.read(from: &buf) + ) - case 2: return try .feeRateMultiplier(multiplier: FfiConverterUInt64.read(from: &buf)) + case 2: return try .feeRateMultiplier(multiplier: FfiConverterUInt64.read(from: &buf) + ) default: throw UniffiInternalError.unexpectedEnumCase } @@ -9000,7 +8970,8 @@ extension NodeError: Foundation.LocalizedError { // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum OfferAmount { - case bitcoin(amountMsats: UInt64) + case bitcoin(amountMsats: UInt64 + ) case currency(iso4217Code: String, amount: UInt64) } @@ -9013,7 +8984,8 @@ public struct FfiConverterTypeOfferAmount: FfiConverterRustBuffer { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> OfferAmount { let variant: Int32 = try readInt(&buf) switch variant { - case 1: return try .bitcoin(amountMsats: FfiConverterUInt64.read(from: &buf)) + case 1: return try .bitcoin(amountMsats: FfiConverterUInt64.read(from: &buf) + ) case 2: return try .currency(iso4217Code: FfiConverterString.read(from: &buf), amount: FfiConverterUInt64.read(from: &buf)) @@ -9437,9 +9409,12 @@ extension PendingSweepBalance: Equatable, Hashable {} // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum QrPaymentResult { - case onchain(txid: Txid) - case bolt11(paymentId: PaymentId) - case bolt12(paymentId: PaymentId) + case onchain(txid: Txid + ) + case bolt11(paymentId: PaymentId + ) + case bolt12(paymentId: PaymentId + ) } #if swift(>=5.8) @@ -9451,11 +9426,14 @@ public struct FfiConverterTypeQrPaymentResult: FfiConverterRustBuffer { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> QrPaymentResult { let variant: Int32 = try readInt(&buf) switch variant { - case 1: return try .onchain(txid: FfiConverterTypeTxid.read(from: &buf)) + case 1: return try .onchain(txid: FfiConverterTypeTxid.read(from: &buf) + ) - case 2: return try .bolt11(paymentId: FfiConverterTypePaymentId.read(from: &buf)) + case 2: return try .bolt11(paymentId: FfiConverterTypePaymentId.read(from: &buf) + ) - case 3: return try .bolt12(paymentId: FfiConverterTypePaymentId.read(from: &buf)) + case 3: return try .bolt12(paymentId: FfiConverterTypePaymentId.read(from: &buf) + ) default: throw UniffiInternalError.unexpectedEnumCase } @@ -12090,8 +12068,8 @@ private func uniffiRustCallAsync( )) } -/// Callback handlers for an async calls. These are invoked by Rust when the future is ready. They -/// lift the return value or error and resume the suspended function. +// Callback handlers for an async calls. These are invoked by Rust when the future is ready. They +// lift the return value or error and resume the suspended function. private func uniffiFutureContinuationCallback(handle: UInt64, pollResult: Int8) { if let continuation = try? uniffiContinuationHandleMap.remove(handle: handle) { continuation.resume(returning: pollResult) @@ -12102,13 +12080,15 @@ private func uniffiFutureContinuationCallback(handle: UInt64, pollResult: Int8) public func batterySavingSyncIntervals() -> RuntimeSyncIntervals { return try! FfiConverterTypeRuntimeSyncIntervals.lift(try! rustCall { - uniffi_ldk_node_fn_func_battery_saving_sync_intervals($0) + uniffi_ldk_node_fn_func_battery_saving_sync_intervals($0 + ) }) } public func defaultConfig() -> Config { return try! FfiConverterTypeConfig.lift(try! rustCall { - uniffi_ldk_node_fn_func_default_config($0) + uniffi_ldk_node_fn_func_default_config($0 + ) }) } @@ -12135,8 +12115,8 @@ private enum InitializationResult { case apiChecksumMismatch } -/// Use a global variable to perform the versioning checks. Swift ensures that -/// the code inside is only computed once. +// Use a global variable to perform the versioning checks. Swift ensures that +// the code inside is only computed once. private var initializationResult: InitializationResult = { // Get the bindings contract version from our ComponentInterface let bindings_contract_version = 26 diff --git a/crates/bdk-wallet-aggregate/src/lib.rs b/crates/bdk-wallet-aggregate/src/lib.rs index 5d6e2d110..fb10611c4 100644 --- a/crates/bdk-wallet-aggregate/src/lib.rs +++ b/crates/bdk-wallet-aggregate/src/lib.rs @@ -414,6 +414,19 @@ where Ok(()) } + /// Cancel a dry-run transaction on the primary wallet without persisting. + /// + /// Unmarks change addresses that were marked "used" by `finish()`, so + /// the next `finish()` reuses them instead of revealing new ones. The + /// reveal itself is left in the staged changeset and persists harmlessly. + /// + /// Only targets the primary wallet. All current build paths use the primary. + pub fn cancel_dry_run_tx(&mut self, tx: &Transaction) { + let primary = + self.wallets.get_mut(&self.primary).expect("Primary wallet must always exist"); + primary.cancel_tx(tx); + } + // ─── Fee Calculation ──────────────────────────────────────────────── /// Calculate the fee of a PSBT by summing input values and subtracting @@ -1346,3 +1359,277 @@ where self.wallets.values().any(|w| w.is_mine(script_pubkey.clone())) } } + +#[cfg(test)] +mod tests { + use bdk_wallet::template::Bip84; + use bdk_wallet::{ChangeSet, KeychainKind, PersistedWallet, Wallet, WalletPersister}; + use bitcoin::bip32::Xpriv; + use bitcoin::{Amount, FeeRate, Network, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Txid}; + + use super::*; + + struct NoopPersister; + + impl WalletPersister for NoopPersister { + type Error = std::convert::Infallible; + + fn initialize(_: &mut Self) -> Result { + Ok(ChangeSet::default()) + } + + fn persist(_: &mut Self, _: &ChangeSet) -> Result<(), Self::Error> { + Ok(()) + } + } + + fn test_xprv() -> Xpriv { + Xpriv::new_master(Network::Regtest, &[0x42; 32]).unwrap() + } + + fn create_funded_wallet( + persister: &mut NoopPersister, amount: Amount, + ) -> PersistedWallet { + let xprv = test_xprv(); + let mut wallet = PersistedWallet::create( + persister, + Wallet::create( + Bip84(xprv, KeychainKind::External), + Bip84(xprv, KeychainKind::Internal), + ) + .network(Network::Regtest), + ) + .unwrap(); + + let addr = wallet.reveal_next_address(KeychainKind::External); + let funding_tx = Transaction { + version: bitcoin::transaction::Version::TWO, + lock_time: bitcoin::blockdata::locktime::absolute::LockTime::ZERO, + input: vec![TxIn { + previous_output: OutPoint { txid: Txid::from_byte_array([0x01; 32]), vout: 0 }, + ..Default::default() + }], + output: vec![TxOut { value: amount, script_pubkey: addr.address.script_pubkey() }], + }; + wallet.apply_unconfirmed_txs([(funding_tx, 0)]); + wallet + } + + fn recipient_script() -> ScriptBuf { + ScriptBuf::new_p2wpkh(&bitcoin::WPubkeyHash::from_byte_array([0xab; 20])) + } + + /// Demonstrates the bug: without cancel_tx, each finish() call + /// cumulatively advances the internal (change) derivation index. + #[test] + fn test_finish_without_cancel_leaks_change_index() { + let mut persister = NoopPersister; + let mut wallet = create_funded_wallet(&mut persister, Amount::from_sat(100_000)); + + let recipient = recipient_script(); + let fee_rate = FeeRate::from_sat_per_vb(2).unwrap(); + + let initial_idx = wallet.derivation_index(KeychainKind::Internal); + + // First dry-run finish(), no cancel + let mut b1 = wallet.build_tx(); + b1.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + let _psbt1 = b1.finish().unwrap(); + let after_first = wallet.derivation_index(KeychainKind::Internal); + + // Second dry-run finish(), no cancel + let mut b2 = wallet.build_tx(); + b2.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + let _psbt2 = b2.finish().unwrap(); + let after_second = wallet.derivation_index(KeychainKind::Internal); + + // Third dry-run finish(), no cancel + let mut b3 = wallet.build_tx(); + b3.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + let _psbt3 = b3.finish().unwrap(); + let after_third = wallet.derivation_index(KeychainKind::Internal); + + assert!( + after_first > initial_idx || (initial_idx.is_none() && after_first.is_some()), + "First finish() should advance the internal index" + ); + assert!( + after_second > after_first, + "Second finish() without cancel should advance further: {:?} > {:?}", + after_second, + after_first, + ); + assert!( + after_third > after_second, + "Third finish() without cancel should advance further: {:?} > {:?}", + after_third, + after_second, + ); + } + + /// Demonstrates the fix: cancel_dry_run_tx unmarks the change address, + /// so subsequent finish() calls reuse the same index. + #[test] + fn test_cancel_dry_run_prevents_cumulative_index_leak() { + let mut persister = NoopPersister; + let wallet = create_funded_wallet(&mut persister, Amount::from_sat(100_000)); + let mut agg = AggregateWallet::::new(wallet, persister, 0, vec![]); + + let recipient = recipient_script(); + let fee_rate = FeeRate::from_sat_per_vb(2).unwrap(); + + let initial_idx = agg.derivation_index(KeychainKind::Internal); + + // Dry-run 1: finish + cancel + let psbt1 = { + let w = agg.primary_wallet_mut(); + let mut b = w.build_tx(); + b.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + b.finish().unwrap() + }; + agg.cancel_dry_run_tx(&psbt1.unsigned_tx); + let after_first = agg.derivation_index(KeychainKind::Internal); + + assert!( + after_first > initial_idx || (initial_idx.is_none() && after_first.is_some()), + "First finish() should reveal an internal address" + ); + + // Dry-run 2: finish + cancel + let psbt2 = { + let w = agg.primary_wallet_mut(); + let mut b = w.build_tx(); + b.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + b.finish().unwrap() + }; + agg.cancel_dry_run_tx(&psbt2.unsigned_tx); + let after_second = agg.derivation_index(KeychainKind::Internal); + + assert_eq!( + after_first, after_second, + "cancel_dry_run_tx should prevent cumulative index advance" + ); + + // Dry-runs 3-5: confirm stability + for i in 3..=5 { + let psbt = { + let w = agg.primary_wallet_mut(); + let mut b = w.build_tx(); + b.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + b.finish().unwrap() + }; + agg.cancel_dry_run_tx(&psbt.unsigned_tx); + let idx = agg.derivation_index(KeychainKind::Internal); + assert_eq!(after_first, idx, "Dry-run {} should still reuse the same index", i); + } + } + + /// Verifies that cancel_dry_run_tx prevents index leak even when an + /// intermediate operation fails between finish() and the cancel. + #[test] + fn test_cancel_after_failed_intermediate_prevents_leak() { + let mut persister = NoopPersister; + let wallet = create_funded_wallet(&mut persister, Amount::from_sat(100_000)); + let mut agg = AggregateWallet::::new(wallet, persister, 0, vec![]); + + let recipient = recipient_script(); + let fee_rate = FeeRate::from_sat_per_vb(2).unwrap(); + + // Baseline + let initial_idx = agg.derivation_index(KeychainKind::Internal); + + // Simulate finish() + failed intermediate + unconditional cancel. + for _ in 0..5 { + let psbt = { + let w = agg.primary_wallet_mut(); + let mut b = w.build_tx(); + b.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + b.finish().unwrap() + }; + + // Simulate an intermediate operation that fails. + let _simulated_failure: Result = Err("simulated fee calculation failure"); + + // Cancel regardless of failure. + agg.cancel_dry_run_tx(&psbt.unsigned_tx); + } + + let final_idx = agg.derivation_index(KeychainKind::Internal); + + assert!( + final_idx > initial_idx || (initial_idx.is_none() && final_idx.is_some()), + "Index should be revealed at least once" + ); + + // One more dry-run + cancel should not change it. + let psbt = { + let w = agg.primary_wallet_mut(); + let mut b = w.build_tx(); + b.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + b.finish().unwrap() + }; + agg.cancel_dry_run_tx(&psbt.unsigned_tx); + assert_eq!( + final_idx, + agg.derivation_index(KeychainKind::Internal), + "Sixth dry-run should still reuse the same index" + ); + } + + /// After a cancelled dry-run, the next real finish() reuses the same + /// change address. Verifies the fix doesn't break real transactions. + #[test] + fn test_dry_run_cancel_then_real_tx_reuses_change_address() { + let mut persister = NoopPersister; + let wallet = create_funded_wallet(&mut persister, Amount::from_sat(200_000)); + let mut agg = AggregateWallet::::new(wallet, persister, 0, vec![]); + + let recipient = recipient_script(); + let fee_rate = FeeRate::from_sat_per_vb(2).unwrap(); + + // Dry-run + cancel + let dry_psbt = { + let w = agg.primary_wallet_mut(); + let mut b = w.build_tx(); + b.add_recipient(recipient.clone(), Amount::from_sat(50_000)).fee_rate(fee_rate); + b.finish().unwrap() + }; + let dry_run_change_script: Option = dry_psbt + .unsigned_tx + .output + .iter() + .find(|o| agg.is_mine(o.script_pubkey.clone())) + .map(|o| o.script_pubkey.clone()); + agg.cancel_dry_run_tx(&dry_psbt.unsigned_tx); + + let idx_after_dry = agg.derivation_index(KeychainKind::Internal); + + // Real tx (no cancel — this would be signed and broadcast) + let real_psbt = { + let w = agg.primary_wallet_mut(); + let mut b = w.build_tx(); + b.add_recipient(recipient.clone(), Amount::from_sat(50_000)).fee_rate(fee_rate); + b.finish().unwrap() + }; + let real_change_script: Option = real_psbt + .unsigned_tx + .output + .iter() + .find(|o| agg.is_mine(o.script_pubkey.clone())) + .map(|o| o.script_pubkey.clone()); + + let idx_after_real = agg.derivation_index(KeychainKind::Internal); + + assert_eq!( + idx_after_dry, idx_after_real, + "Real tx should not advance index beyond what dry-run already revealed" + ); + if let (Some(dry_change), Some(real_change)) = (&dry_run_change_script, &real_change_script) + { + assert_eq!( + dry_change, real_change, + "Real tx should reuse the same change address as the cancelled dry-run" + ); + } + } +} diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 0ca364f90..49928f0be 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -1075,7 +1075,12 @@ impl Wallet { } }; - let base_fee = primary.calculate_fee(&tmp_tx).map_err(|e| { + let fee_result = primary.calculate_fee(&tmp_tx); + + // Cancel the temp tx to free up the change address. + primary.cancel_tx(&tmp_tx); + + let base_fee = fee_result.map_err(|e| { log_error!( self.logger, "Failed to calculate fee of temporary transaction: {}", @@ -1084,9 +1089,6 @@ impl Wallet { e })?; - // 'cancel' the transaction to free up any used change addresses - primary.cancel_tx(&tmp_tx); - // Adjust the fee estimate for non-primary inputs that will be // added to the actual tx (the temp tx only used primary UTXOs). let extra_input_weight: u64 = non_primary_utxo_infos @@ -1184,21 +1186,26 @@ impl Wallet { }; // Check the reserve requirements (again) and return an error if they aren't met. + // Cancel the PSBT before each early return to free up the change address. match send_amount { OnchainSendAmount::ExactRetainingReserve { amount_sats, cur_anchor_reserve_sats } => { let spendable_amount_sats = self .get_balances_inner(&aggregate_balance, cur_anchor_reserve_sats) .map(|(_, s)| s) .unwrap_or(0); - let tx_fee_sats = - locked_wallet.calculate_fee_with_fallback(&psbt).map_err(|e| { + let fee_result = locked_wallet.calculate_fee_with_fallback(&psbt); + let tx_fee_sats = match fee_result { + Ok(fee) => fee, + Err(e) => { log_error!( self.logger, "Failed to calculate fee of candidate transaction: {}", e ); - Error::WalletOperationFailed - })?; + locked_wallet.cancel_dry_run_tx(&psbt.unsigned_tx); + return Err(Error::WalletOperationFailed); + }, + }; if spendable_amount_sats < amount_sats.saturating_add(tx_fee_sats) { log_error!(self.logger, "Unable to send payment due to insufficient funds. Available: {}sats, Required: {}sats + {}sats fee", @@ -1206,6 +1213,7 @@ impl Wallet { amount_sats, tx_fee_sats, ); + locked_wallet.cancel_dry_run_tx(&psbt.unsigned_tx); return Err(Error::InsufficientFunds); } }, @@ -1221,6 +1229,7 @@ impl Wallet { spendable_amount_sats, drain_amount, ); + locked_wallet.cancel_dry_run_tx(&psbt.unsigned_tx); return Err(Error::InsufficientFunds); } }, @@ -1241,7 +1250,7 @@ impl Wallet { let fee_rate = fee_rate.unwrap_or_else(|| self.fee_estimator.estimate_fee_rate(confirmation_target)); - let (psbt, locked_wallet) = self.build_transaction_psbt( + let (psbt, mut locked_wallet) = self.build_transaction_psbt( address, send_amount, fee_rate, @@ -1249,7 +1258,12 @@ impl Wallet { channel_manager, )?; - let calculated_fee = locked_wallet.calculate_fee_with_fallback(&psbt).map_err(|e| { + let fee_result = locked_wallet.calculate_fee_with_fallback(&psbt); + + // Cancel the dry-run PSBT to free up the change address. + locked_wallet.cancel_dry_run_tx(&psbt.unsigned_tx); + + let calculated_fee = fee_result.map_err(|e| { log_error!(self.logger, "Failed to calculate transaction fee: {}", e); Error::WalletOperationFailed })?; @@ -1388,11 +1402,11 @@ impl Wallet { tx_builder.fee_rate(fee_rate); tx_builder.exclude_unconfirmed(); - tx_builder - .finish() - .map_err(|e| { - log_error!(self.logger, "Failed to select confirmed UTXOs: {}", e); - })? + let psbt = tx_builder.finish().map_err(|e| { + log_error!(self.logger, "Failed to select confirmed UTXOs: {}", e); + })?; + + let result = psbt .unsigned_tx .input .iter() @@ -1403,7 +1417,12 @@ impl Wallet { .map(|tx_details| tx_details.tx.deref().clone()) .map(|prevtx| FundingTxInput::new_p2wpkh(prevtx, txin.previous_output.vout)) }) - .collect::, ()>>() + .collect::, ()>>(); + + // Cancel the dry-run PSBT to free up the change address. + locked_wallet.cancel_dry_run_tx(&psbt.unsigned_tx); + + result } fn list_confirmed_utxos_inner(&self) -> Result, ()> {