From 38403e00b4c786cd6d866827a26934d99d9a574c Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Mon, 22 Nov 2021 14:17:03 -0800 Subject: [PATCH 01/33] Initial Commit --- .gitignore | 13 + .gitmodules | 3 + Package.swift | 36 + README.md | 3 + Sources/BitcoinDevKit/BitcoinDevKit.swift | 2113 +++++++++++++++++ .../BitcoinDevKitTests.swift | 12 + bdk-ffi | 1 + build.sh | 73 + 8 files changed, 2254 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 Package.swift create mode 100644 README.md create mode 100644 Sources/BitcoinDevKit/BitcoinDevKit.swift create mode 100644 Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift create mode 160000 bdk-ffi create mode 100755 build.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b18ca41 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.DS_Store +/.build +/.swiftpm +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +/*.xcframework +!bdkFFI-umbrella.h +!module.modulemap +!info.plist +*.xcframework.zip diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..9c7f2ac --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "bdk-ffi"] + path = bdk-ffi + url = git@github.com:bitcoindevkit/bdk-ffi.git diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..485d25e --- /dev/null +++ b/Package.swift @@ -0,0 +1,36 @@ +// swift-tools-version:5.5 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "bdk-swift", + platforms: [ + .macOS(.v12), + .iOS(.v15) + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "BitcoinDevKit", + targets: ["bdkFFI", "BitcoinDevKit"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + // .package(url: /* package url */, from: "1.0.0"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .binaryTarget( + name: "bdkFFI", + url: "https://github.com/notmandatory/bdk-swift/releases/download/0.1.0/bdkFFI.xcframework.zip", + checksum: "b34dc1dea2e53bc894f1ad61269e45de6c77dd6391bbb1318cfb0be17435c4db"), + .target( + name: "BitcoinDevKit", + dependencies: ["bdkFFI"]), + .testTarget( + name: "BitcoinDevKitTests", + dependencies: ["BitcoinDevKit"]), + ] +) diff --git a/README.md b/README.md new file mode 100644 index 0000000..c49608d --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# bdk-swift + +A description of this package. diff --git a/Sources/BitcoinDevKit/BitcoinDevKit.swift b/Sources/BitcoinDevKit/BitcoinDevKit.swift new file mode 100644 index 0000000..1c9432e --- /dev/null +++ b/Sources/BitcoinDevKit/BitcoinDevKit.swift @@ -0,0 +1,2113 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! +import Foundation + +// Depending on the consumer's build setup, the low-level FFI code +// might be in a separate module, or it might be compiled inline into +// this module. This is a bit of light hackery to work with both. +#if canImport(bdkFFI) +import bdkFFI +#endif + +fileprivate extension RustBuffer { + // Allocate a new buffer, copying the contents of a `UInt8` array. + init(bytes: [UInt8]) { + let rbuf = bytes.withUnsafeBufferPointer { ptr in + RustBuffer.from(ptr) + } + self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) + } + + static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { + try! rustCall { ffi_bdk_2e4d_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } + } + + // Frees the buffer in place. + // The buffer must not be used after this is called. + func deallocate() { + try! rustCall { ffi_bdk_2e4d_rustbuffer_free(self, $0) } + } +} + +fileprivate extension ForeignBytes { + init(bufferPointer: UnsafeBufferPointer) { + self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) + } +} + +// For every type used in the interface, we provide helper methods for conveniently +// lifting and lowering that type from C-compatible data, and for reading and writing +// values of that type in a buffer. + +// Helper classes/extensions that don't change. +// Someday, this will be in a libray of its own. + +fileprivate extension Data { + init(rustBuffer: RustBuffer) { + // TODO: This copies the buffer. Can we read directly from a + // Rust buffer? + self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len)) + } +} + +// A helper class to read values out of a byte buffer. +fileprivate class Reader { + let data: Data + var offset: Data.Index + + init(data: Data) { + self.data = data + self.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. + func readInt() throws -> T { + let range = offset...size + guard data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + if T.self == UInt8.self { + let value = data[offset] + offset += 1 + return value as! T + } + var value: T = 0 + let _ = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0, from: range)}) + offset = range.upperBound + return value.bigEndian + } + + // Reads an arbitrary number of bytes, to be used to read + // raw bytes, this is useful when lifting strings + func readBytes(count: Int) throws -> Array { + let range = offset..<(offset+count) + guard data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + var value = [UInt8](repeating: 0, count: count) + value.withUnsafeMutableBufferPointer({ buffer in + data.copyBytes(to: buffer, from: range) + }) + offset = range.upperBound + return value + } + + // Reads a float at the current offset. + @inlinable + func readFloat() throws -> Float { + return Float(bitPattern: try readInt()) + } + + // Reads a float at the current offset. + @inlinable + func readDouble() throws -> Double { + return Double(bitPattern: try readInt()) + } + + // Indicates if the offset has reached the end of the buffer. + @inlinable + func hasRemaining() -> Bool { + return offset < data.count + } +} + +// A helper class to write values into a byte buffer. +fileprivate class Writer { + var bytes: [UInt8] + var offset: Array.Index + + init() { + self.bytes = [] + self.offset = 0 + } + + func writeBytes(_ byteArr: S) where S: Sequence, S.Element == UInt8 { + bytes.append(contentsOf: byteArr) + } + + // Writes an integer in big-endian order. + // + // Warning: make sure what you are trying to write + // is in the correct type! + func writeInt(_ value: T) { + var value = value.bigEndian + withUnsafeBytes(of: &value) { bytes.append(contentsOf: $0) } + } + + @inlinable + func writeFloat(_ value: Float) { + writeInt(value.bitPattern) + } + + @inlinable + func writeDouble(_ value: Double) { + writeInt(value.bitPattern) + } +} + + +// Types conforming to `Serializable` can be read and written in a bytebuffer. +fileprivate protocol Serializable { + func write(into: Writer) + static func read(from: Reader) throws -> Self +} + +// Types confirming to `ViaFfi` can be transferred back-and-for over the FFI. +// This is analogous to the Rust trait of the same name. +fileprivate protocol ViaFfi: Serializable { + associatedtype FfiType + static func lift(_ v: FfiType) throws -> Self + func lower() -> FfiType +} + +// Types conforming to `Primitive` pass themselves directly over the FFI. +fileprivate protocol Primitive {} + +extension Primitive { + fileprivate typealias FfiType = Self + + fileprivate static func lift(_ v: Self) throws -> Self { + return v + } + + fileprivate func lower() -> Self { + return self + } +} + +// Types conforming to `ViaFfiUsingByteBuffer` lift and lower into a bytebuffer. +// Use this for complex types where it's hard to write a custom lift/lower. +fileprivate protocol ViaFfiUsingByteBuffer: Serializable {} + +extension ViaFfiUsingByteBuffer { + fileprivate typealias FfiType = RustBuffer + + fileprivate static func lift(_ buf: FfiType) throws -> Self { + let reader = Reader(data: Data(rustBuffer: buf)) + let value = try Self.read(from: reader) + if reader.hasRemaining() { + throw UniffiInternalError.incompleteData + } + buf.deallocate() + return value + } + + fileprivate func lower() -> FfiType { + let writer = Writer() + self.write(into: writer) + return RustBuffer(bytes: writer.bytes) + } +} +// An error type for FFI errors. These errors occur at the UniFFI level, not +// the library level. +fileprivate enum UniffiInternalError: LocalizedError { + case bufferOverflow + case incompleteData + case unexpectedOptionalTag + case unexpectedEnumCase + case unexpectedNullPointer + case unexpectedRustCallStatusCode + case unexpectedRustCallError + case unexpectedStaleHandle + case rustPanic(_ message: String) + + public var errorDescription: String? { + switch self { + case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" + case .incompleteData: return "The buffer still has data after lifting its containing value" + case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1" + case .unexpectedEnumCase: return "Raw enum value doesn't match any cases" + case .unexpectedNullPointer: return "Raw pointer value was null" + case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code" + case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified" + case .unexpectedStaleHandle: return "The object in the handle map has been dropped already" + case let .rustPanic(message): return message + } + } +} + +fileprivate let CALL_SUCCESS: Int8 = 0 +fileprivate let CALL_ERROR: Int8 = 1 +fileprivate let CALL_PANIC: Int8 = 2 + +fileprivate extension RustCallStatus { + init() { + self.init( + code: CALL_SUCCESS, + errorBuf: RustBuffer.init( + capacity: 0, + len: 0, + data: nil + ) + ) + } +} + +private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T { + try makeRustCall(callback, errorHandler: { + $0.deallocate() + return UniffiInternalError.unexpectedRustCallError + }) +} + +private func rustCallWithError(_ errorClass: E.Type, _ callback: (UnsafeMutablePointer) -> T) throws -> T { + try makeRustCall(callback, errorHandler: { return try E.lift($0) }) +} + +private func makeRustCall(_ callback: (UnsafeMutablePointer) -> T, errorHandler: (RustBuffer) throws -> Error) throws -> T { + var callStatus = RustCallStatus.init() + let returnedVal = callback(&callStatus) + switch callStatus.code { + case CALL_SUCCESS: + return returnedVal + + case CALL_ERROR: + throw try errorHandler(callStatus.errorBuf) + + case CALL_PANIC: + // When the rust code sees a panic, it tries to construct a RustBuffer + // with the message. But if that code panics, then it just sends back + // an empty buffer. + if callStatus.errorBuf.len > 0 { + throw UniffiInternalError.rustPanic(try String.lift(callStatus.errorBuf)) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.rustPanic("Rust panic") + } + + default: + throw UniffiInternalError.unexpectedRustCallStatusCode + } +} +// Protocols for converters we'll implement in templates + +fileprivate protocol FfiConverter { + associatedtype SwiftType + associatedtype FfiType + + static func lift(_ ffiValue: FfiType) throws -> SwiftType + static func lower(_ value: SwiftType) -> FfiType + + static func read(from: Reader) throws -> SwiftType + static func write(_ value: SwiftType, into: Writer) +} + +fileprivate protocol FfiConverterUsingByteBuffer: FfiConverter where FfiType == RustBuffer { + // Empty, because we want to declare some helper methods in the extension below. +} + +extension FfiConverterUsingByteBuffer { + static func lower(_ value: SwiftType) -> FfiType { + let writer = Writer() + Self.write(value, into: writer) + return RustBuffer(bytes: writer.bytes) + } + + static func lift(_ buf: FfiType) throws -> SwiftType { + let reader = Reader(data: Data(rustBuffer: buf)) + let value = try Self.read(from: reader) + if reader.hasRemaining() { + throw UniffiInternalError.incompleteData + } + buf.deallocate() + return value + } +} + +// Helpers for structural types. Note that because of canonical_names, it /should/ be impossible +// to make another `FfiConverterSequence` etc just using the UDL. +fileprivate enum FfiConverterSequence { + static func write(_ value: [T], into buf: Writer, writeItem: (T, Writer) -> Void) { + let len = Int32(value.count) + buf.writeInt(len) + for item in value { + writeItem(item, buf) + } + } + + static func read(from buf: Reader, readItem: (Reader) throws -> T) throws -> [T] { + let len: Int32 = try buf.readInt() + var seq = [T]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try readItem(buf)) + } + return seq + } +} + +fileprivate enum FfiConverterOptional { + static func write(_ value: T?, into buf: Writer, writeItem: (T, Writer) -> Void) { + guard let value = value else { + buf.writeInt(Int8(0)) + return + } + buf.writeInt(Int8(1)) + writeItem(value, buf) + } + + static func read(from buf: Reader, readItem: (Reader) throws -> T) throws -> T? { + switch try buf.readInt() as Int8 { + case 0: return nil + case 1: return try readItem(buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate enum FfiConverterDictionary { + static func write(_ value: [String: T], into buf: Writer, writeItem: (String, T, Writer) -> Void) { + let len = Int32(value.count) + buf.writeInt(len) + for (key, value) in value { + writeItem(key, value, buf) + } + } + + static func read(from buf: Reader, readItem: (Reader) throws -> (String, T)) throws -> [String: T] { + let len: Int32 = try buf.readInt() + var dict = [String: T]() + dict.reserveCapacity(Int(len)) + for _ in 0..(f: () throws -> T) rethrows -> T { + self.lock() + defer { self.unlock() } + return try f() + } +} + +fileprivate typealias Handle = UInt64 +fileprivate class ConcurrentHandleMap { + private var leftMap: [Handle: T] = [:] + private var counter: [Handle: UInt64] = [:] + private var rightMap: [ObjectIdentifier: Handle] = [:] + + private let lock = NSLock() + private var currentHandle: Handle = 0 + private let stride: Handle = 1 + + func insert(obj: T) -> Handle { + lock.withLock { + let id = ObjectIdentifier(obj as AnyObject) + let handle = rightMap[id] ?? { + currentHandle += stride + let handle = currentHandle + leftMap[handle] = obj + rightMap[id] = handle + return handle + }() + counter[handle] = (counter[handle] ?? 0) + 1 + return handle + } + } + + func get(handle: Handle) -> T? { + lock.withLock { + leftMap[handle] + } + } + + func delete(handle: Handle) { + remove(handle: handle) + } + + @discardableResult + func remove(handle: Handle) -> T? { + lock.withLock { + defer { counter[handle] = (counter[handle] ?? 1) - 1 } + guard counter[handle] == 1 else { return leftMap[handle] } + let obj = leftMap.removeValue(forKey: handle) + if let obj = obj { + rightMap.removeValue(forKey: ObjectIdentifier(obj as AnyObject)) + } + return obj + } + } +} + +// 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 + +fileprivate class FfiConverterCallbackInterface { + fileprivate let handleMap = ConcurrentHandleMap() + + func drop(handle: Handle) { + handleMap.remove(handle: handle) + } + + func lift(_ handle: Handle) throws -> CallbackInterface { + guard let callback = handleMap.get(handle: handle) else { + throw UniffiInternalError.unexpectedStaleHandle + } + return callback + } + + func read(from buf: Reader) throws -> CallbackInterface { + let handle: Handle = try buf.readInt() + return try lift(handle) + } + + func lower(_ v: CallbackInterface) -> Handle { + let handle = handleMap.insert(obj: v) + return handle + // assert(handleMap.get(handle: obj) == v, "Handle map is not returning the object we just placed there. This is a bug in the HandleMap.") + } + + func write(_ v: CallbackInterface, into buf: Writer) { + buf.writeInt(lower(v)) + } +} + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum Network { + + case bitcoin + case testnet + case signet + case regtest +} + +extension Network: ViaFfiUsingByteBuffer, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> Network { + let variant: Int32 = try buf.readInt() + switch variant { + + case 1: return .bitcoin + case 2: return .testnet + case 3: return .signet + case 4: return .regtest + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + fileprivate func write(into buf: Writer) { + switch self { + + + case .bitcoin: + buf.writeInt(Int32(1)) + + + case .testnet: + buf.writeInt(Int32(2)) + + + case .signet: + buf.writeInt(Int32(3)) + + + case .regtest: + buf.writeInt(Int32(4)) + + } + } +} + + +extension Network: Equatable, Hashable {} + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum DatabaseConfig { + + case memory(junk: String ) + case sled(config: SledDbConfiguration ) +} + +extension DatabaseConfig: ViaFfiUsingByteBuffer, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> DatabaseConfig { + let variant: Int32 = try buf.readInt() + switch variant { + + case 1: return .memory( + junk: try String.read(from: buf) + ) + case 2: return .sled( + config: try SledDbConfiguration.read(from: buf) + ) + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + fileprivate func write(into buf: Writer) { + switch self { + + + case let .memory(junk): + buf.writeInt(Int32(1)) + junk.write(into: buf) + + + + case let .sled(config): + buf.writeInt(Int32(2)) + config.write(into: buf) + + + } + } +} + + +extension DatabaseConfig: Equatable, Hashable {} + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum Transaction { + + case unconfirmed(details: TransactionDetails ) + case confirmed(details: TransactionDetails, confirmation: Confirmation ) +} + +extension Transaction: ViaFfiUsingByteBuffer, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> Transaction { + let variant: Int32 = try buf.readInt() + switch variant { + + case 1: return .unconfirmed( + details: try TransactionDetails.read(from: buf) + ) + case 2: return .confirmed( + details: try TransactionDetails.read(from: buf), + confirmation: try Confirmation.read(from: buf) + ) + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + fileprivate func write(into buf: Writer) { + switch self { + + + case let .unconfirmed(details): + buf.writeInt(Int32(1)) + details.write(into: buf) + + + + case let .confirmed(details,confirmation): + buf.writeInt(Int32(2)) + details.write(into: buf) + confirmation.write(into: buf) + + + } + } +} + + +extension Transaction: Equatable, Hashable {} + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum BlockchainConfig { + + case electrum(config: ElectrumConfig ) + case esplora(config: EsploraConfig ) +} + +extension BlockchainConfig: ViaFfiUsingByteBuffer, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> BlockchainConfig { + let variant: Int32 = try buf.readInt() + switch variant { + + case 1: return .electrum( + config: try ElectrumConfig.read(from: buf) + ) + case 2: return .esplora( + config: try EsploraConfig.read(from: buf) + ) + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + fileprivate func write(into buf: Writer) { + switch self { + + + case let .electrum(config): + buf.writeInt(Int32(1)) + config.write(into: buf) + + + + case let .esplora(config): + buf.writeInt(Int32(2)) + config.write(into: buf) + + + } + } +} + + +extension BlockchainConfig: Equatable, Hashable {} + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum MnemonicType { + + case words12 + case words15 + case words18 + case words21 + case words24 +} + +extension MnemonicType: ViaFfiUsingByteBuffer, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> MnemonicType { + let variant: Int32 = try buf.readInt() + switch variant { + + case 1: return .words12 + case 2: return .words15 + case 3: return .words18 + case 4: return .words21 + case 5: return .words24 + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + fileprivate func write(into buf: Writer) { + switch self { + + + case .words12: + buf.writeInt(Int32(1)) + + + case .words15: + buf.writeInt(Int32(2)) + + + case .words18: + buf.writeInt(Int32(3)) + + + case .words21: + buf.writeInt(Int32(4)) + + + case .words24: + buf.writeInt(Int32(5)) + + } + } +} + + +extension MnemonicType: Equatable, Hashable {} + + + +public func generateExtendedKey(network: Network, mnemonicType: MnemonicType, password: String? ) throws -> ExtendedKeyInfo { + let _retval = try + + + rustCallWithError(BdkError.self) { + + bdk_2e4d_generate_extended_key(network.lower(), mnemonicType.lower(), FfiConverterOptionString.lower(password) , $0) +} + return try ExtendedKeyInfo.lift(_retval) +} + + + +public func restoreExtendedKey(network: Network, mnemonic: String, password: String? ) throws -> ExtendedKeyInfo { + let _retval = try + + + rustCallWithError(BdkError.self) { + + bdk_2e4d_restore_extended_key(network.lower(), mnemonic.lower(), FfiConverterOptionString.lower(password) , $0) +} + return try ExtendedKeyInfo.lift(_retval) +} + + + +public protocol OfflineWalletProtocol { + func getNewAddress() -> String + func getLastUnusedAddress() -> String + func getBalance() throws -> UInt64 + func sign(psbt: PartiallySignedBitcoinTransaction ) throws + func getTransactions() throws -> [Transaction] + +} + +public class OfflineWallet: OfflineWalletProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `ViaFfi` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(descriptor: String, network: Network, databaseConfig: DatabaseConfig ) throws { + self.init(unsafeFromRawPointer: try + + + rustCallWithError(BdkError.self) { + + bdk_2e4d_OfflineWallet_new(descriptor.lower(), network.lower(), databaseConfig.lower() , $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_2e4d_OfflineWallet_object_free(pointer, $0) } + } + + + + + public func getNewAddress() -> String { + let _retval = try! + rustCall() { + + bdk_2e4d_OfflineWallet_get_new_address(self.pointer, $0 + ) +} + return try! String.lift(_retval) + } + public func getLastUnusedAddress() -> String { + let _retval = try! + rustCall() { + + bdk_2e4d_OfflineWallet_get_last_unused_address(self.pointer, $0 + ) +} + return try! String.lift(_retval) + } + public func getBalance() throws -> UInt64 { + let _retval = try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OfflineWallet_get_balance(self.pointer, $0 + ) +} + return try UInt64.lift(_retval) + } + public func sign(psbt: PartiallySignedBitcoinTransaction ) throws { + try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OfflineWallet_sign(self.pointer, psbt.lower() , $0 + ) +} + } + public func getTransactions() throws -> [Transaction] { + let _retval = try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OfflineWallet_get_transactions(self.pointer, $0 + ) +} + return try FfiConverterSequenceEnumTransaction.lift(_retval) + } + +} + + +fileprivate extension OfflineWallet { + fileprivate typealias FfiType = UnsafeMutableRawPointer + + fileprivate static func read(from buf: Reader) throws -> Self { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try self.lift(ptr!) + } + + fileprivate func write(into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) + } + + fileprivate static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { + return Self(unsafeFromRawPointer: pointer) + } + + fileprivate func lower() -> UnsafeMutableRawPointer { + return self.pointer + } +} + +// Ideally this would be `fileprivate`, but Swift says: +// """ +// 'private' modifier cannot be used with extensions that declare protocol conformances +// """ +extension OfflineWallet : ViaFfi, Serializable {} + + +public protocol OnlineWalletProtocol { + func getNewAddress() -> String + func getLastUnusedAddress() -> String + func getBalance() throws -> UInt64 + func sign(psbt: PartiallySignedBitcoinTransaction ) throws + func getTransactions() throws -> [Transaction] + func getNetwork() -> Network + func sync(progressUpdate: BdkProgress, maxAddressParam: UInt32? ) throws + func broadcast(psbt: PartiallySignedBitcoinTransaction ) throws -> Transaction + +} + +public class OnlineWallet: OnlineWalletProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `ViaFfi` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(descriptor: String, changeDescriptor: String?, network: Network, databaseConfig: DatabaseConfig, blockchainConfig: BlockchainConfig ) throws { + self.init(unsafeFromRawPointer: try + + + rustCallWithError(BdkError.self) { + + bdk_2e4d_OnlineWallet_new(descriptor.lower(), FfiConverterOptionString.lower(changeDescriptor), network.lower(), databaseConfig.lower(), blockchainConfig.lower() , $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_2e4d_OnlineWallet_object_free(pointer, $0) } + } + + + + + public func getNewAddress() -> String { + let _retval = try! + rustCall() { + + bdk_2e4d_OnlineWallet_get_new_address(self.pointer, $0 + ) +} + return try! String.lift(_retval) + } + public func getLastUnusedAddress() -> String { + let _retval = try! + rustCall() { + + bdk_2e4d_OnlineWallet_get_last_unused_address(self.pointer, $0 + ) +} + return try! String.lift(_retval) + } + public func getBalance() throws -> UInt64 { + let _retval = try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OnlineWallet_get_balance(self.pointer, $0 + ) +} + return try UInt64.lift(_retval) + } + public func sign(psbt: PartiallySignedBitcoinTransaction ) throws { + try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OnlineWallet_sign(self.pointer, psbt.lower() , $0 + ) +} + } + public func getTransactions() throws -> [Transaction] { + let _retval = try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OnlineWallet_get_transactions(self.pointer, $0 + ) +} + return try FfiConverterSequenceEnumTransaction.lift(_retval) + } + public func getNetwork() -> Network { + let _retval = try! + rustCall() { + + bdk_2e4d_OnlineWallet_get_network(self.pointer, $0 + ) +} + return try! Network.lift(_retval) + } + public func sync(progressUpdate: BdkProgress, maxAddressParam: UInt32? ) throws { + try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OnlineWallet_sync(self.pointer, ffiConverterCallbackInterfaceBdkProgress.lower(progressUpdate), FfiConverterOptionUInt32.lower(maxAddressParam) , $0 + ) +} + } + public func broadcast(psbt: PartiallySignedBitcoinTransaction ) throws -> Transaction { + let _retval = try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OnlineWallet_broadcast(self.pointer, psbt.lower() , $0 + ) +} + return try Transaction.lift(_retval) + } + +} + + +fileprivate extension OnlineWallet { + fileprivate typealias FfiType = UnsafeMutableRawPointer + + fileprivate static func read(from buf: Reader) throws -> Self { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try self.lift(ptr!) + } + + fileprivate func write(into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) + } + + fileprivate static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { + return Self(unsafeFromRawPointer: pointer) + } + + fileprivate func lower() -> UnsafeMutableRawPointer { + return self.pointer + } +} + +// Ideally this would be `fileprivate`, but Swift says: +// """ +// 'private' modifier cannot be used with extensions that declare protocol conformances +// """ +extension OnlineWallet : ViaFfi, Serializable {} + + +public protocol PartiallySignedBitcoinTransactionProtocol { + +} + +public class PartiallySignedBitcoinTransaction: PartiallySignedBitcoinTransactionProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `ViaFfi` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(wallet: OnlineWallet, recipient: String, amount: UInt64, feeRate: Float? ) throws { + self.init(unsafeFromRawPointer: try + + + rustCallWithError(BdkError.self) { + + bdk_2e4d_PartiallySignedBitcoinTransaction_new(wallet.lower(), recipient.lower(), amount.lower(), FfiConverterOptionFloat.lower(feeRate) , $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_2e4d_PartiallySignedBitcoinTransaction_object_free(pointer, $0) } + } + + + + + +} + + +fileprivate extension PartiallySignedBitcoinTransaction { + fileprivate typealias FfiType = UnsafeMutableRawPointer + + fileprivate static func read(from buf: Reader) throws -> Self { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try self.lift(ptr!) + } + + fileprivate func write(into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) + } + + fileprivate static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { + return Self(unsafeFromRawPointer: pointer) + } + + fileprivate func lower() -> UnsafeMutableRawPointer { + return self.pointer + } +} + +// Ideally this would be `fileprivate`, but Swift says: +// """ +// 'private' modifier cannot be used with extensions that declare protocol conformances +// """ +extension PartiallySignedBitcoinTransaction : ViaFfi, Serializable {} + +public struct SledDbConfiguration { + public var path: String + public var treeName: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(path: String, treeName: String ) { + self.path = path + self.treeName = treeName + } +} + + +extension SledDbConfiguration: Equatable, Hashable { + public static func ==(lhs: SledDbConfiguration, rhs: SledDbConfiguration) -> Bool { + if lhs.path != rhs.path { + return false + } + if lhs.treeName != rhs.treeName { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(path) + hasher.combine(treeName) + } +} + + +fileprivate extension SledDbConfiguration { + static func read(from buf: Reader) throws -> SledDbConfiguration { + return try SledDbConfiguration( + path: String.read(from: buf), + treeName: String.read(from: buf) + ) + } + + func write(into buf: Writer) { + self.path.write(into: buf) + self.treeName.write(into: buf) + } +} + +extension SledDbConfiguration: ViaFfiUsingByteBuffer, ViaFfi {} + +public struct TransactionDetails { + public var fees: UInt64? + public var received: UInt64 + public var sent: UInt64 + public var txid: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(fees: UInt64?, received: UInt64, sent: UInt64, txid: String ) { + self.fees = fees + self.received = received + self.sent = sent + self.txid = txid + } +} + + +extension TransactionDetails: Equatable, Hashable { + public static func ==(lhs: TransactionDetails, rhs: TransactionDetails) -> Bool { + if lhs.fees != rhs.fees { + return false + } + if lhs.received != rhs.received { + return false + } + if lhs.sent != rhs.sent { + return false + } + if lhs.txid != rhs.txid { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(fees) + hasher.combine(received) + hasher.combine(sent) + hasher.combine(txid) + } +} + + +fileprivate extension TransactionDetails { + static func read(from buf: Reader) throws -> TransactionDetails { + return try TransactionDetails( + fees: FfiConverterOptionUInt64.read(from: buf), + received: UInt64.read(from: buf), + sent: UInt64.read(from: buf), + txid: String.read(from: buf) + ) + } + + func write(into buf: Writer) { + FfiConverterOptionUInt64.write(self.fees, into: buf) + self.received.write(into: buf) + self.sent.write(into: buf) + self.txid.write(into: buf) + } +} + +extension TransactionDetails: ViaFfiUsingByteBuffer, ViaFfi {} + +public struct Confirmation { + public var height: UInt32 + public var timestamp: UInt64 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(height: UInt32, timestamp: UInt64 ) { + self.height = height + self.timestamp = timestamp + } +} + + +extension Confirmation: Equatable, Hashable { + public static func ==(lhs: Confirmation, rhs: Confirmation) -> Bool { + if lhs.height != rhs.height { + return false + } + if lhs.timestamp != rhs.timestamp { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(height) + hasher.combine(timestamp) + } +} + + +fileprivate extension Confirmation { + static func read(from buf: Reader) throws -> Confirmation { + return try Confirmation( + height: UInt32.read(from: buf), + timestamp: UInt64.read(from: buf) + ) + } + + func write(into buf: Writer) { + self.height.write(into: buf) + self.timestamp.write(into: buf) + } +} + +extension Confirmation: ViaFfiUsingByteBuffer, ViaFfi {} + +public struct ElectrumConfig { + public var url: String + public var socks5: String? + public var retry: UInt8 + public var timeout: UInt8? + public var stopGap: UInt64 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(url: String, socks5: String?, retry: UInt8, timeout: UInt8?, stopGap: UInt64 ) { + self.url = url + self.socks5 = socks5 + self.retry = retry + self.timeout = timeout + self.stopGap = stopGap + } +} + + +extension ElectrumConfig: Equatable, Hashable { + public static func ==(lhs: ElectrumConfig, rhs: ElectrumConfig) -> Bool { + if lhs.url != rhs.url { + return false + } + if lhs.socks5 != rhs.socks5 { + return false + } + if lhs.retry != rhs.retry { + return false + } + if lhs.timeout != rhs.timeout { + return false + } + if lhs.stopGap != rhs.stopGap { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(url) + hasher.combine(socks5) + hasher.combine(retry) + hasher.combine(timeout) + hasher.combine(stopGap) + } +} + + +fileprivate extension ElectrumConfig { + static func read(from buf: Reader) throws -> ElectrumConfig { + return try ElectrumConfig( + url: String.read(from: buf), + socks5: FfiConverterOptionString.read(from: buf), + retry: UInt8.read(from: buf), + timeout: FfiConverterOptionUInt8.read(from: buf), + stopGap: UInt64.read(from: buf) + ) + } + + func write(into buf: Writer) { + self.url.write(into: buf) + FfiConverterOptionString.write(self.socks5, into: buf) + self.retry.write(into: buf) + FfiConverterOptionUInt8.write(self.timeout, into: buf) + self.stopGap.write(into: buf) + } +} + +extension ElectrumConfig: ViaFfiUsingByteBuffer, ViaFfi {} + +public struct EsploraConfig { + public var baseUrl: String + public var proxy: String? + public var timeoutRead: UInt64 + public var timeoutWrite: UInt64 + public var stopGap: UInt64 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(baseUrl: String, proxy: String?, timeoutRead: UInt64, timeoutWrite: UInt64, stopGap: UInt64 ) { + self.baseUrl = baseUrl + self.proxy = proxy + self.timeoutRead = timeoutRead + self.timeoutWrite = timeoutWrite + self.stopGap = stopGap + } +} + + +extension EsploraConfig: Equatable, Hashable { + public static func ==(lhs: EsploraConfig, rhs: EsploraConfig) -> Bool { + if lhs.baseUrl != rhs.baseUrl { + return false + } + if lhs.proxy != rhs.proxy { + return false + } + if lhs.timeoutRead != rhs.timeoutRead { + return false + } + if lhs.timeoutWrite != rhs.timeoutWrite { + return false + } + if lhs.stopGap != rhs.stopGap { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(baseUrl) + hasher.combine(proxy) + hasher.combine(timeoutRead) + hasher.combine(timeoutWrite) + hasher.combine(stopGap) + } +} + + +fileprivate extension EsploraConfig { + static func read(from buf: Reader) throws -> EsploraConfig { + return try EsploraConfig( + baseUrl: String.read(from: buf), + proxy: FfiConverterOptionString.read(from: buf), + timeoutRead: UInt64.read(from: buf), + timeoutWrite: UInt64.read(from: buf), + stopGap: UInt64.read(from: buf) + ) + } + + func write(into buf: Writer) { + self.baseUrl.write(into: buf) + FfiConverterOptionString.write(self.proxy, into: buf) + self.timeoutRead.write(into: buf) + self.timeoutWrite.write(into: buf) + self.stopGap.write(into: buf) + } +} + +extension EsploraConfig: ViaFfiUsingByteBuffer, ViaFfi {} + +public struct ExtendedKeyInfo { + public var mnemonic: String + public var xprv: String + public var fingerprint: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(mnemonic: String, xprv: String, fingerprint: String ) { + self.mnemonic = mnemonic + self.xprv = xprv + self.fingerprint = fingerprint + } +} + + +extension ExtendedKeyInfo: Equatable, Hashable { + public static func ==(lhs: ExtendedKeyInfo, rhs: ExtendedKeyInfo) -> Bool { + if lhs.mnemonic != rhs.mnemonic { + return false + } + if lhs.xprv != rhs.xprv { + return false + } + if lhs.fingerprint != rhs.fingerprint { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(mnemonic) + hasher.combine(xprv) + hasher.combine(fingerprint) + } +} + + +fileprivate extension ExtendedKeyInfo { + static func read(from buf: Reader) throws -> ExtendedKeyInfo { + return try ExtendedKeyInfo( + mnemonic: String.read(from: buf), + xprv: String.read(from: buf), + fingerprint: String.read(from: buf) + ) + } + + func write(into buf: Writer) { + self.mnemonic.write(into: buf) + self.xprv.write(into: buf) + self.fingerprint.write(into: buf) + } +} + +extension ExtendedKeyInfo: ViaFfiUsingByteBuffer, ViaFfi {} + +public enum BdkError { + + + + // Simple error enums only carry a message + case InvalidU32Bytes(message: String) + + // Simple error enums only carry a message + case Generic(message: String) + + // Simple error enums only carry a message + case ScriptDoesntHaveAddressForm(message: String) + + // Simple error enums only carry a message + case NoRecipients(message: String) + + // Simple error enums only carry a message + case NoUtxosSelected(message: String) + + // Simple error enums only carry a message + case OutputBelowDustLimit(message: String) + + // Simple error enums only carry a message + case InsufficientFunds(message: String) + + // Simple error enums only carry a message + case BnBTotalTriesExceeded(message: String) + + // Simple error enums only carry a message + case BnBNoExactMatch(message: String) + + // Simple error enums only carry a message + case UnknownUtxo(message: String) + + // Simple error enums only carry a message + case TransactionNotFound(message: String) + + // Simple error enums only carry a message + case TransactionConfirmed(message: String) + + // Simple error enums only carry a message + case IrreplaceableTransaction(message: String) + + // Simple error enums only carry a message + case FeeRateTooLow(message: String) + + // Simple error enums only carry a message + case FeeTooLow(message: String) + + // Simple error enums only carry a message + case FeeRateUnavailable(message: String) + + // Simple error enums only carry a message + case MissingKeyOrigin(message: String) + + // Simple error enums only carry a message + case Key(message: String) + + // Simple error enums only carry a message + case ChecksumMismatch(message: String) + + // Simple error enums only carry a message + case SpendingPolicyRequired(message: String) + + // Simple error enums only carry a message + case InvalidPolicyPathError(message: String) + + // Simple error enums only carry a message + case Signer(message: String) + + // Simple error enums only carry a message + case InvalidNetwork(message: String) + + // Simple error enums only carry a message + case InvalidProgressValue(message: String) + + // Simple error enums only carry a message + case ProgressUpdateError(message: String) + + // Simple error enums only carry a message + case InvalidOutpoint(message: String) + + // Simple error enums only carry a message + case Descriptor(message: String) + + // Simple error enums only carry a message + case AddressValidator(message: String) + + // Simple error enums only carry a message + case Encode(message: String) + + // Simple error enums only carry a message + case Miniscript(message: String) + + // Simple error enums only carry a message + case Bip32(message: String) + + // Simple error enums only carry a message + case Secp256k1(message: String) + + // Simple error enums only carry a message + case Json(message: String) + + // Simple error enums only carry a message + case Hex(message: String) + + // Simple error enums only carry a message + case Psbt(message: String) + + // Simple error enums only carry a message + case PsbtParse(message: String) + + // Simple error enums only carry a message + case Electrum(message: String) + + // Simple error enums only carry a message + case Esplora(message: String) + + // Simple error enums only carry a message + case Sled(message: String) + +} + +extension BdkError: ViaFfiUsingByteBuffer, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> BdkError { + let variant: Int32 = try buf.readInt() + switch variant { + + + + + case 1: return .InvalidU32Bytes( + message: try String.read(from: buf) + ) + + case 2: return .Generic( + message: try String.read(from: buf) + ) + + case 3: return .ScriptDoesntHaveAddressForm( + message: try String.read(from: buf) + ) + + case 4: return .NoRecipients( + message: try String.read(from: buf) + ) + + case 5: return .NoUtxosSelected( + message: try String.read(from: buf) + ) + + case 6: return .OutputBelowDustLimit( + message: try String.read(from: buf) + ) + + case 7: return .InsufficientFunds( + message: try String.read(from: buf) + ) + + case 8: return .BnBTotalTriesExceeded( + message: try String.read(from: buf) + ) + + case 9: return .BnBNoExactMatch( + message: try String.read(from: buf) + ) + + case 10: return .UnknownUtxo( + message: try String.read(from: buf) + ) + + case 11: return .TransactionNotFound( + message: try String.read(from: buf) + ) + + case 12: return .TransactionConfirmed( + message: try String.read(from: buf) + ) + + case 13: return .IrreplaceableTransaction( + message: try String.read(from: buf) + ) + + case 14: return .FeeRateTooLow( + message: try String.read(from: buf) + ) + + case 15: return .FeeTooLow( + message: try String.read(from: buf) + ) + + case 16: return .FeeRateUnavailable( + message: try String.read(from: buf) + ) + + case 17: return .MissingKeyOrigin( + message: try String.read(from: buf) + ) + + case 18: return .Key( + message: try String.read(from: buf) + ) + + case 19: return .ChecksumMismatch( + message: try String.read(from: buf) + ) + + case 20: return .SpendingPolicyRequired( + message: try String.read(from: buf) + ) + + case 21: return .InvalidPolicyPathError( + message: try String.read(from: buf) + ) + + case 22: return .Signer( + message: try String.read(from: buf) + ) + + case 23: return .InvalidNetwork( + message: try String.read(from: buf) + ) + + case 24: return .InvalidProgressValue( + message: try String.read(from: buf) + ) + + case 25: return .ProgressUpdateError( + message: try String.read(from: buf) + ) + + case 26: return .InvalidOutpoint( + message: try String.read(from: buf) + ) + + case 27: return .Descriptor( + message: try String.read(from: buf) + ) + + case 28: return .AddressValidator( + message: try String.read(from: buf) + ) + + case 29: return .Encode( + message: try String.read(from: buf) + ) + + case 30: return .Miniscript( + message: try String.read(from: buf) + ) + + case 31: return .Bip32( + message: try String.read(from: buf) + ) + + case 32: return .Secp256k1( + message: try String.read(from: buf) + ) + + case 33: return .Json( + message: try String.read(from: buf) + ) + + case 34: return .Hex( + message: try String.read(from: buf) + ) + + case 35: return .Psbt( + message: try String.read(from: buf) + ) + + case 36: return .PsbtParse( + message: try String.read(from: buf) + ) + + case 37: return .Electrum( + message: try String.read(from: buf) + ) + + case 38: return .Esplora( + message: try String.read(from: buf) + ) + + case 39: return .Sled( + message: try String.read(from: buf) + ) + + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + fileprivate func write(into buf: Writer) { + switch self { + + + + + case let .InvalidU32Bytes(message): + buf.writeInt(Int32(1)) + message.write(into: buf) + case let .Generic(message): + buf.writeInt(Int32(2)) + message.write(into: buf) + case let .ScriptDoesntHaveAddressForm(message): + buf.writeInt(Int32(3)) + message.write(into: buf) + case let .NoRecipients(message): + buf.writeInt(Int32(4)) + message.write(into: buf) + case let .NoUtxosSelected(message): + buf.writeInt(Int32(5)) + message.write(into: buf) + case let .OutputBelowDustLimit(message): + buf.writeInt(Int32(6)) + message.write(into: buf) + case let .InsufficientFunds(message): + buf.writeInt(Int32(7)) + message.write(into: buf) + case let .BnBTotalTriesExceeded(message): + buf.writeInt(Int32(8)) + message.write(into: buf) + case let .BnBNoExactMatch(message): + buf.writeInt(Int32(9)) + message.write(into: buf) + case let .UnknownUtxo(message): + buf.writeInt(Int32(10)) + message.write(into: buf) + case let .TransactionNotFound(message): + buf.writeInt(Int32(11)) + message.write(into: buf) + case let .TransactionConfirmed(message): + buf.writeInt(Int32(12)) + message.write(into: buf) + case let .IrreplaceableTransaction(message): + buf.writeInt(Int32(13)) + message.write(into: buf) + case let .FeeRateTooLow(message): + buf.writeInt(Int32(14)) + message.write(into: buf) + case let .FeeTooLow(message): + buf.writeInt(Int32(15)) + message.write(into: buf) + case let .FeeRateUnavailable(message): + buf.writeInt(Int32(16)) + message.write(into: buf) + case let .MissingKeyOrigin(message): + buf.writeInt(Int32(17)) + message.write(into: buf) + case let .Key(message): + buf.writeInt(Int32(18)) + message.write(into: buf) + case let .ChecksumMismatch(message): + buf.writeInt(Int32(19)) + message.write(into: buf) + case let .SpendingPolicyRequired(message): + buf.writeInt(Int32(20)) + message.write(into: buf) + case let .InvalidPolicyPathError(message): + buf.writeInt(Int32(21)) + message.write(into: buf) + case let .Signer(message): + buf.writeInt(Int32(22)) + message.write(into: buf) + case let .InvalidNetwork(message): + buf.writeInt(Int32(23)) + message.write(into: buf) + case let .InvalidProgressValue(message): + buf.writeInt(Int32(24)) + message.write(into: buf) + case let .ProgressUpdateError(message): + buf.writeInt(Int32(25)) + message.write(into: buf) + case let .InvalidOutpoint(message): + buf.writeInt(Int32(26)) + message.write(into: buf) + case let .Descriptor(message): + buf.writeInt(Int32(27)) + message.write(into: buf) + case let .AddressValidator(message): + buf.writeInt(Int32(28)) + message.write(into: buf) + case let .Encode(message): + buf.writeInt(Int32(29)) + message.write(into: buf) + case let .Miniscript(message): + buf.writeInt(Int32(30)) + message.write(into: buf) + case let .Bip32(message): + buf.writeInt(Int32(31)) + message.write(into: buf) + case let .Secp256k1(message): + buf.writeInt(Int32(32)) + message.write(into: buf) + case let .Json(message): + buf.writeInt(Int32(33)) + message.write(into: buf) + case let .Hex(message): + buf.writeInt(Int32(34)) + message.write(into: buf) + case let .Psbt(message): + buf.writeInt(Int32(35)) + message.write(into: buf) + case let .PsbtParse(message): + buf.writeInt(Int32(36)) + message.write(into: buf) + case let .Electrum(message): + buf.writeInt(Int32(37)) + message.write(into: buf) + case let .Esplora(message): + buf.writeInt(Int32(38)) + message.write(into: buf) + case let .Sled(message): + buf.writeInt(Int32(39)) + message.write(into: buf) + } + } +} + + +extension BdkError: Equatable, Hashable {} + +extension BdkError: Error { } + + +// Declaration and FfiConverters for BdkProgress Callback Interface + +public protocol BdkProgress : AnyObject { + func update(progress: Float, message: String? ) + +} + +// The ForeignCallback that is passed to Rust. +fileprivate let foreignCallbackCallbackInterfaceBdkProgress : ForeignCallback = + { (handle: Handle, method: Int32, args: RustBuffer) -> RustBuffer in + func invokeUpdate(_ swiftCallbackInterface: BdkProgress, _ args: RustBuffer) throws -> RustBuffer { + defer { args.deallocate() } + + let reader = Reader(data: Data(rustBuffer: args)) + swiftCallbackInterface.update( + progress: try Float.read(from: reader), + message: try FfiConverterOptionString.read(from: reader) + ) + return RustBuffer() + // TODO catch errors and report them back to Rust. + // https://github.com/mozilla/uniffi-rs/issues/351 + + } + + + let cb = try! ffiConverterCallbackInterfaceBdkProgress.lift(handle) + switch method { + case IDX_CALLBACK_FREE: + ffiConverterCallbackInterfaceBdkProgress.drop(handle: handle) + return RustBuffer() + case 1: return try! invokeUpdate(cb, args) + + // This should never happen, because an out of bounds method index won't + // ever be used. Once we can catch errors, we should return an InternalError. + // https://github.com/mozilla/uniffi-rs/issues/351 + default: return RustBuffer() + } + } + +// The ffiConverter which transforms the Callbacks in to Handles to pass to Rust. +private let ffiConverterCallbackInterfaceBdkProgress: FfiConverterCallbackInterface = { + try! rustCall { (err: UnsafeMutablePointer) in + ffi_bdk_2e4d_BdkProgress_init_callback(foreignCallbackCallbackInterfaceBdkProgress, err) + } + return FfiConverterCallbackInterface() +}() +extension UInt8: Primitive, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> Self { + return try self.lift(buf.readInt()) + } + + fileprivate func write(into buf: Writer) { + buf.writeInt(self.lower()) + } +} +extension UInt32: Primitive, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> Self { + return try self.lift(buf.readInt()) + } + + fileprivate func write(into buf: Writer) { + buf.writeInt(self.lower()) + } +} +extension UInt64: Primitive, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> Self { + return try self.lift(buf.readInt()) + } + + fileprivate func write(into buf: Writer) { + buf.writeInt(self.lower()) + } +} +extension Float: Primitive, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> Self { + return try self.lift(buf.readFloat()) + } + + fileprivate func write(into buf: Writer) { + buf.writeFloat(self.lower()) + } +} +extension String: ViaFfi { + fileprivate typealias FfiType = RustBuffer + + fileprivate static func lift(_ v: FfiType) throws -> Self { + defer { + v.deallocate() + } + if v.data == nil { + return String() + } + let bytes = UnsafeBufferPointer(start: v.data!, count: Int(v.len)) + return String(bytes: bytes, encoding: String.Encoding.utf8)! + } + + fileprivate func lower() -> FfiType { + return self.utf8CString.withUnsafeBufferPointer { ptr in + // The swift string gives us int8_t, we want uint8_t. + ptr.withMemoryRebound(to: UInt8.self) { ptr in + // The swift string gives us a trailing null byte, we don't want it. + let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) + return RustBuffer.from(buf) + } + } + } + + fileprivate static func read(from buf: Reader) throws -> Self { + let len: Int32 = try buf.readInt() + return String(bytes: try buf.readBytes(count: Int(len)), encoding: String.Encoding.utf8)! + } + + fileprivate func write(into buf: Writer) { + let len = Int32(self.utf8.count) + buf.writeInt(len) + buf.writeBytes(self.utf8) + } +} +// Helper code for OfflineWallet class is found in ObjectTemplate.swift +// Helper code for OnlineWallet class is found in ObjectTemplate.swift +// Helper code for PartiallySignedBitcoinTransaction class is found in ObjectTemplate.swift +// Helper code for Confirmation record is found in RecordTemplate.swift +// Helper code for ElectrumConfig record is found in RecordTemplate.swift +// Helper code for EsploraConfig record is found in RecordTemplate.swift +// Helper code for ExtendedKeyInfo record is found in RecordTemplate.swift +// Helper code for SledDbConfiguration record is found in RecordTemplate.swift +// Helper code for TransactionDetails record is found in RecordTemplate.swift +// Helper code for BlockchainConfig enum is found in EnumTemplate.swift +// Helper code for DatabaseConfig enum is found in EnumTemplate.swift +// Helper code for MnemonicType enum is found in EnumTemplate.swift +// Helper code for Network enum is found in EnumTemplate.swift +// Helper code for Transaction enum is found in EnumTemplate.swift +// Helper code for BdkError error is found in ErrorTemplate.swift + +fileprivate enum FfiConverterOptionUInt8: FfiConverterUsingByteBuffer { + typealias SwiftType = UInt8? + + static func write(_ value: SwiftType, into buf: Writer) { + FfiConverterOptional.write(value, into: buf) { item, buf in + item.write(into: buf) + } + } + + static func read(from buf: Reader) throws -> SwiftType { + try FfiConverterOptional.read(from: buf) { buf in + try UInt8.read(from: buf) + } + } +} + +fileprivate enum FfiConverterOptionUInt32: FfiConverterUsingByteBuffer { + typealias SwiftType = UInt32? + + static func write(_ value: SwiftType, into buf: Writer) { + FfiConverterOptional.write(value, into: buf) { item, buf in + item.write(into: buf) + } + } + + static func read(from buf: Reader) throws -> SwiftType { + try FfiConverterOptional.read(from: buf) { buf in + try UInt32.read(from: buf) + } + } +} + +fileprivate enum FfiConverterOptionUInt64: FfiConverterUsingByteBuffer { + typealias SwiftType = UInt64? + + static func write(_ value: SwiftType, into buf: Writer) { + FfiConverterOptional.write(value, into: buf) { item, buf in + item.write(into: buf) + } + } + + static func read(from buf: Reader) throws -> SwiftType { + try FfiConverterOptional.read(from: buf) { buf in + try UInt64.read(from: buf) + } + } +} + +fileprivate enum FfiConverterOptionFloat: FfiConverterUsingByteBuffer { + typealias SwiftType = Float? + + static func write(_ value: SwiftType, into buf: Writer) { + FfiConverterOptional.write(value, into: buf) { item, buf in + item.write(into: buf) + } + } + + static func read(from buf: Reader) throws -> SwiftType { + try FfiConverterOptional.read(from: buf) { buf in + try Float.read(from: buf) + } + } +} + +fileprivate enum FfiConverterOptionString: FfiConverterUsingByteBuffer { + typealias SwiftType = String? + + static func write(_ value: SwiftType, into buf: Writer) { + FfiConverterOptional.write(value, into: buf) { item, buf in + item.write(into: buf) + } + } + + static func read(from buf: Reader) throws -> SwiftType { + try FfiConverterOptional.read(from: buf) { buf in + try String.read(from: buf) + } + } +} + +fileprivate enum FfiConverterSequenceEnumTransaction: FfiConverterUsingByteBuffer { + typealias SwiftType = [Transaction] + + static func write(_ value: SwiftType, into buf: Writer) { + FfiConverterSequence.write(value, into: buf) { (item, buf) in + item.write(into: buf) + } + } + + static func read(from buf: Reader) throws -> SwiftType { + try FfiConverterSequence.read(from: buf) { buf in + try Transaction.read(from: buf) + } + } +} + + +/** + * Top level initializers and tear down methods. + * + * This is generated by uniffi. + */ +public enum BdkLifecycle { + /** + * Initialize the FFI and Rust library. This should be only called once per application. + */ + func initialize() { + + // No initialization code needed + + } +} \ No newline at end of file diff --git a/Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift b/Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift new file mode 100644 index 0000000..88b9a69 --- /dev/null +++ b/Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift @@ -0,0 +1,12 @@ +import XCTest +@testable import BitcoinDevKit + +final class BitcoinDevKitTests: XCTestCase { + func testMemoryWalletNewAddress() throws { + let desc = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)" + let config = DatabaseConfig.memory(junk: "") + let wallet = try OfflineWallet.init(descriptor: desc, network: Network.regtest, databaseConfig: config) + let address = wallet.getNewAddress() + XCTAssertEqual(address, "bcrt1qzg4mckdh50nwdm9hkzq06528rsu73hjxytqkxs") + } +} diff --git a/bdk-ffi b/bdk-ffi new file mode 160000 index 0000000..4e087ef --- /dev/null +++ b/bdk-ffi @@ -0,0 +1 @@ +Subproject commit 4e087ef21c69986090ad8157bba112842156b8b9 diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..7c4ee81 --- /dev/null +++ b/build.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +set -eo pipefail + +BUILD_PROFILE=release +BDKFFI_DIR=bdk-ffi +TARGET_DIR=$BDKFFI_DIR/target +STATIC_LIB_NAME=libbdkffi.a +SWIFT_DIR="$BDKFFI_DIR/bindings/bdk-swift" +XCFRAMEWORK_NAME="bdkFFI" +XCFRAMEWORK_ROOT="$XCFRAMEWORK_NAME.xcframework" +XCFRAMEWORK_COMMON="$XCFRAMEWORK_ROOT/common/$XCFRAMEWORK_NAME.framework" + +## build bdk-ffi rust libs +echo "Build bdk-ffi rust library" +pushd $BDKFFI_DIR +cargo build --release + +echo "Generate bdk-ffi swift bindings" +uniffi-bindgen generate src/bdk.udl --no-format --out-dir bindings/bdk-swift/ --language swift +swiftc -module-name bdk -emit-library -o libbdkffi.dylib -emit-module -emit-module-path bindings/bdk-swift/ -parse-as-library -L target/release/ -lbdkffi -Xcc -fmodule-map-file=bindings/bdk-swift/$XCFRAMEWORK_NAME.modulemap bindings/bdk-swift/bdk.swift -suppress-warnings + +## build bdk-ffi rust libs into xcframework +echo "Build bdk-ffi libs into swift xcframework" + +APPLE_TRIPLES=("x86_64-apple-darwin" "x86_64-apple-ios" "aarch64-apple-ios") +for TARGET in $APPLE_TRIPLES; do + echo "Build bdk-ffi lib for target $TARGET" + cargo build --release --target $TARGET +done +popd + +## Manually construct xcframework + +# Cleanup prior build +rm -rf "$XCFRAMEWORK_ROOT" +rm -f $XCFRAMEWORK_ROOT.zip + +# Common files +mkdir -p "$XCFRAMEWORK_COMMON/Modules" +cp "$SWIFT_DIR/$XCFRAMEWORK_NAME.modulemap" "$XCFRAMEWORK_COMMON/Modules/" +mkdir -p "$XCFRAMEWORK_COMMON/Headers" +cp "$SWIFT_DIR/$XCFRAMEWORK_NAME-umbrella.h" "$XCFRAMEWORK_COMMON/Headers" +cp "$SWIFT_DIR/$XCFRAMEWORK_NAME.h" "$XCFRAMEWORK_COMMON/Headers" + +# macOS x86_64 hardware +mkdir -p "$XCFRAMEWORK_ROOT/macos-x86_64" +cp -R "$XCFRAMEWORK_COMMON" "$XCFRAMEWORK_ROOT/macos-x86_64/$XCFRAMEWORK_NAME.framework" +cp "$TARGET_DIR/x86_64-apple-darwin/$BUILD_PROFILE/$STATIC_LIB_NAME" "$XCFRAMEWORK_ROOT/macos-x86_64/$XCFRAMEWORK_NAME.framework/$XCFRAMEWORK_NAME" + +# iOS hardware +mkdir -p "$XCFRAMEWORK_ROOT/ios-arm64" +cp -R "$XCFRAMEWORK_COMMON" "$XCFRAMEWORK_ROOT/ios-arm64/$XCFRAMEWORK_NAME.framework" +cp "$TARGET_DIR/aarch64-apple-ios/$BUILD_PROFILE/$STATIC_LIB_NAME" "$XCFRAMEWORK_ROOT/ios-arm64/$XCFRAMEWORK_NAME.framework/$XCFRAMEWORK_NAME" + +# iOS simulator, currently x86_64 only (need to make fat binary to add M1) +mkdir -p "$XCFRAMEWORK_ROOT/ios-arm64_x86_64-simulator" +cp -R "$XCFRAMEWORK_COMMON" "$XCFRAMEWORK_ROOT/ios-arm64_x86_64-simulator/$XCFRAMEWORK_NAME.framework" +cp "$TARGET_DIR/x86_64-apple-ios/$BUILD_PROFILE/$STATIC_LIB_NAME" "$XCFRAMEWORK_ROOT/ios-arm64_x86_64-simulator/$XCFRAMEWORK_NAME.framework/$XCFRAMEWORK_NAME" + +# Set up the metadata for the XCFramework as a whole. +cp "$SWIFT_DIR/Info.plist" "$XCFRAMEWORK_ROOT/Info.plist" +# TODO add license info + +# Remove common +rm -rf "$XCFRAMEWORK_ROOT/common" + +# Zip it all up into a bundle for distribution. +zip -9 -r "$XCFRAMEWORK_ROOT.zip" "$XCFRAMEWORK_ROOT" + +swift package compute-checksum bdkFFI.xcframework.zip + +# Cleanup build ? +# rm -rf "$XCFRAMEWORK_ROOT" From 2ccd89ed2e048b41d48caac412af3f72ba97801f Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Tue, 23 Nov 2021 21:46:11 -0800 Subject: [PATCH 02/33] Fix build.sh cargo build loop and xcframework module.modulemap --- Package.swift | 3 ++- build.sh | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Package.swift b/Package.swift index 485d25e..21e9347 100644 --- a/Package.swift +++ b/Package.swift @@ -25,7 +25,8 @@ let package = Package( .binaryTarget( name: "bdkFFI", url: "https://github.com/notmandatory/bdk-swift/releases/download/0.1.0/bdkFFI.xcframework.zip", - checksum: "b34dc1dea2e53bc894f1ad61269e45de6c77dd6391bbb1318cfb0be17435c4db"), + checksum: "496423e55dd5db14cb2b692f59ae6bf527431c59f79ab51d89c83f68e23d4722"), +// .binaryTarget(name: "bdkFFI", path: "./bdkFFI.xcframework"), .target( name: "BitcoinDevKit", dependencies: ["bdkFFI"]), diff --git a/build.sh b/build.sh index 7c4ee81..2e12ca5 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -set -eo pipefail +set -euo pipefail BUILD_PROFILE=release BDKFFI_DIR=bdk-ffi @@ -22,11 +22,13 @@ swiftc -module-name bdk -emit-library -o libbdkffi.dylib -emit-module -emit-modu ## build bdk-ffi rust libs into xcframework echo "Build bdk-ffi libs into swift xcframework" -APPLE_TRIPLES=("x86_64-apple-darwin" "x86_64-apple-ios" "aarch64-apple-ios") -for TARGET in $APPLE_TRIPLES; do +TARGET_TRIPLES=("x86_64-apple-darwin" "x86_64-apple-ios" "aarch64-apple-ios") +for TARGET in ${TARGET_TRIPLES[@]}; do echo "Build bdk-ffi lib for target $TARGET" cargo build --release --target $TARGET + echo $? done + popd ## Manually construct xcframework @@ -37,7 +39,7 @@ rm -f $XCFRAMEWORK_ROOT.zip # Common files mkdir -p "$XCFRAMEWORK_COMMON/Modules" -cp "$SWIFT_DIR/$XCFRAMEWORK_NAME.modulemap" "$XCFRAMEWORK_COMMON/Modules/" +cp "$SWIFT_DIR/module.modulemap" "$XCFRAMEWORK_COMMON/Modules/" mkdir -p "$XCFRAMEWORK_COMMON/Headers" cp "$SWIFT_DIR/$XCFRAMEWORK_NAME-umbrella.h" "$XCFRAMEWORK_COMMON/Headers" cp "$SWIFT_DIR/$XCFRAMEWORK_NAME.h" "$XCFRAMEWORK_COMMON/Headers" From 71496cd56a1c3330253f9b7143c243d2ee852d09 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Tue, 23 Nov 2021 22:46:38 -0800 Subject: [PATCH 03/33] Simplify build.sh and add template bdkFFI.xcframework to repo --- .gitignore | 10 +- Sources/BitcoinDevKit/BitcoinDevKit.swift | 2113 ----------------- bdkFFI.xcframework/Info.plist | 52 + .../Headers/bdkFFI-umbrella.h | 4 + .../bdkFFI.framework/Modules/module.modulemap | 6 + .../Headers/bdkFFI-umbrella.h | 4 + .../bdkFFI.framework/Modules/module.modulemap | 6 + .../Headers/bdkFFI-umbrella.h | 4 + .../bdkFFI.framework/Modules/module.modulemap | 6 + build.sh | 82 +- 10 files changed, 120 insertions(+), 2167 deletions(-) delete mode 100644 Sources/BitcoinDevKit/BitcoinDevKit.swift create mode 100644 bdkFFI.xcframework/Info.plist create mode 100644 bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Headers/bdkFFI-umbrella.h create mode 100644 bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Modules/module.modulemap create mode 100644 bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Headers/bdkFFI-umbrella.h create mode 100644 bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Modules/module.modulemap create mode 100644 bdkFFI.xcframework/macos-x86_64/bdkFFI.framework/Headers/bdkFFI-umbrella.h create mode 100644 bdkFFI.xcframework/macos-x86_64/bdkFFI.framework/Modules/module.modulemap diff --git a/.gitignore b/.gitignore index b18ca41..c850c2d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,8 @@ xcuserdata/ DerivedData/ .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata -/*.xcframework -!bdkFFI-umbrella.h -!module.modulemap -!info.plist -*.xcframework.zip +bdkFFI.xcframework.zip +bdkFFI +bdkFFI.h +bdk.swift +BitcoinDevKit.swift diff --git a/Sources/BitcoinDevKit/BitcoinDevKit.swift b/Sources/BitcoinDevKit/BitcoinDevKit.swift deleted file mode 100644 index 1c9432e..0000000 --- a/Sources/BitcoinDevKit/BitcoinDevKit.swift +++ /dev/null @@ -1,2113 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! -import Foundation - -// Depending on the consumer's build setup, the low-level FFI code -// might be in a separate module, or it might be compiled inline into -// this module. This is a bit of light hackery to work with both. -#if canImport(bdkFFI) -import bdkFFI -#endif - -fileprivate extension RustBuffer { - // Allocate a new buffer, copying the contents of a `UInt8` array. - init(bytes: [UInt8]) { - let rbuf = bytes.withUnsafeBufferPointer { ptr in - RustBuffer.from(ptr) - } - self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) - } - - static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { - try! rustCall { ffi_bdk_2e4d_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } - } - - // Frees the buffer in place. - // The buffer must not be used after this is called. - func deallocate() { - try! rustCall { ffi_bdk_2e4d_rustbuffer_free(self, $0) } - } -} - -fileprivate extension ForeignBytes { - init(bufferPointer: UnsafeBufferPointer) { - self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) - } -} - -// For every type used in the interface, we provide helper methods for conveniently -// lifting and lowering that type from C-compatible data, and for reading and writing -// values of that type in a buffer. - -// Helper classes/extensions that don't change. -// Someday, this will be in a libray of its own. - -fileprivate extension Data { - init(rustBuffer: RustBuffer) { - // TODO: This copies the buffer. Can we read directly from a - // Rust buffer? - self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len)) - } -} - -// A helper class to read values out of a byte buffer. -fileprivate class Reader { - let data: Data - var offset: Data.Index - - init(data: Data) { - self.data = data - self.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. - func readInt() throws -> T { - let range = offset...size - guard data.count >= range.upperBound else { - throw UniffiInternalError.bufferOverflow - } - if T.self == UInt8.self { - let value = data[offset] - offset += 1 - return value as! T - } - var value: T = 0 - let _ = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0, from: range)}) - offset = range.upperBound - return value.bigEndian - } - - // Reads an arbitrary number of bytes, to be used to read - // raw bytes, this is useful when lifting strings - func readBytes(count: Int) throws -> Array { - let range = offset..<(offset+count) - guard data.count >= range.upperBound else { - throw UniffiInternalError.bufferOverflow - } - var value = [UInt8](repeating: 0, count: count) - value.withUnsafeMutableBufferPointer({ buffer in - data.copyBytes(to: buffer, from: range) - }) - offset = range.upperBound - return value - } - - // Reads a float at the current offset. - @inlinable - func readFloat() throws -> Float { - return Float(bitPattern: try readInt()) - } - - // Reads a float at the current offset. - @inlinable - func readDouble() throws -> Double { - return Double(bitPattern: try readInt()) - } - - // Indicates if the offset has reached the end of the buffer. - @inlinable - func hasRemaining() -> Bool { - return offset < data.count - } -} - -// A helper class to write values into a byte buffer. -fileprivate class Writer { - var bytes: [UInt8] - var offset: Array.Index - - init() { - self.bytes = [] - self.offset = 0 - } - - func writeBytes(_ byteArr: S) where S: Sequence, S.Element == UInt8 { - bytes.append(contentsOf: byteArr) - } - - // Writes an integer in big-endian order. - // - // Warning: make sure what you are trying to write - // is in the correct type! - func writeInt(_ value: T) { - var value = value.bigEndian - withUnsafeBytes(of: &value) { bytes.append(contentsOf: $0) } - } - - @inlinable - func writeFloat(_ value: Float) { - writeInt(value.bitPattern) - } - - @inlinable - func writeDouble(_ value: Double) { - writeInt(value.bitPattern) - } -} - - -// Types conforming to `Serializable` can be read and written in a bytebuffer. -fileprivate protocol Serializable { - func write(into: Writer) - static func read(from: Reader) throws -> Self -} - -// Types confirming to `ViaFfi` can be transferred back-and-for over the FFI. -// This is analogous to the Rust trait of the same name. -fileprivate protocol ViaFfi: Serializable { - associatedtype FfiType - static func lift(_ v: FfiType) throws -> Self - func lower() -> FfiType -} - -// Types conforming to `Primitive` pass themselves directly over the FFI. -fileprivate protocol Primitive {} - -extension Primitive { - fileprivate typealias FfiType = Self - - fileprivate static func lift(_ v: Self) throws -> Self { - return v - } - - fileprivate func lower() -> Self { - return self - } -} - -// Types conforming to `ViaFfiUsingByteBuffer` lift and lower into a bytebuffer. -// Use this for complex types where it's hard to write a custom lift/lower. -fileprivate protocol ViaFfiUsingByteBuffer: Serializable {} - -extension ViaFfiUsingByteBuffer { - fileprivate typealias FfiType = RustBuffer - - fileprivate static func lift(_ buf: FfiType) throws -> Self { - let reader = Reader(data: Data(rustBuffer: buf)) - let value = try Self.read(from: reader) - if reader.hasRemaining() { - throw UniffiInternalError.incompleteData - } - buf.deallocate() - return value - } - - fileprivate func lower() -> FfiType { - let writer = Writer() - self.write(into: writer) - return RustBuffer(bytes: writer.bytes) - } -} -// An error type for FFI errors. These errors occur at the UniFFI level, not -// the library level. -fileprivate enum UniffiInternalError: LocalizedError { - case bufferOverflow - case incompleteData - case unexpectedOptionalTag - case unexpectedEnumCase - case unexpectedNullPointer - case unexpectedRustCallStatusCode - case unexpectedRustCallError - case unexpectedStaleHandle - case rustPanic(_ message: String) - - public var errorDescription: String? { - switch self { - case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" - case .incompleteData: return "The buffer still has data after lifting its containing value" - case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1" - case .unexpectedEnumCase: return "Raw enum value doesn't match any cases" - case .unexpectedNullPointer: return "Raw pointer value was null" - case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code" - case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified" - case .unexpectedStaleHandle: return "The object in the handle map has been dropped already" - case let .rustPanic(message): return message - } - } -} - -fileprivate let CALL_SUCCESS: Int8 = 0 -fileprivate let CALL_ERROR: Int8 = 1 -fileprivate let CALL_PANIC: Int8 = 2 - -fileprivate extension RustCallStatus { - init() { - self.init( - code: CALL_SUCCESS, - errorBuf: RustBuffer.init( - capacity: 0, - len: 0, - data: nil - ) - ) - } -} - -private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T { - try makeRustCall(callback, errorHandler: { - $0.deallocate() - return UniffiInternalError.unexpectedRustCallError - }) -} - -private func rustCallWithError(_ errorClass: E.Type, _ callback: (UnsafeMutablePointer) -> T) throws -> T { - try makeRustCall(callback, errorHandler: { return try E.lift($0) }) -} - -private func makeRustCall(_ callback: (UnsafeMutablePointer) -> T, errorHandler: (RustBuffer) throws -> Error) throws -> T { - var callStatus = RustCallStatus.init() - let returnedVal = callback(&callStatus) - switch callStatus.code { - case CALL_SUCCESS: - return returnedVal - - case CALL_ERROR: - throw try errorHandler(callStatus.errorBuf) - - case CALL_PANIC: - // When the rust code sees a panic, it tries to construct a RustBuffer - // with the message. But if that code panics, then it just sends back - // an empty buffer. - if callStatus.errorBuf.len > 0 { - throw UniffiInternalError.rustPanic(try String.lift(callStatus.errorBuf)) - } else { - callStatus.errorBuf.deallocate() - throw UniffiInternalError.rustPanic("Rust panic") - } - - default: - throw UniffiInternalError.unexpectedRustCallStatusCode - } -} -// Protocols for converters we'll implement in templates - -fileprivate protocol FfiConverter { - associatedtype SwiftType - associatedtype FfiType - - static func lift(_ ffiValue: FfiType) throws -> SwiftType - static func lower(_ value: SwiftType) -> FfiType - - static func read(from: Reader) throws -> SwiftType - static func write(_ value: SwiftType, into: Writer) -} - -fileprivate protocol FfiConverterUsingByteBuffer: FfiConverter where FfiType == RustBuffer { - // Empty, because we want to declare some helper methods in the extension below. -} - -extension FfiConverterUsingByteBuffer { - static func lower(_ value: SwiftType) -> FfiType { - let writer = Writer() - Self.write(value, into: writer) - return RustBuffer(bytes: writer.bytes) - } - - static func lift(_ buf: FfiType) throws -> SwiftType { - let reader = Reader(data: Data(rustBuffer: buf)) - let value = try Self.read(from: reader) - if reader.hasRemaining() { - throw UniffiInternalError.incompleteData - } - buf.deallocate() - return value - } -} - -// Helpers for structural types. Note that because of canonical_names, it /should/ be impossible -// to make another `FfiConverterSequence` etc just using the UDL. -fileprivate enum FfiConverterSequence { - static func write(_ value: [T], into buf: Writer, writeItem: (T, Writer) -> Void) { - let len = Int32(value.count) - buf.writeInt(len) - for item in value { - writeItem(item, buf) - } - } - - static func read(from buf: Reader, readItem: (Reader) throws -> T) throws -> [T] { - let len: Int32 = try buf.readInt() - var seq = [T]() - seq.reserveCapacity(Int(len)) - for _ in 0 ..< len { - seq.append(try readItem(buf)) - } - return seq - } -} - -fileprivate enum FfiConverterOptional { - static func write(_ value: T?, into buf: Writer, writeItem: (T, Writer) -> Void) { - guard let value = value else { - buf.writeInt(Int8(0)) - return - } - buf.writeInt(Int8(1)) - writeItem(value, buf) - } - - static func read(from buf: Reader, readItem: (Reader) throws -> T) throws -> T? { - switch try buf.readInt() as Int8 { - case 0: return nil - case 1: return try readItem(buf) - default: throw UniffiInternalError.unexpectedOptionalTag - } - } -} - -fileprivate enum FfiConverterDictionary { - static func write(_ value: [String: T], into buf: Writer, writeItem: (String, T, Writer) -> Void) { - let len = Int32(value.count) - buf.writeInt(len) - for (key, value) in value { - writeItem(key, value, buf) - } - } - - static func read(from buf: Reader, readItem: (Reader) throws -> (String, T)) throws -> [String: T] { - let len: Int32 = try buf.readInt() - var dict = [String: T]() - dict.reserveCapacity(Int(len)) - for _ in 0..(f: () throws -> T) rethrows -> T { - self.lock() - defer { self.unlock() } - return try f() - } -} - -fileprivate typealias Handle = UInt64 -fileprivate class ConcurrentHandleMap { - private var leftMap: [Handle: T] = [:] - private var counter: [Handle: UInt64] = [:] - private var rightMap: [ObjectIdentifier: Handle] = [:] - - private let lock = NSLock() - private var currentHandle: Handle = 0 - private let stride: Handle = 1 - - func insert(obj: T) -> Handle { - lock.withLock { - let id = ObjectIdentifier(obj as AnyObject) - let handle = rightMap[id] ?? { - currentHandle += stride - let handle = currentHandle - leftMap[handle] = obj - rightMap[id] = handle - return handle - }() - counter[handle] = (counter[handle] ?? 0) + 1 - return handle - } - } - - func get(handle: Handle) -> T? { - lock.withLock { - leftMap[handle] - } - } - - func delete(handle: Handle) { - remove(handle: handle) - } - - @discardableResult - func remove(handle: Handle) -> T? { - lock.withLock { - defer { counter[handle] = (counter[handle] ?? 1) - 1 } - guard counter[handle] == 1 else { return leftMap[handle] } - let obj = leftMap.removeValue(forKey: handle) - if let obj = obj { - rightMap.removeValue(forKey: ObjectIdentifier(obj as AnyObject)) - } - return obj - } - } -} - -// 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 - -fileprivate class FfiConverterCallbackInterface { - fileprivate let handleMap = ConcurrentHandleMap() - - func drop(handle: Handle) { - handleMap.remove(handle: handle) - } - - func lift(_ handle: Handle) throws -> CallbackInterface { - guard let callback = handleMap.get(handle: handle) else { - throw UniffiInternalError.unexpectedStaleHandle - } - return callback - } - - func read(from buf: Reader) throws -> CallbackInterface { - let handle: Handle = try buf.readInt() - return try lift(handle) - } - - func lower(_ v: CallbackInterface) -> Handle { - let handle = handleMap.insert(obj: v) - return handle - // assert(handleMap.get(handle: obj) == v, "Handle map is not returning the object we just placed there. This is a bug in the HandleMap.") - } - - func write(_ v: CallbackInterface, into buf: Writer) { - buf.writeInt(lower(v)) - } -} - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - -public enum Network { - - case bitcoin - case testnet - case signet - case regtest -} - -extension Network: ViaFfiUsingByteBuffer, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> Network { - let variant: Int32 = try buf.readInt() - switch variant { - - case 1: return .bitcoin - case 2: return .testnet - case 3: return .signet - case 4: return .regtest - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - fileprivate func write(into buf: Writer) { - switch self { - - - case .bitcoin: - buf.writeInt(Int32(1)) - - - case .testnet: - buf.writeInt(Int32(2)) - - - case .signet: - buf.writeInt(Int32(3)) - - - case .regtest: - buf.writeInt(Int32(4)) - - } - } -} - - -extension Network: Equatable, Hashable {} - - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - -public enum DatabaseConfig { - - case memory(junk: String ) - case sled(config: SledDbConfiguration ) -} - -extension DatabaseConfig: ViaFfiUsingByteBuffer, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> DatabaseConfig { - let variant: Int32 = try buf.readInt() - switch variant { - - case 1: return .memory( - junk: try String.read(from: buf) - ) - case 2: return .sled( - config: try SledDbConfiguration.read(from: buf) - ) - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - fileprivate func write(into buf: Writer) { - switch self { - - - case let .memory(junk): - buf.writeInt(Int32(1)) - junk.write(into: buf) - - - - case let .sled(config): - buf.writeInt(Int32(2)) - config.write(into: buf) - - - } - } -} - - -extension DatabaseConfig: Equatable, Hashable {} - - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - -public enum Transaction { - - case unconfirmed(details: TransactionDetails ) - case confirmed(details: TransactionDetails, confirmation: Confirmation ) -} - -extension Transaction: ViaFfiUsingByteBuffer, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> Transaction { - let variant: Int32 = try buf.readInt() - switch variant { - - case 1: return .unconfirmed( - details: try TransactionDetails.read(from: buf) - ) - case 2: return .confirmed( - details: try TransactionDetails.read(from: buf), - confirmation: try Confirmation.read(from: buf) - ) - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - fileprivate func write(into buf: Writer) { - switch self { - - - case let .unconfirmed(details): - buf.writeInt(Int32(1)) - details.write(into: buf) - - - - case let .confirmed(details,confirmation): - buf.writeInt(Int32(2)) - details.write(into: buf) - confirmation.write(into: buf) - - - } - } -} - - -extension Transaction: Equatable, Hashable {} - - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - -public enum BlockchainConfig { - - case electrum(config: ElectrumConfig ) - case esplora(config: EsploraConfig ) -} - -extension BlockchainConfig: ViaFfiUsingByteBuffer, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> BlockchainConfig { - let variant: Int32 = try buf.readInt() - switch variant { - - case 1: return .electrum( - config: try ElectrumConfig.read(from: buf) - ) - case 2: return .esplora( - config: try EsploraConfig.read(from: buf) - ) - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - fileprivate func write(into buf: Writer) { - switch self { - - - case let .electrum(config): - buf.writeInt(Int32(1)) - config.write(into: buf) - - - - case let .esplora(config): - buf.writeInt(Int32(2)) - config.write(into: buf) - - - } - } -} - - -extension BlockchainConfig: Equatable, Hashable {} - - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - -public enum MnemonicType { - - case words12 - case words15 - case words18 - case words21 - case words24 -} - -extension MnemonicType: ViaFfiUsingByteBuffer, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> MnemonicType { - let variant: Int32 = try buf.readInt() - switch variant { - - case 1: return .words12 - case 2: return .words15 - case 3: return .words18 - case 4: return .words21 - case 5: return .words24 - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - fileprivate func write(into buf: Writer) { - switch self { - - - case .words12: - buf.writeInt(Int32(1)) - - - case .words15: - buf.writeInt(Int32(2)) - - - case .words18: - buf.writeInt(Int32(3)) - - - case .words21: - buf.writeInt(Int32(4)) - - - case .words24: - buf.writeInt(Int32(5)) - - } - } -} - - -extension MnemonicType: Equatable, Hashable {} - - - -public func generateExtendedKey(network: Network, mnemonicType: MnemonicType, password: String? ) throws -> ExtendedKeyInfo { - let _retval = try - - - rustCallWithError(BdkError.self) { - - bdk_2e4d_generate_extended_key(network.lower(), mnemonicType.lower(), FfiConverterOptionString.lower(password) , $0) -} - return try ExtendedKeyInfo.lift(_retval) -} - - - -public func restoreExtendedKey(network: Network, mnemonic: String, password: String? ) throws -> ExtendedKeyInfo { - let _retval = try - - - rustCallWithError(BdkError.self) { - - bdk_2e4d_restore_extended_key(network.lower(), mnemonic.lower(), FfiConverterOptionString.lower(password) , $0) -} - return try ExtendedKeyInfo.lift(_retval) -} - - - -public protocol OfflineWalletProtocol { - func getNewAddress() -> String - func getLastUnusedAddress() -> String - func getBalance() throws -> UInt64 - func sign(psbt: PartiallySignedBitcoinTransaction ) throws - func getTransactions() throws -> [Transaction] - -} - -public class OfflineWallet: OfflineWalletProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `ViaFfi` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init(descriptor: String, network: Network, databaseConfig: DatabaseConfig ) throws { - self.init(unsafeFromRawPointer: try - - - rustCallWithError(BdkError.self) { - - bdk_2e4d_OfflineWallet_new(descriptor.lower(), network.lower(), databaseConfig.lower() , $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_2e4d_OfflineWallet_object_free(pointer, $0) } - } - - - - - public func getNewAddress() -> String { - let _retval = try! - rustCall() { - - bdk_2e4d_OfflineWallet_get_new_address(self.pointer, $0 - ) -} - return try! String.lift(_retval) - } - public func getLastUnusedAddress() -> String { - let _retval = try! - rustCall() { - - bdk_2e4d_OfflineWallet_get_last_unused_address(self.pointer, $0 - ) -} - return try! String.lift(_retval) - } - public func getBalance() throws -> UInt64 { - let _retval = try - rustCallWithError(BdkError.self) { - - bdk_2e4d_OfflineWallet_get_balance(self.pointer, $0 - ) -} - return try UInt64.lift(_retval) - } - public func sign(psbt: PartiallySignedBitcoinTransaction ) throws { - try - rustCallWithError(BdkError.self) { - - bdk_2e4d_OfflineWallet_sign(self.pointer, psbt.lower() , $0 - ) -} - } - public func getTransactions() throws -> [Transaction] { - let _retval = try - rustCallWithError(BdkError.self) { - - bdk_2e4d_OfflineWallet_get_transactions(self.pointer, $0 - ) -} - return try FfiConverterSequenceEnumTransaction.lift(_retval) - } - -} - - -fileprivate extension OfflineWallet { - fileprivate typealias FfiType = UnsafeMutableRawPointer - - fileprivate static func read(from buf: Reader) throws -> Self { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try self.lift(ptr!) - } - - fileprivate func write(into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) - } - - fileprivate static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { - return Self(unsafeFromRawPointer: pointer) - } - - fileprivate func lower() -> UnsafeMutableRawPointer { - return self.pointer - } -} - -// Ideally this would be `fileprivate`, but Swift says: -// """ -// 'private' modifier cannot be used with extensions that declare protocol conformances -// """ -extension OfflineWallet : ViaFfi, Serializable {} - - -public protocol OnlineWalletProtocol { - func getNewAddress() -> String - func getLastUnusedAddress() -> String - func getBalance() throws -> UInt64 - func sign(psbt: PartiallySignedBitcoinTransaction ) throws - func getTransactions() throws -> [Transaction] - func getNetwork() -> Network - func sync(progressUpdate: BdkProgress, maxAddressParam: UInt32? ) throws - func broadcast(psbt: PartiallySignedBitcoinTransaction ) throws -> Transaction - -} - -public class OnlineWallet: OnlineWalletProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `ViaFfi` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init(descriptor: String, changeDescriptor: String?, network: Network, databaseConfig: DatabaseConfig, blockchainConfig: BlockchainConfig ) throws { - self.init(unsafeFromRawPointer: try - - - rustCallWithError(BdkError.self) { - - bdk_2e4d_OnlineWallet_new(descriptor.lower(), FfiConverterOptionString.lower(changeDescriptor), network.lower(), databaseConfig.lower(), blockchainConfig.lower() , $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_2e4d_OnlineWallet_object_free(pointer, $0) } - } - - - - - public func getNewAddress() -> String { - let _retval = try! - rustCall() { - - bdk_2e4d_OnlineWallet_get_new_address(self.pointer, $0 - ) -} - return try! String.lift(_retval) - } - public func getLastUnusedAddress() -> String { - let _retval = try! - rustCall() { - - bdk_2e4d_OnlineWallet_get_last_unused_address(self.pointer, $0 - ) -} - return try! String.lift(_retval) - } - public func getBalance() throws -> UInt64 { - let _retval = try - rustCallWithError(BdkError.self) { - - bdk_2e4d_OnlineWallet_get_balance(self.pointer, $0 - ) -} - return try UInt64.lift(_retval) - } - public func sign(psbt: PartiallySignedBitcoinTransaction ) throws { - try - rustCallWithError(BdkError.self) { - - bdk_2e4d_OnlineWallet_sign(self.pointer, psbt.lower() , $0 - ) -} - } - public func getTransactions() throws -> [Transaction] { - let _retval = try - rustCallWithError(BdkError.self) { - - bdk_2e4d_OnlineWallet_get_transactions(self.pointer, $0 - ) -} - return try FfiConverterSequenceEnumTransaction.lift(_retval) - } - public func getNetwork() -> Network { - let _retval = try! - rustCall() { - - bdk_2e4d_OnlineWallet_get_network(self.pointer, $0 - ) -} - return try! Network.lift(_retval) - } - public func sync(progressUpdate: BdkProgress, maxAddressParam: UInt32? ) throws { - try - rustCallWithError(BdkError.self) { - - bdk_2e4d_OnlineWallet_sync(self.pointer, ffiConverterCallbackInterfaceBdkProgress.lower(progressUpdate), FfiConverterOptionUInt32.lower(maxAddressParam) , $0 - ) -} - } - public func broadcast(psbt: PartiallySignedBitcoinTransaction ) throws -> Transaction { - let _retval = try - rustCallWithError(BdkError.self) { - - bdk_2e4d_OnlineWallet_broadcast(self.pointer, psbt.lower() , $0 - ) -} - return try Transaction.lift(_retval) - } - -} - - -fileprivate extension OnlineWallet { - fileprivate typealias FfiType = UnsafeMutableRawPointer - - fileprivate static func read(from buf: Reader) throws -> Self { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try self.lift(ptr!) - } - - fileprivate func write(into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) - } - - fileprivate static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { - return Self(unsafeFromRawPointer: pointer) - } - - fileprivate func lower() -> UnsafeMutableRawPointer { - return self.pointer - } -} - -// Ideally this would be `fileprivate`, but Swift says: -// """ -// 'private' modifier cannot be used with extensions that declare protocol conformances -// """ -extension OnlineWallet : ViaFfi, Serializable {} - - -public protocol PartiallySignedBitcoinTransactionProtocol { - -} - -public class PartiallySignedBitcoinTransaction: PartiallySignedBitcoinTransactionProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `ViaFfi` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init(wallet: OnlineWallet, recipient: String, amount: UInt64, feeRate: Float? ) throws { - self.init(unsafeFromRawPointer: try - - - rustCallWithError(BdkError.self) { - - bdk_2e4d_PartiallySignedBitcoinTransaction_new(wallet.lower(), recipient.lower(), amount.lower(), FfiConverterOptionFloat.lower(feeRate) , $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_2e4d_PartiallySignedBitcoinTransaction_object_free(pointer, $0) } - } - - - - - -} - - -fileprivate extension PartiallySignedBitcoinTransaction { - fileprivate typealias FfiType = UnsafeMutableRawPointer - - fileprivate static func read(from buf: Reader) throws -> Self { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try self.lift(ptr!) - } - - fileprivate func write(into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) - } - - fileprivate static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { - return Self(unsafeFromRawPointer: pointer) - } - - fileprivate func lower() -> UnsafeMutableRawPointer { - return self.pointer - } -} - -// Ideally this would be `fileprivate`, but Swift says: -// """ -// 'private' modifier cannot be used with extensions that declare protocol conformances -// """ -extension PartiallySignedBitcoinTransaction : ViaFfi, Serializable {} - -public struct SledDbConfiguration { - public var path: String - public var treeName: String - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(path: String, treeName: String ) { - self.path = path - self.treeName = treeName - } -} - - -extension SledDbConfiguration: Equatable, Hashable { - public static func ==(lhs: SledDbConfiguration, rhs: SledDbConfiguration) -> Bool { - if lhs.path != rhs.path { - return false - } - if lhs.treeName != rhs.treeName { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(path) - hasher.combine(treeName) - } -} - - -fileprivate extension SledDbConfiguration { - static func read(from buf: Reader) throws -> SledDbConfiguration { - return try SledDbConfiguration( - path: String.read(from: buf), - treeName: String.read(from: buf) - ) - } - - func write(into buf: Writer) { - self.path.write(into: buf) - self.treeName.write(into: buf) - } -} - -extension SledDbConfiguration: ViaFfiUsingByteBuffer, ViaFfi {} - -public struct TransactionDetails { - public var fees: UInt64? - public var received: UInt64 - public var sent: UInt64 - public var txid: String - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(fees: UInt64?, received: UInt64, sent: UInt64, txid: String ) { - self.fees = fees - self.received = received - self.sent = sent - self.txid = txid - } -} - - -extension TransactionDetails: Equatable, Hashable { - public static func ==(lhs: TransactionDetails, rhs: TransactionDetails) -> Bool { - if lhs.fees != rhs.fees { - return false - } - if lhs.received != rhs.received { - return false - } - if lhs.sent != rhs.sent { - return false - } - if lhs.txid != rhs.txid { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(fees) - hasher.combine(received) - hasher.combine(sent) - hasher.combine(txid) - } -} - - -fileprivate extension TransactionDetails { - static func read(from buf: Reader) throws -> TransactionDetails { - return try TransactionDetails( - fees: FfiConverterOptionUInt64.read(from: buf), - received: UInt64.read(from: buf), - sent: UInt64.read(from: buf), - txid: String.read(from: buf) - ) - } - - func write(into buf: Writer) { - FfiConverterOptionUInt64.write(self.fees, into: buf) - self.received.write(into: buf) - self.sent.write(into: buf) - self.txid.write(into: buf) - } -} - -extension TransactionDetails: ViaFfiUsingByteBuffer, ViaFfi {} - -public struct Confirmation { - public var height: UInt32 - public var timestamp: UInt64 - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(height: UInt32, timestamp: UInt64 ) { - self.height = height - self.timestamp = timestamp - } -} - - -extension Confirmation: Equatable, Hashable { - public static func ==(lhs: Confirmation, rhs: Confirmation) -> Bool { - if lhs.height != rhs.height { - return false - } - if lhs.timestamp != rhs.timestamp { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(height) - hasher.combine(timestamp) - } -} - - -fileprivate extension Confirmation { - static func read(from buf: Reader) throws -> Confirmation { - return try Confirmation( - height: UInt32.read(from: buf), - timestamp: UInt64.read(from: buf) - ) - } - - func write(into buf: Writer) { - self.height.write(into: buf) - self.timestamp.write(into: buf) - } -} - -extension Confirmation: ViaFfiUsingByteBuffer, ViaFfi {} - -public struct ElectrumConfig { - public var url: String - public var socks5: String? - public var retry: UInt8 - public var timeout: UInt8? - public var stopGap: UInt64 - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(url: String, socks5: String?, retry: UInt8, timeout: UInt8?, stopGap: UInt64 ) { - self.url = url - self.socks5 = socks5 - self.retry = retry - self.timeout = timeout - self.stopGap = stopGap - } -} - - -extension ElectrumConfig: Equatable, Hashable { - public static func ==(lhs: ElectrumConfig, rhs: ElectrumConfig) -> Bool { - if lhs.url != rhs.url { - return false - } - if lhs.socks5 != rhs.socks5 { - return false - } - if lhs.retry != rhs.retry { - return false - } - if lhs.timeout != rhs.timeout { - return false - } - if lhs.stopGap != rhs.stopGap { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(url) - hasher.combine(socks5) - hasher.combine(retry) - hasher.combine(timeout) - hasher.combine(stopGap) - } -} - - -fileprivate extension ElectrumConfig { - static func read(from buf: Reader) throws -> ElectrumConfig { - return try ElectrumConfig( - url: String.read(from: buf), - socks5: FfiConverterOptionString.read(from: buf), - retry: UInt8.read(from: buf), - timeout: FfiConverterOptionUInt8.read(from: buf), - stopGap: UInt64.read(from: buf) - ) - } - - func write(into buf: Writer) { - self.url.write(into: buf) - FfiConverterOptionString.write(self.socks5, into: buf) - self.retry.write(into: buf) - FfiConverterOptionUInt8.write(self.timeout, into: buf) - self.stopGap.write(into: buf) - } -} - -extension ElectrumConfig: ViaFfiUsingByteBuffer, ViaFfi {} - -public struct EsploraConfig { - public var baseUrl: String - public var proxy: String? - public var timeoutRead: UInt64 - public var timeoutWrite: UInt64 - public var stopGap: UInt64 - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(baseUrl: String, proxy: String?, timeoutRead: UInt64, timeoutWrite: UInt64, stopGap: UInt64 ) { - self.baseUrl = baseUrl - self.proxy = proxy - self.timeoutRead = timeoutRead - self.timeoutWrite = timeoutWrite - self.stopGap = stopGap - } -} - - -extension EsploraConfig: Equatable, Hashable { - public static func ==(lhs: EsploraConfig, rhs: EsploraConfig) -> Bool { - if lhs.baseUrl != rhs.baseUrl { - return false - } - if lhs.proxy != rhs.proxy { - return false - } - if lhs.timeoutRead != rhs.timeoutRead { - return false - } - if lhs.timeoutWrite != rhs.timeoutWrite { - return false - } - if lhs.stopGap != rhs.stopGap { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(baseUrl) - hasher.combine(proxy) - hasher.combine(timeoutRead) - hasher.combine(timeoutWrite) - hasher.combine(stopGap) - } -} - - -fileprivate extension EsploraConfig { - static func read(from buf: Reader) throws -> EsploraConfig { - return try EsploraConfig( - baseUrl: String.read(from: buf), - proxy: FfiConverterOptionString.read(from: buf), - timeoutRead: UInt64.read(from: buf), - timeoutWrite: UInt64.read(from: buf), - stopGap: UInt64.read(from: buf) - ) - } - - func write(into buf: Writer) { - self.baseUrl.write(into: buf) - FfiConverterOptionString.write(self.proxy, into: buf) - self.timeoutRead.write(into: buf) - self.timeoutWrite.write(into: buf) - self.stopGap.write(into: buf) - } -} - -extension EsploraConfig: ViaFfiUsingByteBuffer, ViaFfi {} - -public struct ExtendedKeyInfo { - public var mnemonic: String - public var xprv: String - public var fingerprint: String - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(mnemonic: String, xprv: String, fingerprint: String ) { - self.mnemonic = mnemonic - self.xprv = xprv - self.fingerprint = fingerprint - } -} - - -extension ExtendedKeyInfo: Equatable, Hashable { - public static func ==(lhs: ExtendedKeyInfo, rhs: ExtendedKeyInfo) -> Bool { - if lhs.mnemonic != rhs.mnemonic { - return false - } - if lhs.xprv != rhs.xprv { - return false - } - if lhs.fingerprint != rhs.fingerprint { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(mnemonic) - hasher.combine(xprv) - hasher.combine(fingerprint) - } -} - - -fileprivate extension ExtendedKeyInfo { - static func read(from buf: Reader) throws -> ExtendedKeyInfo { - return try ExtendedKeyInfo( - mnemonic: String.read(from: buf), - xprv: String.read(from: buf), - fingerprint: String.read(from: buf) - ) - } - - func write(into buf: Writer) { - self.mnemonic.write(into: buf) - self.xprv.write(into: buf) - self.fingerprint.write(into: buf) - } -} - -extension ExtendedKeyInfo: ViaFfiUsingByteBuffer, ViaFfi {} - -public enum BdkError { - - - - // Simple error enums only carry a message - case InvalidU32Bytes(message: String) - - // Simple error enums only carry a message - case Generic(message: String) - - // Simple error enums only carry a message - case ScriptDoesntHaveAddressForm(message: String) - - // Simple error enums only carry a message - case NoRecipients(message: String) - - // Simple error enums only carry a message - case NoUtxosSelected(message: String) - - // Simple error enums only carry a message - case OutputBelowDustLimit(message: String) - - // Simple error enums only carry a message - case InsufficientFunds(message: String) - - // Simple error enums only carry a message - case BnBTotalTriesExceeded(message: String) - - // Simple error enums only carry a message - case BnBNoExactMatch(message: String) - - // Simple error enums only carry a message - case UnknownUtxo(message: String) - - // Simple error enums only carry a message - case TransactionNotFound(message: String) - - // Simple error enums only carry a message - case TransactionConfirmed(message: String) - - // Simple error enums only carry a message - case IrreplaceableTransaction(message: String) - - // Simple error enums only carry a message - case FeeRateTooLow(message: String) - - // Simple error enums only carry a message - case FeeTooLow(message: String) - - // Simple error enums only carry a message - case FeeRateUnavailable(message: String) - - // Simple error enums only carry a message - case MissingKeyOrigin(message: String) - - // Simple error enums only carry a message - case Key(message: String) - - // Simple error enums only carry a message - case ChecksumMismatch(message: String) - - // Simple error enums only carry a message - case SpendingPolicyRequired(message: String) - - // Simple error enums only carry a message - case InvalidPolicyPathError(message: String) - - // Simple error enums only carry a message - case Signer(message: String) - - // Simple error enums only carry a message - case InvalidNetwork(message: String) - - // Simple error enums only carry a message - case InvalidProgressValue(message: String) - - // Simple error enums only carry a message - case ProgressUpdateError(message: String) - - // Simple error enums only carry a message - case InvalidOutpoint(message: String) - - // Simple error enums only carry a message - case Descriptor(message: String) - - // Simple error enums only carry a message - case AddressValidator(message: String) - - // Simple error enums only carry a message - case Encode(message: String) - - // Simple error enums only carry a message - case Miniscript(message: String) - - // Simple error enums only carry a message - case Bip32(message: String) - - // Simple error enums only carry a message - case Secp256k1(message: String) - - // Simple error enums only carry a message - case Json(message: String) - - // Simple error enums only carry a message - case Hex(message: String) - - // Simple error enums only carry a message - case Psbt(message: String) - - // Simple error enums only carry a message - case PsbtParse(message: String) - - // Simple error enums only carry a message - case Electrum(message: String) - - // Simple error enums only carry a message - case Esplora(message: String) - - // Simple error enums only carry a message - case Sled(message: String) - -} - -extension BdkError: ViaFfiUsingByteBuffer, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> BdkError { - let variant: Int32 = try buf.readInt() - switch variant { - - - - - case 1: return .InvalidU32Bytes( - message: try String.read(from: buf) - ) - - case 2: return .Generic( - message: try String.read(from: buf) - ) - - case 3: return .ScriptDoesntHaveAddressForm( - message: try String.read(from: buf) - ) - - case 4: return .NoRecipients( - message: try String.read(from: buf) - ) - - case 5: return .NoUtxosSelected( - message: try String.read(from: buf) - ) - - case 6: return .OutputBelowDustLimit( - message: try String.read(from: buf) - ) - - case 7: return .InsufficientFunds( - message: try String.read(from: buf) - ) - - case 8: return .BnBTotalTriesExceeded( - message: try String.read(from: buf) - ) - - case 9: return .BnBNoExactMatch( - message: try String.read(from: buf) - ) - - case 10: return .UnknownUtxo( - message: try String.read(from: buf) - ) - - case 11: return .TransactionNotFound( - message: try String.read(from: buf) - ) - - case 12: return .TransactionConfirmed( - message: try String.read(from: buf) - ) - - case 13: return .IrreplaceableTransaction( - message: try String.read(from: buf) - ) - - case 14: return .FeeRateTooLow( - message: try String.read(from: buf) - ) - - case 15: return .FeeTooLow( - message: try String.read(from: buf) - ) - - case 16: return .FeeRateUnavailable( - message: try String.read(from: buf) - ) - - case 17: return .MissingKeyOrigin( - message: try String.read(from: buf) - ) - - case 18: return .Key( - message: try String.read(from: buf) - ) - - case 19: return .ChecksumMismatch( - message: try String.read(from: buf) - ) - - case 20: return .SpendingPolicyRequired( - message: try String.read(from: buf) - ) - - case 21: return .InvalidPolicyPathError( - message: try String.read(from: buf) - ) - - case 22: return .Signer( - message: try String.read(from: buf) - ) - - case 23: return .InvalidNetwork( - message: try String.read(from: buf) - ) - - case 24: return .InvalidProgressValue( - message: try String.read(from: buf) - ) - - case 25: return .ProgressUpdateError( - message: try String.read(from: buf) - ) - - case 26: return .InvalidOutpoint( - message: try String.read(from: buf) - ) - - case 27: return .Descriptor( - message: try String.read(from: buf) - ) - - case 28: return .AddressValidator( - message: try String.read(from: buf) - ) - - case 29: return .Encode( - message: try String.read(from: buf) - ) - - case 30: return .Miniscript( - message: try String.read(from: buf) - ) - - case 31: return .Bip32( - message: try String.read(from: buf) - ) - - case 32: return .Secp256k1( - message: try String.read(from: buf) - ) - - case 33: return .Json( - message: try String.read(from: buf) - ) - - case 34: return .Hex( - message: try String.read(from: buf) - ) - - case 35: return .Psbt( - message: try String.read(from: buf) - ) - - case 36: return .PsbtParse( - message: try String.read(from: buf) - ) - - case 37: return .Electrum( - message: try String.read(from: buf) - ) - - case 38: return .Esplora( - message: try String.read(from: buf) - ) - - case 39: return .Sled( - message: try String.read(from: buf) - ) - - - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - fileprivate func write(into buf: Writer) { - switch self { - - - - - case let .InvalidU32Bytes(message): - buf.writeInt(Int32(1)) - message.write(into: buf) - case let .Generic(message): - buf.writeInt(Int32(2)) - message.write(into: buf) - case let .ScriptDoesntHaveAddressForm(message): - buf.writeInt(Int32(3)) - message.write(into: buf) - case let .NoRecipients(message): - buf.writeInt(Int32(4)) - message.write(into: buf) - case let .NoUtxosSelected(message): - buf.writeInt(Int32(5)) - message.write(into: buf) - case let .OutputBelowDustLimit(message): - buf.writeInt(Int32(6)) - message.write(into: buf) - case let .InsufficientFunds(message): - buf.writeInt(Int32(7)) - message.write(into: buf) - case let .BnBTotalTriesExceeded(message): - buf.writeInt(Int32(8)) - message.write(into: buf) - case let .BnBNoExactMatch(message): - buf.writeInt(Int32(9)) - message.write(into: buf) - case let .UnknownUtxo(message): - buf.writeInt(Int32(10)) - message.write(into: buf) - case let .TransactionNotFound(message): - buf.writeInt(Int32(11)) - message.write(into: buf) - case let .TransactionConfirmed(message): - buf.writeInt(Int32(12)) - message.write(into: buf) - case let .IrreplaceableTransaction(message): - buf.writeInt(Int32(13)) - message.write(into: buf) - case let .FeeRateTooLow(message): - buf.writeInt(Int32(14)) - message.write(into: buf) - case let .FeeTooLow(message): - buf.writeInt(Int32(15)) - message.write(into: buf) - case let .FeeRateUnavailable(message): - buf.writeInt(Int32(16)) - message.write(into: buf) - case let .MissingKeyOrigin(message): - buf.writeInt(Int32(17)) - message.write(into: buf) - case let .Key(message): - buf.writeInt(Int32(18)) - message.write(into: buf) - case let .ChecksumMismatch(message): - buf.writeInt(Int32(19)) - message.write(into: buf) - case let .SpendingPolicyRequired(message): - buf.writeInt(Int32(20)) - message.write(into: buf) - case let .InvalidPolicyPathError(message): - buf.writeInt(Int32(21)) - message.write(into: buf) - case let .Signer(message): - buf.writeInt(Int32(22)) - message.write(into: buf) - case let .InvalidNetwork(message): - buf.writeInt(Int32(23)) - message.write(into: buf) - case let .InvalidProgressValue(message): - buf.writeInt(Int32(24)) - message.write(into: buf) - case let .ProgressUpdateError(message): - buf.writeInt(Int32(25)) - message.write(into: buf) - case let .InvalidOutpoint(message): - buf.writeInt(Int32(26)) - message.write(into: buf) - case let .Descriptor(message): - buf.writeInt(Int32(27)) - message.write(into: buf) - case let .AddressValidator(message): - buf.writeInt(Int32(28)) - message.write(into: buf) - case let .Encode(message): - buf.writeInt(Int32(29)) - message.write(into: buf) - case let .Miniscript(message): - buf.writeInt(Int32(30)) - message.write(into: buf) - case let .Bip32(message): - buf.writeInt(Int32(31)) - message.write(into: buf) - case let .Secp256k1(message): - buf.writeInt(Int32(32)) - message.write(into: buf) - case let .Json(message): - buf.writeInt(Int32(33)) - message.write(into: buf) - case let .Hex(message): - buf.writeInt(Int32(34)) - message.write(into: buf) - case let .Psbt(message): - buf.writeInt(Int32(35)) - message.write(into: buf) - case let .PsbtParse(message): - buf.writeInt(Int32(36)) - message.write(into: buf) - case let .Electrum(message): - buf.writeInt(Int32(37)) - message.write(into: buf) - case let .Esplora(message): - buf.writeInt(Int32(38)) - message.write(into: buf) - case let .Sled(message): - buf.writeInt(Int32(39)) - message.write(into: buf) - } - } -} - - -extension BdkError: Equatable, Hashable {} - -extension BdkError: Error { } - - -// Declaration and FfiConverters for BdkProgress Callback Interface - -public protocol BdkProgress : AnyObject { - func update(progress: Float, message: String? ) - -} - -// The ForeignCallback that is passed to Rust. -fileprivate let foreignCallbackCallbackInterfaceBdkProgress : ForeignCallback = - { (handle: Handle, method: Int32, args: RustBuffer) -> RustBuffer in - func invokeUpdate(_ swiftCallbackInterface: BdkProgress, _ args: RustBuffer) throws -> RustBuffer { - defer { args.deallocate() } - - let reader = Reader(data: Data(rustBuffer: args)) - swiftCallbackInterface.update( - progress: try Float.read(from: reader), - message: try FfiConverterOptionString.read(from: reader) - ) - return RustBuffer() - // TODO catch errors and report them back to Rust. - // https://github.com/mozilla/uniffi-rs/issues/351 - - } - - - let cb = try! ffiConverterCallbackInterfaceBdkProgress.lift(handle) - switch method { - case IDX_CALLBACK_FREE: - ffiConverterCallbackInterfaceBdkProgress.drop(handle: handle) - return RustBuffer() - case 1: return try! invokeUpdate(cb, args) - - // This should never happen, because an out of bounds method index won't - // ever be used. Once we can catch errors, we should return an InternalError. - // https://github.com/mozilla/uniffi-rs/issues/351 - default: return RustBuffer() - } - } - -// The ffiConverter which transforms the Callbacks in to Handles to pass to Rust. -private let ffiConverterCallbackInterfaceBdkProgress: FfiConverterCallbackInterface = { - try! rustCall { (err: UnsafeMutablePointer) in - ffi_bdk_2e4d_BdkProgress_init_callback(foreignCallbackCallbackInterfaceBdkProgress, err) - } - return FfiConverterCallbackInterface() -}() -extension UInt8: Primitive, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> Self { - return try self.lift(buf.readInt()) - } - - fileprivate func write(into buf: Writer) { - buf.writeInt(self.lower()) - } -} -extension UInt32: Primitive, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> Self { - return try self.lift(buf.readInt()) - } - - fileprivate func write(into buf: Writer) { - buf.writeInt(self.lower()) - } -} -extension UInt64: Primitive, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> Self { - return try self.lift(buf.readInt()) - } - - fileprivate func write(into buf: Writer) { - buf.writeInt(self.lower()) - } -} -extension Float: Primitive, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> Self { - return try self.lift(buf.readFloat()) - } - - fileprivate func write(into buf: Writer) { - buf.writeFloat(self.lower()) - } -} -extension String: ViaFfi { - fileprivate typealias FfiType = RustBuffer - - fileprivate static func lift(_ v: FfiType) throws -> Self { - defer { - v.deallocate() - } - if v.data == nil { - return String() - } - let bytes = UnsafeBufferPointer(start: v.data!, count: Int(v.len)) - return String(bytes: bytes, encoding: String.Encoding.utf8)! - } - - fileprivate func lower() -> FfiType { - return self.utf8CString.withUnsafeBufferPointer { ptr in - // The swift string gives us int8_t, we want uint8_t. - ptr.withMemoryRebound(to: UInt8.self) { ptr in - // The swift string gives us a trailing null byte, we don't want it. - let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) - return RustBuffer.from(buf) - } - } - } - - fileprivate static func read(from buf: Reader) throws -> Self { - let len: Int32 = try buf.readInt() - return String(bytes: try buf.readBytes(count: Int(len)), encoding: String.Encoding.utf8)! - } - - fileprivate func write(into buf: Writer) { - let len = Int32(self.utf8.count) - buf.writeInt(len) - buf.writeBytes(self.utf8) - } -} -// Helper code for OfflineWallet class is found in ObjectTemplate.swift -// Helper code for OnlineWallet class is found in ObjectTemplate.swift -// Helper code for PartiallySignedBitcoinTransaction class is found in ObjectTemplate.swift -// Helper code for Confirmation record is found in RecordTemplate.swift -// Helper code for ElectrumConfig record is found in RecordTemplate.swift -// Helper code for EsploraConfig record is found in RecordTemplate.swift -// Helper code for ExtendedKeyInfo record is found in RecordTemplate.swift -// Helper code for SledDbConfiguration record is found in RecordTemplate.swift -// Helper code for TransactionDetails record is found in RecordTemplate.swift -// Helper code for BlockchainConfig enum is found in EnumTemplate.swift -// Helper code for DatabaseConfig enum is found in EnumTemplate.swift -// Helper code for MnemonicType enum is found in EnumTemplate.swift -// Helper code for Network enum is found in EnumTemplate.swift -// Helper code for Transaction enum is found in EnumTemplate.swift -// Helper code for BdkError error is found in ErrorTemplate.swift - -fileprivate enum FfiConverterOptionUInt8: FfiConverterUsingByteBuffer { - typealias SwiftType = UInt8? - - static func write(_ value: SwiftType, into buf: Writer) { - FfiConverterOptional.write(value, into: buf) { item, buf in - item.write(into: buf) - } - } - - static func read(from buf: Reader) throws -> SwiftType { - try FfiConverterOptional.read(from: buf) { buf in - try UInt8.read(from: buf) - } - } -} - -fileprivate enum FfiConverterOptionUInt32: FfiConverterUsingByteBuffer { - typealias SwiftType = UInt32? - - static func write(_ value: SwiftType, into buf: Writer) { - FfiConverterOptional.write(value, into: buf) { item, buf in - item.write(into: buf) - } - } - - static func read(from buf: Reader) throws -> SwiftType { - try FfiConverterOptional.read(from: buf) { buf in - try UInt32.read(from: buf) - } - } -} - -fileprivate enum FfiConverterOptionUInt64: FfiConverterUsingByteBuffer { - typealias SwiftType = UInt64? - - static func write(_ value: SwiftType, into buf: Writer) { - FfiConverterOptional.write(value, into: buf) { item, buf in - item.write(into: buf) - } - } - - static func read(from buf: Reader) throws -> SwiftType { - try FfiConverterOptional.read(from: buf) { buf in - try UInt64.read(from: buf) - } - } -} - -fileprivate enum FfiConverterOptionFloat: FfiConverterUsingByteBuffer { - typealias SwiftType = Float? - - static func write(_ value: SwiftType, into buf: Writer) { - FfiConverterOptional.write(value, into: buf) { item, buf in - item.write(into: buf) - } - } - - static func read(from buf: Reader) throws -> SwiftType { - try FfiConverterOptional.read(from: buf) { buf in - try Float.read(from: buf) - } - } -} - -fileprivate enum FfiConverterOptionString: FfiConverterUsingByteBuffer { - typealias SwiftType = String? - - static func write(_ value: SwiftType, into buf: Writer) { - FfiConverterOptional.write(value, into: buf) { item, buf in - item.write(into: buf) - } - } - - static func read(from buf: Reader) throws -> SwiftType { - try FfiConverterOptional.read(from: buf) { buf in - try String.read(from: buf) - } - } -} - -fileprivate enum FfiConverterSequenceEnumTransaction: FfiConverterUsingByteBuffer { - typealias SwiftType = [Transaction] - - static func write(_ value: SwiftType, into buf: Writer) { - FfiConverterSequence.write(value, into: buf) { (item, buf) in - item.write(into: buf) - } - } - - static func read(from buf: Reader) throws -> SwiftType { - try FfiConverterSequence.read(from: buf) { buf in - try Transaction.read(from: buf) - } - } -} - - -/** - * Top level initializers and tear down methods. - * - * This is generated by uniffi. - */ -public enum BdkLifecycle { - /** - * Initialize the FFI and Rust library. This should be only called once per application. - */ - func initialize() { - - // No initialization code needed - - } -} \ No newline at end of file diff --git a/bdkFFI.xcframework/Info.plist b/bdkFFI.xcframework/Info.plist new file mode 100644 index 0000000..3b0157a --- /dev/null +++ b/bdkFFI.xcframework/Info.plist @@ -0,0 +1,52 @@ + + + + + AvailableLibraries + + + LibraryIdentifier + macos-x86_64 + LibraryPath + bdkFFI.framework + SupportedArchitectures + + x86_64 + + SupportedPlatform + macos + + + LibraryIdentifier + ios-arm64 + LibraryPath + bdkFFI.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + bdkFFI.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Headers/bdkFFI-umbrella.h b/bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Headers/bdkFFI-umbrella.h new file mode 100644 index 0000000..c10f2d9 --- /dev/null +++ b/bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Headers/bdkFFI-umbrella.h @@ -0,0 +1,4 @@ +// This is the "umbrella header" for our combined Rust code library. +// It needs to import all of the individual headers. + +#import "bdkFFI.h" diff --git a/bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Modules/module.modulemap b/bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Modules/module.modulemap new file mode 100644 index 0000000..1b7f601 --- /dev/null +++ b/bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module bdkFFI { + umbrella header "bdkFFI-umbrella.h" + + export * + module * { export * } +} diff --git a/bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Headers/bdkFFI-umbrella.h b/bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Headers/bdkFFI-umbrella.h new file mode 100644 index 0000000..c10f2d9 --- /dev/null +++ b/bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Headers/bdkFFI-umbrella.h @@ -0,0 +1,4 @@ +// This is the "umbrella header" for our combined Rust code library. +// It needs to import all of the individual headers. + +#import "bdkFFI.h" diff --git a/bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Modules/module.modulemap b/bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Modules/module.modulemap new file mode 100644 index 0000000..1b7f601 --- /dev/null +++ b/bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module bdkFFI { + umbrella header "bdkFFI-umbrella.h" + + export * + module * { export * } +} diff --git a/bdkFFI.xcframework/macos-x86_64/bdkFFI.framework/Headers/bdkFFI-umbrella.h b/bdkFFI.xcframework/macos-x86_64/bdkFFI.framework/Headers/bdkFFI-umbrella.h new file mode 100644 index 0000000..c10f2d9 --- /dev/null +++ b/bdkFFI.xcframework/macos-x86_64/bdkFFI.framework/Headers/bdkFFI-umbrella.h @@ -0,0 +1,4 @@ +// This is the "umbrella header" for our combined Rust code library. +// It needs to import all of the individual headers. + +#import "bdkFFI.h" diff --git a/bdkFFI.xcframework/macos-x86_64/bdkFFI.framework/Modules/module.modulemap b/bdkFFI.xcframework/macos-x86_64/bdkFFI.framework/Modules/module.modulemap new file mode 100644 index 0000000..1b7f601 --- /dev/null +++ b/bdkFFI.xcframework/macos-x86_64/bdkFFI.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module bdkFFI { + umbrella header "bdkFFI-umbrella.h" + + export * + module * { export * } +} diff --git a/build.sh b/build.sh index 2e12ca5..c278b29 100755 --- a/build.sh +++ b/build.sh @@ -1,75 +1,59 @@ #!/usr/bin/env bash set -euo pipefail -BUILD_PROFILE=release -BDKFFI_DIR=bdk-ffi -TARGET_DIR=$BDKFFI_DIR/target -STATIC_LIB_NAME=libbdkffi.a -SWIFT_DIR="$BDKFFI_DIR/bindings/bdk-swift" -XCFRAMEWORK_NAME="bdkFFI" -XCFRAMEWORK_ROOT="$XCFRAMEWORK_NAME.xcframework" -XCFRAMEWORK_COMMON="$XCFRAMEWORK_ROOT/common/$XCFRAMEWORK_NAME.framework" - -## build bdk-ffi rust libs -echo "Build bdk-ffi rust library" -pushd $BDKFFI_DIR +## confirm bdk-ffi rust lib builds +pushd bdk-ffi +echo "Confirm bdk-ffi rust lib builds" cargo build --release -echo "Generate bdk-ffi swift bindings" -uniffi-bindgen generate src/bdk.udl --no-format --out-dir bindings/bdk-swift/ --language swift -swiftc -module-name bdk -emit-library -o libbdkffi.dylib -emit-module -emit-module-path bindings/bdk-swift/ -parse-as-library -L target/release/ -lbdkffi -Xcc -fmodule-map-file=bindings/bdk-swift/$XCFRAMEWORK_NAME.modulemap bindings/bdk-swift/bdk.swift -suppress-warnings - -## build bdk-ffi rust libs into xcframework -echo "Build bdk-ffi libs into swift xcframework" +## build bdk-ffi rust libs for apple targets +echo "Build bdk-ffi libs for apple targets" TARGET_TRIPLES=("x86_64-apple-darwin" "x86_64-apple-ios" "aarch64-apple-ios") for TARGET in ${TARGET_TRIPLES[@]}; do echo "Build bdk-ffi lib for target $TARGET" cargo build --release --target $TARGET - echo $? done +echo "Generate bdk-ffi swift bindings" +uniffi-bindgen generate src/bdk.udl --no-format --out-dir ../Sources/BitcoinDevKit --language swift popd -## Manually construct xcframework +# rename bdk.swift bindings to BitcoinDevKit.swift +mv Sources/BitcoinDevKit/bdk.swift Sources/BitcoinDevKit/BitcoinDevKit.swift -# Cleanup prior build -rm -rf "$XCFRAMEWORK_ROOT" -rm -f $XCFRAMEWORK_ROOT.zip +# copy bdkFFI.h to bdkFFI.xcframework platforms +PLATFORMS=("macos-x86_64" "ios-arm64_x86_64-simulator" "ios-arm64") +for PLATFORM in ${PLATFORMS[@]}; do + cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/$PLATFORM/bdkFFI.framework/Headers +done -# Common files -mkdir -p "$XCFRAMEWORK_COMMON/Modules" -cp "$SWIFT_DIR/module.modulemap" "$XCFRAMEWORK_COMMON/Modules/" -mkdir -p "$XCFRAMEWORK_COMMON/Headers" -cp "$SWIFT_DIR/$XCFRAMEWORK_NAME-umbrella.h" "$XCFRAMEWORK_COMMON/Headers" -cp "$SWIFT_DIR/$XCFRAMEWORK_NAME.h" "$XCFRAMEWORK_COMMON/Headers" +# remove unneed .h and .modulemap files +rm Sources/BitcoinDevKit/bdkFFI.h +rm Sources/BitcoinDevkit/bdkFFI.modulemap -# macOS x86_64 hardware -mkdir -p "$XCFRAMEWORK_ROOT/macos-x86_64" -cp -R "$XCFRAMEWORK_COMMON" "$XCFRAMEWORK_ROOT/macos-x86_64/$XCFRAMEWORK_NAME.framework" -cp "$TARGET_DIR/x86_64-apple-darwin/$BUILD_PROFILE/$STATIC_LIB_NAME" "$XCFRAMEWORK_ROOT/macos-x86_64/$XCFRAMEWORK_NAME.framework/$XCFRAMEWORK_NAME" +# add bdkFFI libs to bdkFFI.xcframework -# iOS hardware -mkdir -p "$XCFRAMEWORK_ROOT/ios-arm64" -cp -R "$XCFRAMEWORK_COMMON" "$XCFRAMEWORK_ROOT/ios-arm64/$XCFRAMEWORK_NAME.framework" -cp "$TARGET_DIR/aarch64-apple-ios/$BUILD_PROFILE/$STATIC_LIB_NAME" "$XCFRAMEWORK_ROOT/ios-arm64/$XCFRAMEWORK_NAME.framework/$XCFRAMEWORK_NAME" +# macos-x86_64 platform +cp bdk-ffi/target/x86_64-apple-darwin/release/libbdkffi.a bdkFFI.xcframework/macos-x86_64/bdkFFI.framework/bdkFFI -# iOS simulator, currently x86_64 only (need to make fat binary to add M1) -mkdir -p "$XCFRAMEWORK_ROOT/ios-arm64_x86_64-simulator" -cp -R "$XCFRAMEWORK_COMMON" "$XCFRAMEWORK_ROOT/ios-arm64_x86_64-simulator/$XCFRAMEWORK_NAME.framework" -cp "$TARGET_DIR/x86_64-apple-ios/$BUILD_PROFILE/$STATIC_LIB_NAME" "$XCFRAMEWORK_ROOT/ios-arm64_x86_64-simulator/$XCFRAMEWORK_NAME.framework/$XCFRAMEWORK_NAME" +# ios-arm64 platform +cp bdk-ffi/target/aarch64-apple-ios/release/libbdkffi.a bdkFFI.xcframework/ios-arm64/bdkFFI.framework/bdkFFI + +# ios-arm64_x86_64-simulator, currently x86_64 only (need to make fat binary to add M1) +cp bdk-ffi/target/x86_64-apple-ios/release/libbdkffi.a bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/bdkFFI -# Set up the metadata for the XCFramework as a whole. -cp "$SWIFT_DIR/Info.plist" "$XCFRAMEWORK_ROOT/Info.plist" # TODO add license info -# Remove common -rm -rf "$XCFRAMEWORK_ROOT/common" +# remove any existing bdkFFI.xcframework.zip +rm bdkFFI.xcframework.zip -# Zip it all up into a bundle for distribution. -zip -9 -r "$XCFRAMEWORK_ROOT.zip" "$XCFRAMEWORK_ROOT" +# zip bdkFFI.xcframework directory into a bundle for distribution +zip -9 -r bdkFFI.xcframework.zip bdkFFI.xcframework +# compute bdkFFI.xcframework.zip checksum +echo checksum: swift package compute-checksum bdkFFI.xcframework.zip -# Cleanup build ? -# rm -rf "$XCFRAMEWORK_ROOT" +# TODO update Package.swift with checksum +# TODO upload zip to github release From a74f5caaff18504791414a09961757b3468bc728 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Tue, 23 Nov 2021 23:22:03 -0800 Subject: [PATCH 04/33] Fix bdkFFI checksum --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 21e9347..60dcfdd 100644 --- a/Package.swift +++ b/Package.swift @@ -25,7 +25,7 @@ let package = Package( .binaryTarget( name: "bdkFFI", url: "https://github.com/notmandatory/bdk-swift/releases/download/0.1.0/bdkFFI.xcframework.zip", - checksum: "496423e55dd5db14cb2b692f59ae6bf527431c59f79ab51d89c83f68e23d4722"), + checksum: "a88d3c8a2267e9e8a953fe332a91bd3356f8317e3758499192001993969a9dad"), // .binaryTarget(name: "bdkFFI", path: "./bdkFFI.xcframework"), .target( name: "BitcoinDevKit", From 14c10b6631ed703caa6d90a57405a71bd6397313 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Tue, 23 Nov 2021 23:57:24 -0800 Subject: [PATCH 05/33] Fix bdkFFI url --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 60dcfdd..b149720 100644 --- a/Package.swift +++ b/Package.swift @@ -24,7 +24,7 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages this package depends on. .binaryTarget( name: "bdkFFI", - url: "https://github.com/notmandatory/bdk-swift/releases/download/0.1.0/bdkFFI.xcframework.zip", + url: "https://github.com/notmandatory/bdk-swift/releases/download/0.1.1/bdkFFI.xcframework.zip", checksum: "a88d3c8a2267e9e8a953fe332a91bd3356f8317e3758499192001993969a9dad"), // .binaryTarget(name: "bdkFFI", path: "./bdkFFI.xcframework"), .target( From 18a2efa8daee468847443ebce69d170be8e3c571 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Wed, 24 Nov 2021 00:10:26 -0800 Subject: [PATCH 06/33] Add missing BitcoinDevKit.swift --- .gitignore | 2 - Sources/BitcoinDevKit/BitcoinDevKit.swift | 2113 +++++++++++++++++++++ 2 files changed, 2113 insertions(+), 2 deletions(-) create mode 100644 Sources/BitcoinDevKit/BitcoinDevKit.swift diff --git a/.gitignore b/.gitignore index c850c2d..7a7671d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,3 @@ DerivedData/ bdkFFI.xcframework.zip bdkFFI bdkFFI.h -bdk.swift -BitcoinDevKit.swift diff --git a/Sources/BitcoinDevKit/BitcoinDevKit.swift b/Sources/BitcoinDevKit/BitcoinDevKit.swift new file mode 100644 index 0000000..1c9432e --- /dev/null +++ b/Sources/BitcoinDevKit/BitcoinDevKit.swift @@ -0,0 +1,2113 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! +import Foundation + +// Depending on the consumer's build setup, the low-level FFI code +// might be in a separate module, or it might be compiled inline into +// this module. This is a bit of light hackery to work with both. +#if canImport(bdkFFI) +import bdkFFI +#endif + +fileprivate extension RustBuffer { + // Allocate a new buffer, copying the contents of a `UInt8` array. + init(bytes: [UInt8]) { + let rbuf = bytes.withUnsafeBufferPointer { ptr in + RustBuffer.from(ptr) + } + self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) + } + + static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { + try! rustCall { ffi_bdk_2e4d_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } + } + + // Frees the buffer in place. + // The buffer must not be used after this is called. + func deallocate() { + try! rustCall { ffi_bdk_2e4d_rustbuffer_free(self, $0) } + } +} + +fileprivate extension ForeignBytes { + init(bufferPointer: UnsafeBufferPointer) { + self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) + } +} + +// For every type used in the interface, we provide helper methods for conveniently +// lifting and lowering that type from C-compatible data, and for reading and writing +// values of that type in a buffer. + +// Helper classes/extensions that don't change. +// Someday, this will be in a libray of its own. + +fileprivate extension Data { + init(rustBuffer: RustBuffer) { + // TODO: This copies the buffer. Can we read directly from a + // Rust buffer? + self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len)) + } +} + +// A helper class to read values out of a byte buffer. +fileprivate class Reader { + let data: Data + var offset: Data.Index + + init(data: Data) { + self.data = data + self.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. + func readInt() throws -> T { + let range = offset...size + guard data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + if T.self == UInt8.self { + let value = data[offset] + offset += 1 + return value as! T + } + var value: T = 0 + let _ = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0, from: range)}) + offset = range.upperBound + return value.bigEndian + } + + // Reads an arbitrary number of bytes, to be used to read + // raw bytes, this is useful when lifting strings + func readBytes(count: Int) throws -> Array { + let range = offset..<(offset+count) + guard data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + var value = [UInt8](repeating: 0, count: count) + value.withUnsafeMutableBufferPointer({ buffer in + data.copyBytes(to: buffer, from: range) + }) + offset = range.upperBound + return value + } + + // Reads a float at the current offset. + @inlinable + func readFloat() throws -> Float { + return Float(bitPattern: try readInt()) + } + + // Reads a float at the current offset. + @inlinable + func readDouble() throws -> Double { + return Double(bitPattern: try readInt()) + } + + // Indicates if the offset has reached the end of the buffer. + @inlinable + func hasRemaining() -> Bool { + return offset < data.count + } +} + +// A helper class to write values into a byte buffer. +fileprivate class Writer { + var bytes: [UInt8] + var offset: Array.Index + + init() { + self.bytes = [] + self.offset = 0 + } + + func writeBytes(_ byteArr: S) where S: Sequence, S.Element == UInt8 { + bytes.append(contentsOf: byteArr) + } + + // Writes an integer in big-endian order. + // + // Warning: make sure what you are trying to write + // is in the correct type! + func writeInt(_ value: T) { + var value = value.bigEndian + withUnsafeBytes(of: &value) { bytes.append(contentsOf: $0) } + } + + @inlinable + func writeFloat(_ value: Float) { + writeInt(value.bitPattern) + } + + @inlinable + func writeDouble(_ value: Double) { + writeInt(value.bitPattern) + } +} + + +// Types conforming to `Serializable` can be read and written in a bytebuffer. +fileprivate protocol Serializable { + func write(into: Writer) + static func read(from: Reader) throws -> Self +} + +// Types confirming to `ViaFfi` can be transferred back-and-for over the FFI. +// This is analogous to the Rust trait of the same name. +fileprivate protocol ViaFfi: Serializable { + associatedtype FfiType + static func lift(_ v: FfiType) throws -> Self + func lower() -> FfiType +} + +// Types conforming to `Primitive` pass themselves directly over the FFI. +fileprivate protocol Primitive {} + +extension Primitive { + fileprivate typealias FfiType = Self + + fileprivate static func lift(_ v: Self) throws -> Self { + return v + } + + fileprivate func lower() -> Self { + return self + } +} + +// Types conforming to `ViaFfiUsingByteBuffer` lift and lower into a bytebuffer. +// Use this for complex types where it's hard to write a custom lift/lower. +fileprivate protocol ViaFfiUsingByteBuffer: Serializable {} + +extension ViaFfiUsingByteBuffer { + fileprivate typealias FfiType = RustBuffer + + fileprivate static func lift(_ buf: FfiType) throws -> Self { + let reader = Reader(data: Data(rustBuffer: buf)) + let value = try Self.read(from: reader) + if reader.hasRemaining() { + throw UniffiInternalError.incompleteData + } + buf.deallocate() + return value + } + + fileprivate func lower() -> FfiType { + let writer = Writer() + self.write(into: writer) + return RustBuffer(bytes: writer.bytes) + } +} +// An error type for FFI errors. These errors occur at the UniFFI level, not +// the library level. +fileprivate enum UniffiInternalError: LocalizedError { + case bufferOverflow + case incompleteData + case unexpectedOptionalTag + case unexpectedEnumCase + case unexpectedNullPointer + case unexpectedRustCallStatusCode + case unexpectedRustCallError + case unexpectedStaleHandle + case rustPanic(_ message: String) + + public var errorDescription: String? { + switch self { + case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" + case .incompleteData: return "The buffer still has data after lifting its containing value" + case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1" + case .unexpectedEnumCase: return "Raw enum value doesn't match any cases" + case .unexpectedNullPointer: return "Raw pointer value was null" + case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code" + case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified" + case .unexpectedStaleHandle: return "The object in the handle map has been dropped already" + case let .rustPanic(message): return message + } + } +} + +fileprivate let CALL_SUCCESS: Int8 = 0 +fileprivate let CALL_ERROR: Int8 = 1 +fileprivate let CALL_PANIC: Int8 = 2 + +fileprivate extension RustCallStatus { + init() { + self.init( + code: CALL_SUCCESS, + errorBuf: RustBuffer.init( + capacity: 0, + len: 0, + data: nil + ) + ) + } +} + +private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T { + try makeRustCall(callback, errorHandler: { + $0.deallocate() + return UniffiInternalError.unexpectedRustCallError + }) +} + +private func rustCallWithError(_ errorClass: E.Type, _ callback: (UnsafeMutablePointer) -> T) throws -> T { + try makeRustCall(callback, errorHandler: { return try E.lift($0) }) +} + +private func makeRustCall(_ callback: (UnsafeMutablePointer) -> T, errorHandler: (RustBuffer) throws -> Error) throws -> T { + var callStatus = RustCallStatus.init() + let returnedVal = callback(&callStatus) + switch callStatus.code { + case CALL_SUCCESS: + return returnedVal + + case CALL_ERROR: + throw try errorHandler(callStatus.errorBuf) + + case CALL_PANIC: + // When the rust code sees a panic, it tries to construct a RustBuffer + // with the message. But if that code panics, then it just sends back + // an empty buffer. + if callStatus.errorBuf.len > 0 { + throw UniffiInternalError.rustPanic(try String.lift(callStatus.errorBuf)) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.rustPanic("Rust panic") + } + + default: + throw UniffiInternalError.unexpectedRustCallStatusCode + } +} +// Protocols for converters we'll implement in templates + +fileprivate protocol FfiConverter { + associatedtype SwiftType + associatedtype FfiType + + static func lift(_ ffiValue: FfiType) throws -> SwiftType + static func lower(_ value: SwiftType) -> FfiType + + static func read(from: Reader) throws -> SwiftType + static func write(_ value: SwiftType, into: Writer) +} + +fileprivate protocol FfiConverterUsingByteBuffer: FfiConverter where FfiType == RustBuffer { + // Empty, because we want to declare some helper methods in the extension below. +} + +extension FfiConverterUsingByteBuffer { + static func lower(_ value: SwiftType) -> FfiType { + let writer = Writer() + Self.write(value, into: writer) + return RustBuffer(bytes: writer.bytes) + } + + static func lift(_ buf: FfiType) throws -> SwiftType { + let reader = Reader(data: Data(rustBuffer: buf)) + let value = try Self.read(from: reader) + if reader.hasRemaining() { + throw UniffiInternalError.incompleteData + } + buf.deallocate() + return value + } +} + +// Helpers for structural types. Note that because of canonical_names, it /should/ be impossible +// to make another `FfiConverterSequence` etc just using the UDL. +fileprivate enum FfiConverterSequence { + static func write(_ value: [T], into buf: Writer, writeItem: (T, Writer) -> Void) { + let len = Int32(value.count) + buf.writeInt(len) + for item in value { + writeItem(item, buf) + } + } + + static func read(from buf: Reader, readItem: (Reader) throws -> T) throws -> [T] { + let len: Int32 = try buf.readInt() + var seq = [T]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try readItem(buf)) + } + return seq + } +} + +fileprivate enum FfiConverterOptional { + static func write(_ value: T?, into buf: Writer, writeItem: (T, Writer) -> Void) { + guard let value = value else { + buf.writeInt(Int8(0)) + return + } + buf.writeInt(Int8(1)) + writeItem(value, buf) + } + + static func read(from buf: Reader, readItem: (Reader) throws -> T) throws -> T? { + switch try buf.readInt() as Int8 { + case 0: return nil + case 1: return try readItem(buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate enum FfiConverterDictionary { + static func write(_ value: [String: T], into buf: Writer, writeItem: (String, T, Writer) -> Void) { + let len = Int32(value.count) + buf.writeInt(len) + for (key, value) in value { + writeItem(key, value, buf) + } + } + + static func read(from buf: Reader, readItem: (Reader) throws -> (String, T)) throws -> [String: T] { + let len: Int32 = try buf.readInt() + var dict = [String: T]() + dict.reserveCapacity(Int(len)) + for _ in 0..(f: () throws -> T) rethrows -> T { + self.lock() + defer { self.unlock() } + return try f() + } +} + +fileprivate typealias Handle = UInt64 +fileprivate class ConcurrentHandleMap { + private var leftMap: [Handle: T] = [:] + private var counter: [Handle: UInt64] = [:] + private var rightMap: [ObjectIdentifier: Handle] = [:] + + private let lock = NSLock() + private var currentHandle: Handle = 0 + private let stride: Handle = 1 + + func insert(obj: T) -> Handle { + lock.withLock { + let id = ObjectIdentifier(obj as AnyObject) + let handle = rightMap[id] ?? { + currentHandle += stride + let handle = currentHandle + leftMap[handle] = obj + rightMap[id] = handle + return handle + }() + counter[handle] = (counter[handle] ?? 0) + 1 + return handle + } + } + + func get(handle: Handle) -> T? { + lock.withLock { + leftMap[handle] + } + } + + func delete(handle: Handle) { + remove(handle: handle) + } + + @discardableResult + func remove(handle: Handle) -> T? { + lock.withLock { + defer { counter[handle] = (counter[handle] ?? 1) - 1 } + guard counter[handle] == 1 else { return leftMap[handle] } + let obj = leftMap.removeValue(forKey: handle) + if let obj = obj { + rightMap.removeValue(forKey: ObjectIdentifier(obj as AnyObject)) + } + return obj + } + } +} + +// 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 + +fileprivate class FfiConverterCallbackInterface { + fileprivate let handleMap = ConcurrentHandleMap() + + func drop(handle: Handle) { + handleMap.remove(handle: handle) + } + + func lift(_ handle: Handle) throws -> CallbackInterface { + guard let callback = handleMap.get(handle: handle) else { + throw UniffiInternalError.unexpectedStaleHandle + } + return callback + } + + func read(from buf: Reader) throws -> CallbackInterface { + let handle: Handle = try buf.readInt() + return try lift(handle) + } + + func lower(_ v: CallbackInterface) -> Handle { + let handle = handleMap.insert(obj: v) + return handle + // assert(handleMap.get(handle: obj) == v, "Handle map is not returning the object we just placed there. This is a bug in the HandleMap.") + } + + func write(_ v: CallbackInterface, into buf: Writer) { + buf.writeInt(lower(v)) + } +} + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum Network { + + case bitcoin + case testnet + case signet + case regtest +} + +extension Network: ViaFfiUsingByteBuffer, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> Network { + let variant: Int32 = try buf.readInt() + switch variant { + + case 1: return .bitcoin + case 2: return .testnet + case 3: return .signet + case 4: return .regtest + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + fileprivate func write(into buf: Writer) { + switch self { + + + case .bitcoin: + buf.writeInt(Int32(1)) + + + case .testnet: + buf.writeInt(Int32(2)) + + + case .signet: + buf.writeInt(Int32(3)) + + + case .regtest: + buf.writeInt(Int32(4)) + + } + } +} + + +extension Network: Equatable, Hashable {} + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum DatabaseConfig { + + case memory(junk: String ) + case sled(config: SledDbConfiguration ) +} + +extension DatabaseConfig: ViaFfiUsingByteBuffer, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> DatabaseConfig { + let variant: Int32 = try buf.readInt() + switch variant { + + case 1: return .memory( + junk: try String.read(from: buf) + ) + case 2: return .sled( + config: try SledDbConfiguration.read(from: buf) + ) + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + fileprivate func write(into buf: Writer) { + switch self { + + + case let .memory(junk): + buf.writeInt(Int32(1)) + junk.write(into: buf) + + + + case let .sled(config): + buf.writeInt(Int32(2)) + config.write(into: buf) + + + } + } +} + + +extension DatabaseConfig: Equatable, Hashable {} + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum Transaction { + + case unconfirmed(details: TransactionDetails ) + case confirmed(details: TransactionDetails, confirmation: Confirmation ) +} + +extension Transaction: ViaFfiUsingByteBuffer, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> Transaction { + let variant: Int32 = try buf.readInt() + switch variant { + + case 1: return .unconfirmed( + details: try TransactionDetails.read(from: buf) + ) + case 2: return .confirmed( + details: try TransactionDetails.read(from: buf), + confirmation: try Confirmation.read(from: buf) + ) + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + fileprivate func write(into buf: Writer) { + switch self { + + + case let .unconfirmed(details): + buf.writeInt(Int32(1)) + details.write(into: buf) + + + + case let .confirmed(details,confirmation): + buf.writeInt(Int32(2)) + details.write(into: buf) + confirmation.write(into: buf) + + + } + } +} + + +extension Transaction: Equatable, Hashable {} + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum BlockchainConfig { + + case electrum(config: ElectrumConfig ) + case esplora(config: EsploraConfig ) +} + +extension BlockchainConfig: ViaFfiUsingByteBuffer, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> BlockchainConfig { + let variant: Int32 = try buf.readInt() + switch variant { + + case 1: return .electrum( + config: try ElectrumConfig.read(from: buf) + ) + case 2: return .esplora( + config: try EsploraConfig.read(from: buf) + ) + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + fileprivate func write(into buf: Writer) { + switch self { + + + case let .electrum(config): + buf.writeInt(Int32(1)) + config.write(into: buf) + + + + case let .esplora(config): + buf.writeInt(Int32(2)) + config.write(into: buf) + + + } + } +} + + +extension BlockchainConfig: Equatable, Hashable {} + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum MnemonicType { + + case words12 + case words15 + case words18 + case words21 + case words24 +} + +extension MnemonicType: ViaFfiUsingByteBuffer, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> MnemonicType { + let variant: Int32 = try buf.readInt() + switch variant { + + case 1: return .words12 + case 2: return .words15 + case 3: return .words18 + case 4: return .words21 + case 5: return .words24 + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + fileprivate func write(into buf: Writer) { + switch self { + + + case .words12: + buf.writeInt(Int32(1)) + + + case .words15: + buf.writeInt(Int32(2)) + + + case .words18: + buf.writeInt(Int32(3)) + + + case .words21: + buf.writeInt(Int32(4)) + + + case .words24: + buf.writeInt(Int32(5)) + + } + } +} + + +extension MnemonicType: Equatable, Hashable {} + + + +public func generateExtendedKey(network: Network, mnemonicType: MnemonicType, password: String? ) throws -> ExtendedKeyInfo { + let _retval = try + + + rustCallWithError(BdkError.self) { + + bdk_2e4d_generate_extended_key(network.lower(), mnemonicType.lower(), FfiConverterOptionString.lower(password) , $0) +} + return try ExtendedKeyInfo.lift(_retval) +} + + + +public func restoreExtendedKey(network: Network, mnemonic: String, password: String? ) throws -> ExtendedKeyInfo { + let _retval = try + + + rustCallWithError(BdkError.self) { + + bdk_2e4d_restore_extended_key(network.lower(), mnemonic.lower(), FfiConverterOptionString.lower(password) , $0) +} + return try ExtendedKeyInfo.lift(_retval) +} + + + +public protocol OfflineWalletProtocol { + func getNewAddress() -> String + func getLastUnusedAddress() -> String + func getBalance() throws -> UInt64 + func sign(psbt: PartiallySignedBitcoinTransaction ) throws + func getTransactions() throws -> [Transaction] + +} + +public class OfflineWallet: OfflineWalletProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `ViaFfi` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(descriptor: String, network: Network, databaseConfig: DatabaseConfig ) throws { + self.init(unsafeFromRawPointer: try + + + rustCallWithError(BdkError.self) { + + bdk_2e4d_OfflineWallet_new(descriptor.lower(), network.lower(), databaseConfig.lower() , $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_2e4d_OfflineWallet_object_free(pointer, $0) } + } + + + + + public func getNewAddress() -> String { + let _retval = try! + rustCall() { + + bdk_2e4d_OfflineWallet_get_new_address(self.pointer, $0 + ) +} + return try! String.lift(_retval) + } + public func getLastUnusedAddress() -> String { + let _retval = try! + rustCall() { + + bdk_2e4d_OfflineWallet_get_last_unused_address(self.pointer, $0 + ) +} + return try! String.lift(_retval) + } + public func getBalance() throws -> UInt64 { + let _retval = try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OfflineWallet_get_balance(self.pointer, $0 + ) +} + return try UInt64.lift(_retval) + } + public func sign(psbt: PartiallySignedBitcoinTransaction ) throws { + try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OfflineWallet_sign(self.pointer, psbt.lower() , $0 + ) +} + } + public func getTransactions() throws -> [Transaction] { + let _retval = try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OfflineWallet_get_transactions(self.pointer, $0 + ) +} + return try FfiConverterSequenceEnumTransaction.lift(_retval) + } + +} + + +fileprivate extension OfflineWallet { + fileprivate typealias FfiType = UnsafeMutableRawPointer + + fileprivate static func read(from buf: Reader) throws -> Self { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try self.lift(ptr!) + } + + fileprivate func write(into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) + } + + fileprivate static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { + return Self(unsafeFromRawPointer: pointer) + } + + fileprivate func lower() -> UnsafeMutableRawPointer { + return self.pointer + } +} + +// Ideally this would be `fileprivate`, but Swift says: +// """ +// 'private' modifier cannot be used with extensions that declare protocol conformances +// """ +extension OfflineWallet : ViaFfi, Serializable {} + + +public protocol OnlineWalletProtocol { + func getNewAddress() -> String + func getLastUnusedAddress() -> String + func getBalance() throws -> UInt64 + func sign(psbt: PartiallySignedBitcoinTransaction ) throws + func getTransactions() throws -> [Transaction] + func getNetwork() -> Network + func sync(progressUpdate: BdkProgress, maxAddressParam: UInt32? ) throws + func broadcast(psbt: PartiallySignedBitcoinTransaction ) throws -> Transaction + +} + +public class OnlineWallet: OnlineWalletProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `ViaFfi` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(descriptor: String, changeDescriptor: String?, network: Network, databaseConfig: DatabaseConfig, blockchainConfig: BlockchainConfig ) throws { + self.init(unsafeFromRawPointer: try + + + rustCallWithError(BdkError.self) { + + bdk_2e4d_OnlineWallet_new(descriptor.lower(), FfiConverterOptionString.lower(changeDescriptor), network.lower(), databaseConfig.lower(), blockchainConfig.lower() , $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_2e4d_OnlineWallet_object_free(pointer, $0) } + } + + + + + public func getNewAddress() -> String { + let _retval = try! + rustCall() { + + bdk_2e4d_OnlineWallet_get_new_address(self.pointer, $0 + ) +} + return try! String.lift(_retval) + } + public func getLastUnusedAddress() -> String { + let _retval = try! + rustCall() { + + bdk_2e4d_OnlineWallet_get_last_unused_address(self.pointer, $0 + ) +} + return try! String.lift(_retval) + } + public func getBalance() throws -> UInt64 { + let _retval = try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OnlineWallet_get_balance(self.pointer, $0 + ) +} + return try UInt64.lift(_retval) + } + public func sign(psbt: PartiallySignedBitcoinTransaction ) throws { + try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OnlineWallet_sign(self.pointer, psbt.lower() , $0 + ) +} + } + public func getTransactions() throws -> [Transaction] { + let _retval = try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OnlineWallet_get_transactions(self.pointer, $0 + ) +} + return try FfiConverterSequenceEnumTransaction.lift(_retval) + } + public func getNetwork() -> Network { + let _retval = try! + rustCall() { + + bdk_2e4d_OnlineWallet_get_network(self.pointer, $0 + ) +} + return try! Network.lift(_retval) + } + public func sync(progressUpdate: BdkProgress, maxAddressParam: UInt32? ) throws { + try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OnlineWallet_sync(self.pointer, ffiConverterCallbackInterfaceBdkProgress.lower(progressUpdate), FfiConverterOptionUInt32.lower(maxAddressParam) , $0 + ) +} + } + public func broadcast(psbt: PartiallySignedBitcoinTransaction ) throws -> Transaction { + let _retval = try + rustCallWithError(BdkError.self) { + + bdk_2e4d_OnlineWallet_broadcast(self.pointer, psbt.lower() , $0 + ) +} + return try Transaction.lift(_retval) + } + +} + + +fileprivate extension OnlineWallet { + fileprivate typealias FfiType = UnsafeMutableRawPointer + + fileprivate static func read(from buf: Reader) throws -> Self { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try self.lift(ptr!) + } + + fileprivate func write(into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) + } + + fileprivate static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { + return Self(unsafeFromRawPointer: pointer) + } + + fileprivate func lower() -> UnsafeMutableRawPointer { + return self.pointer + } +} + +// Ideally this would be `fileprivate`, but Swift says: +// """ +// 'private' modifier cannot be used with extensions that declare protocol conformances +// """ +extension OnlineWallet : ViaFfi, Serializable {} + + +public protocol PartiallySignedBitcoinTransactionProtocol { + +} + +public class PartiallySignedBitcoinTransaction: PartiallySignedBitcoinTransactionProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `ViaFfi` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(wallet: OnlineWallet, recipient: String, amount: UInt64, feeRate: Float? ) throws { + self.init(unsafeFromRawPointer: try + + + rustCallWithError(BdkError.self) { + + bdk_2e4d_PartiallySignedBitcoinTransaction_new(wallet.lower(), recipient.lower(), amount.lower(), FfiConverterOptionFloat.lower(feeRate) , $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_2e4d_PartiallySignedBitcoinTransaction_object_free(pointer, $0) } + } + + + + + +} + + +fileprivate extension PartiallySignedBitcoinTransaction { + fileprivate typealias FfiType = UnsafeMutableRawPointer + + fileprivate static func read(from buf: Reader) throws -> Self { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try self.lift(ptr!) + } + + fileprivate func write(into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) + } + + fileprivate static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { + return Self(unsafeFromRawPointer: pointer) + } + + fileprivate func lower() -> UnsafeMutableRawPointer { + return self.pointer + } +} + +// Ideally this would be `fileprivate`, but Swift says: +// """ +// 'private' modifier cannot be used with extensions that declare protocol conformances +// """ +extension PartiallySignedBitcoinTransaction : ViaFfi, Serializable {} + +public struct SledDbConfiguration { + public var path: String + public var treeName: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(path: String, treeName: String ) { + self.path = path + self.treeName = treeName + } +} + + +extension SledDbConfiguration: Equatable, Hashable { + public static func ==(lhs: SledDbConfiguration, rhs: SledDbConfiguration) -> Bool { + if lhs.path != rhs.path { + return false + } + if lhs.treeName != rhs.treeName { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(path) + hasher.combine(treeName) + } +} + + +fileprivate extension SledDbConfiguration { + static func read(from buf: Reader) throws -> SledDbConfiguration { + return try SledDbConfiguration( + path: String.read(from: buf), + treeName: String.read(from: buf) + ) + } + + func write(into buf: Writer) { + self.path.write(into: buf) + self.treeName.write(into: buf) + } +} + +extension SledDbConfiguration: ViaFfiUsingByteBuffer, ViaFfi {} + +public struct TransactionDetails { + public var fees: UInt64? + public var received: UInt64 + public var sent: UInt64 + public var txid: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(fees: UInt64?, received: UInt64, sent: UInt64, txid: String ) { + self.fees = fees + self.received = received + self.sent = sent + self.txid = txid + } +} + + +extension TransactionDetails: Equatable, Hashable { + public static func ==(lhs: TransactionDetails, rhs: TransactionDetails) -> Bool { + if lhs.fees != rhs.fees { + return false + } + if lhs.received != rhs.received { + return false + } + if lhs.sent != rhs.sent { + return false + } + if lhs.txid != rhs.txid { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(fees) + hasher.combine(received) + hasher.combine(sent) + hasher.combine(txid) + } +} + + +fileprivate extension TransactionDetails { + static func read(from buf: Reader) throws -> TransactionDetails { + return try TransactionDetails( + fees: FfiConverterOptionUInt64.read(from: buf), + received: UInt64.read(from: buf), + sent: UInt64.read(from: buf), + txid: String.read(from: buf) + ) + } + + func write(into buf: Writer) { + FfiConverterOptionUInt64.write(self.fees, into: buf) + self.received.write(into: buf) + self.sent.write(into: buf) + self.txid.write(into: buf) + } +} + +extension TransactionDetails: ViaFfiUsingByteBuffer, ViaFfi {} + +public struct Confirmation { + public var height: UInt32 + public var timestamp: UInt64 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(height: UInt32, timestamp: UInt64 ) { + self.height = height + self.timestamp = timestamp + } +} + + +extension Confirmation: Equatable, Hashable { + public static func ==(lhs: Confirmation, rhs: Confirmation) -> Bool { + if lhs.height != rhs.height { + return false + } + if lhs.timestamp != rhs.timestamp { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(height) + hasher.combine(timestamp) + } +} + + +fileprivate extension Confirmation { + static func read(from buf: Reader) throws -> Confirmation { + return try Confirmation( + height: UInt32.read(from: buf), + timestamp: UInt64.read(from: buf) + ) + } + + func write(into buf: Writer) { + self.height.write(into: buf) + self.timestamp.write(into: buf) + } +} + +extension Confirmation: ViaFfiUsingByteBuffer, ViaFfi {} + +public struct ElectrumConfig { + public var url: String + public var socks5: String? + public var retry: UInt8 + public var timeout: UInt8? + public var stopGap: UInt64 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(url: String, socks5: String?, retry: UInt8, timeout: UInt8?, stopGap: UInt64 ) { + self.url = url + self.socks5 = socks5 + self.retry = retry + self.timeout = timeout + self.stopGap = stopGap + } +} + + +extension ElectrumConfig: Equatable, Hashable { + public static func ==(lhs: ElectrumConfig, rhs: ElectrumConfig) -> Bool { + if lhs.url != rhs.url { + return false + } + if lhs.socks5 != rhs.socks5 { + return false + } + if lhs.retry != rhs.retry { + return false + } + if lhs.timeout != rhs.timeout { + return false + } + if lhs.stopGap != rhs.stopGap { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(url) + hasher.combine(socks5) + hasher.combine(retry) + hasher.combine(timeout) + hasher.combine(stopGap) + } +} + + +fileprivate extension ElectrumConfig { + static func read(from buf: Reader) throws -> ElectrumConfig { + return try ElectrumConfig( + url: String.read(from: buf), + socks5: FfiConverterOptionString.read(from: buf), + retry: UInt8.read(from: buf), + timeout: FfiConverterOptionUInt8.read(from: buf), + stopGap: UInt64.read(from: buf) + ) + } + + func write(into buf: Writer) { + self.url.write(into: buf) + FfiConverterOptionString.write(self.socks5, into: buf) + self.retry.write(into: buf) + FfiConverterOptionUInt8.write(self.timeout, into: buf) + self.stopGap.write(into: buf) + } +} + +extension ElectrumConfig: ViaFfiUsingByteBuffer, ViaFfi {} + +public struct EsploraConfig { + public var baseUrl: String + public var proxy: String? + public var timeoutRead: UInt64 + public var timeoutWrite: UInt64 + public var stopGap: UInt64 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(baseUrl: String, proxy: String?, timeoutRead: UInt64, timeoutWrite: UInt64, stopGap: UInt64 ) { + self.baseUrl = baseUrl + self.proxy = proxy + self.timeoutRead = timeoutRead + self.timeoutWrite = timeoutWrite + self.stopGap = stopGap + } +} + + +extension EsploraConfig: Equatable, Hashable { + public static func ==(lhs: EsploraConfig, rhs: EsploraConfig) -> Bool { + if lhs.baseUrl != rhs.baseUrl { + return false + } + if lhs.proxy != rhs.proxy { + return false + } + if lhs.timeoutRead != rhs.timeoutRead { + return false + } + if lhs.timeoutWrite != rhs.timeoutWrite { + return false + } + if lhs.stopGap != rhs.stopGap { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(baseUrl) + hasher.combine(proxy) + hasher.combine(timeoutRead) + hasher.combine(timeoutWrite) + hasher.combine(stopGap) + } +} + + +fileprivate extension EsploraConfig { + static func read(from buf: Reader) throws -> EsploraConfig { + return try EsploraConfig( + baseUrl: String.read(from: buf), + proxy: FfiConverterOptionString.read(from: buf), + timeoutRead: UInt64.read(from: buf), + timeoutWrite: UInt64.read(from: buf), + stopGap: UInt64.read(from: buf) + ) + } + + func write(into buf: Writer) { + self.baseUrl.write(into: buf) + FfiConverterOptionString.write(self.proxy, into: buf) + self.timeoutRead.write(into: buf) + self.timeoutWrite.write(into: buf) + self.stopGap.write(into: buf) + } +} + +extension EsploraConfig: ViaFfiUsingByteBuffer, ViaFfi {} + +public struct ExtendedKeyInfo { + public var mnemonic: String + public var xprv: String + public var fingerprint: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(mnemonic: String, xprv: String, fingerprint: String ) { + self.mnemonic = mnemonic + self.xprv = xprv + self.fingerprint = fingerprint + } +} + + +extension ExtendedKeyInfo: Equatable, Hashable { + public static func ==(lhs: ExtendedKeyInfo, rhs: ExtendedKeyInfo) -> Bool { + if lhs.mnemonic != rhs.mnemonic { + return false + } + if lhs.xprv != rhs.xprv { + return false + } + if lhs.fingerprint != rhs.fingerprint { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(mnemonic) + hasher.combine(xprv) + hasher.combine(fingerprint) + } +} + + +fileprivate extension ExtendedKeyInfo { + static func read(from buf: Reader) throws -> ExtendedKeyInfo { + return try ExtendedKeyInfo( + mnemonic: String.read(from: buf), + xprv: String.read(from: buf), + fingerprint: String.read(from: buf) + ) + } + + func write(into buf: Writer) { + self.mnemonic.write(into: buf) + self.xprv.write(into: buf) + self.fingerprint.write(into: buf) + } +} + +extension ExtendedKeyInfo: ViaFfiUsingByteBuffer, ViaFfi {} + +public enum BdkError { + + + + // Simple error enums only carry a message + case InvalidU32Bytes(message: String) + + // Simple error enums only carry a message + case Generic(message: String) + + // Simple error enums only carry a message + case ScriptDoesntHaveAddressForm(message: String) + + // Simple error enums only carry a message + case NoRecipients(message: String) + + // Simple error enums only carry a message + case NoUtxosSelected(message: String) + + // Simple error enums only carry a message + case OutputBelowDustLimit(message: String) + + // Simple error enums only carry a message + case InsufficientFunds(message: String) + + // Simple error enums only carry a message + case BnBTotalTriesExceeded(message: String) + + // Simple error enums only carry a message + case BnBNoExactMatch(message: String) + + // Simple error enums only carry a message + case UnknownUtxo(message: String) + + // Simple error enums only carry a message + case TransactionNotFound(message: String) + + // Simple error enums only carry a message + case TransactionConfirmed(message: String) + + // Simple error enums only carry a message + case IrreplaceableTransaction(message: String) + + // Simple error enums only carry a message + case FeeRateTooLow(message: String) + + // Simple error enums only carry a message + case FeeTooLow(message: String) + + // Simple error enums only carry a message + case FeeRateUnavailable(message: String) + + // Simple error enums only carry a message + case MissingKeyOrigin(message: String) + + // Simple error enums only carry a message + case Key(message: String) + + // Simple error enums only carry a message + case ChecksumMismatch(message: String) + + // Simple error enums only carry a message + case SpendingPolicyRequired(message: String) + + // Simple error enums only carry a message + case InvalidPolicyPathError(message: String) + + // Simple error enums only carry a message + case Signer(message: String) + + // Simple error enums only carry a message + case InvalidNetwork(message: String) + + // Simple error enums only carry a message + case InvalidProgressValue(message: String) + + // Simple error enums only carry a message + case ProgressUpdateError(message: String) + + // Simple error enums only carry a message + case InvalidOutpoint(message: String) + + // Simple error enums only carry a message + case Descriptor(message: String) + + // Simple error enums only carry a message + case AddressValidator(message: String) + + // Simple error enums only carry a message + case Encode(message: String) + + // Simple error enums only carry a message + case Miniscript(message: String) + + // Simple error enums only carry a message + case Bip32(message: String) + + // Simple error enums only carry a message + case Secp256k1(message: String) + + // Simple error enums only carry a message + case Json(message: String) + + // Simple error enums only carry a message + case Hex(message: String) + + // Simple error enums only carry a message + case Psbt(message: String) + + // Simple error enums only carry a message + case PsbtParse(message: String) + + // Simple error enums only carry a message + case Electrum(message: String) + + // Simple error enums only carry a message + case Esplora(message: String) + + // Simple error enums only carry a message + case Sled(message: String) + +} + +extension BdkError: ViaFfiUsingByteBuffer, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> BdkError { + let variant: Int32 = try buf.readInt() + switch variant { + + + + + case 1: return .InvalidU32Bytes( + message: try String.read(from: buf) + ) + + case 2: return .Generic( + message: try String.read(from: buf) + ) + + case 3: return .ScriptDoesntHaveAddressForm( + message: try String.read(from: buf) + ) + + case 4: return .NoRecipients( + message: try String.read(from: buf) + ) + + case 5: return .NoUtxosSelected( + message: try String.read(from: buf) + ) + + case 6: return .OutputBelowDustLimit( + message: try String.read(from: buf) + ) + + case 7: return .InsufficientFunds( + message: try String.read(from: buf) + ) + + case 8: return .BnBTotalTriesExceeded( + message: try String.read(from: buf) + ) + + case 9: return .BnBNoExactMatch( + message: try String.read(from: buf) + ) + + case 10: return .UnknownUtxo( + message: try String.read(from: buf) + ) + + case 11: return .TransactionNotFound( + message: try String.read(from: buf) + ) + + case 12: return .TransactionConfirmed( + message: try String.read(from: buf) + ) + + case 13: return .IrreplaceableTransaction( + message: try String.read(from: buf) + ) + + case 14: return .FeeRateTooLow( + message: try String.read(from: buf) + ) + + case 15: return .FeeTooLow( + message: try String.read(from: buf) + ) + + case 16: return .FeeRateUnavailable( + message: try String.read(from: buf) + ) + + case 17: return .MissingKeyOrigin( + message: try String.read(from: buf) + ) + + case 18: return .Key( + message: try String.read(from: buf) + ) + + case 19: return .ChecksumMismatch( + message: try String.read(from: buf) + ) + + case 20: return .SpendingPolicyRequired( + message: try String.read(from: buf) + ) + + case 21: return .InvalidPolicyPathError( + message: try String.read(from: buf) + ) + + case 22: return .Signer( + message: try String.read(from: buf) + ) + + case 23: return .InvalidNetwork( + message: try String.read(from: buf) + ) + + case 24: return .InvalidProgressValue( + message: try String.read(from: buf) + ) + + case 25: return .ProgressUpdateError( + message: try String.read(from: buf) + ) + + case 26: return .InvalidOutpoint( + message: try String.read(from: buf) + ) + + case 27: return .Descriptor( + message: try String.read(from: buf) + ) + + case 28: return .AddressValidator( + message: try String.read(from: buf) + ) + + case 29: return .Encode( + message: try String.read(from: buf) + ) + + case 30: return .Miniscript( + message: try String.read(from: buf) + ) + + case 31: return .Bip32( + message: try String.read(from: buf) + ) + + case 32: return .Secp256k1( + message: try String.read(from: buf) + ) + + case 33: return .Json( + message: try String.read(from: buf) + ) + + case 34: return .Hex( + message: try String.read(from: buf) + ) + + case 35: return .Psbt( + message: try String.read(from: buf) + ) + + case 36: return .PsbtParse( + message: try String.read(from: buf) + ) + + case 37: return .Electrum( + message: try String.read(from: buf) + ) + + case 38: return .Esplora( + message: try String.read(from: buf) + ) + + case 39: return .Sled( + message: try String.read(from: buf) + ) + + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + fileprivate func write(into buf: Writer) { + switch self { + + + + + case let .InvalidU32Bytes(message): + buf.writeInt(Int32(1)) + message.write(into: buf) + case let .Generic(message): + buf.writeInt(Int32(2)) + message.write(into: buf) + case let .ScriptDoesntHaveAddressForm(message): + buf.writeInt(Int32(3)) + message.write(into: buf) + case let .NoRecipients(message): + buf.writeInt(Int32(4)) + message.write(into: buf) + case let .NoUtxosSelected(message): + buf.writeInt(Int32(5)) + message.write(into: buf) + case let .OutputBelowDustLimit(message): + buf.writeInt(Int32(6)) + message.write(into: buf) + case let .InsufficientFunds(message): + buf.writeInt(Int32(7)) + message.write(into: buf) + case let .BnBTotalTriesExceeded(message): + buf.writeInt(Int32(8)) + message.write(into: buf) + case let .BnBNoExactMatch(message): + buf.writeInt(Int32(9)) + message.write(into: buf) + case let .UnknownUtxo(message): + buf.writeInt(Int32(10)) + message.write(into: buf) + case let .TransactionNotFound(message): + buf.writeInt(Int32(11)) + message.write(into: buf) + case let .TransactionConfirmed(message): + buf.writeInt(Int32(12)) + message.write(into: buf) + case let .IrreplaceableTransaction(message): + buf.writeInt(Int32(13)) + message.write(into: buf) + case let .FeeRateTooLow(message): + buf.writeInt(Int32(14)) + message.write(into: buf) + case let .FeeTooLow(message): + buf.writeInt(Int32(15)) + message.write(into: buf) + case let .FeeRateUnavailable(message): + buf.writeInt(Int32(16)) + message.write(into: buf) + case let .MissingKeyOrigin(message): + buf.writeInt(Int32(17)) + message.write(into: buf) + case let .Key(message): + buf.writeInt(Int32(18)) + message.write(into: buf) + case let .ChecksumMismatch(message): + buf.writeInt(Int32(19)) + message.write(into: buf) + case let .SpendingPolicyRequired(message): + buf.writeInt(Int32(20)) + message.write(into: buf) + case let .InvalidPolicyPathError(message): + buf.writeInt(Int32(21)) + message.write(into: buf) + case let .Signer(message): + buf.writeInt(Int32(22)) + message.write(into: buf) + case let .InvalidNetwork(message): + buf.writeInt(Int32(23)) + message.write(into: buf) + case let .InvalidProgressValue(message): + buf.writeInt(Int32(24)) + message.write(into: buf) + case let .ProgressUpdateError(message): + buf.writeInt(Int32(25)) + message.write(into: buf) + case let .InvalidOutpoint(message): + buf.writeInt(Int32(26)) + message.write(into: buf) + case let .Descriptor(message): + buf.writeInt(Int32(27)) + message.write(into: buf) + case let .AddressValidator(message): + buf.writeInt(Int32(28)) + message.write(into: buf) + case let .Encode(message): + buf.writeInt(Int32(29)) + message.write(into: buf) + case let .Miniscript(message): + buf.writeInt(Int32(30)) + message.write(into: buf) + case let .Bip32(message): + buf.writeInt(Int32(31)) + message.write(into: buf) + case let .Secp256k1(message): + buf.writeInt(Int32(32)) + message.write(into: buf) + case let .Json(message): + buf.writeInt(Int32(33)) + message.write(into: buf) + case let .Hex(message): + buf.writeInt(Int32(34)) + message.write(into: buf) + case let .Psbt(message): + buf.writeInt(Int32(35)) + message.write(into: buf) + case let .PsbtParse(message): + buf.writeInt(Int32(36)) + message.write(into: buf) + case let .Electrum(message): + buf.writeInt(Int32(37)) + message.write(into: buf) + case let .Esplora(message): + buf.writeInt(Int32(38)) + message.write(into: buf) + case let .Sled(message): + buf.writeInt(Int32(39)) + message.write(into: buf) + } + } +} + + +extension BdkError: Equatable, Hashable {} + +extension BdkError: Error { } + + +// Declaration and FfiConverters for BdkProgress Callback Interface + +public protocol BdkProgress : AnyObject { + func update(progress: Float, message: String? ) + +} + +// The ForeignCallback that is passed to Rust. +fileprivate let foreignCallbackCallbackInterfaceBdkProgress : ForeignCallback = + { (handle: Handle, method: Int32, args: RustBuffer) -> RustBuffer in + func invokeUpdate(_ swiftCallbackInterface: BdkProgress, _ args: RustBuffer) throws -> RustBuffer { + defer { args.deallocate() } + + let reader = Reader(data: Data(rustBuffer: args)) + swiftCallbackInterface.update( + progress: try Float.read(from: reader), + message: try FfiConverterOptionString.read(from: reader) + ) + return RustBuffer() + // TODO catch errors and report them back to Rust. + // https://github.com/mozilla/uniffi-rs/issues/351 + + } + + + let cb = try! ffiConverterCallbackInterfaceBdkProgress.lift(handle) + switch method { + case IDX_CALLBACK_FREE: + ffiConverterCallbackInterfaceBdkProgress.drop(handle: handle) + return RustBuffer() + case 1: return try! invokeUpdate(cb, args) + + // This should never happen, because an out of bounds method index won't + // ever be used. Once we can catch errors, we should return an InternalError. + // https://github.com/mozilla/uniffi-rs/issues/351 + default: return RustBuffer() + } + } + +// The ffiConverter which transforms the Callbacks in to Handles to pass to Rust. +private let ffiConverterCallbackInterfaceBdkProgress: FfiConverterCallbackInterface = { + try! rustCall { (err: UnsafeMutablePointer) in + ffi_bdk_2e4d_BdkProgress_init_callback(foreignCallbackCallbackInterfaceBdkProgress, err) + } + return FfiConverterCallbackInterface() +}() +extension UInt8: Primitive, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> Self { + return try self.lift(buf.readInt()) + } + + fileprivate func write(into buf: Writer) { + buf.writeInt(self.lower()) + } +} +extension UInt32: Primitive, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> Self { + return try self.lift(buf.readInt()) + } + + fileprivate func write(into buf: Writer) { + buf.writeInt(self.lower()) + } +} +extension UInt64: Primitive, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> Self { + return try self.lift(buf.readInt()) + } + + fileprivate func write(into buf: Writer) { + buf.writeInt(self.lower()) + } +} +extension Float: Primitive, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> Self { + return try self.lift(buf.readFloat()) + } + + fileprivate func write(into buf: Writer) { + buf.writeFloat(self.lower()) + } +} +extension String: ViaFfi { + fileprivate typealias FfiType = RustBuffer + + fileprivate static func lift(_ v: FfiType) throws -> Self { + defer { + v.deallocate() + } + if v.data == nil { + return String() + } + let bytes = UnsafeBufferPointer(start: v.data!, count: Int(v.len)) + return String(bytes: bytes, encoding: String.Encoding.utf8)! + } + + fileprivate func lower() -> FfiType { + return self.utf8CString.withUnsafeBufferPointer { ptr in + // The swift string gives us int8_t, we want uint8_t. + ptr.withMemoryRebound(to: UInt8.self) { ptr in + // The swift string gives us a trailing null byte, we don't want it. + let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) + return RustBuffer.from(buf) + } + } + } + + fileprivate static func read(from buf: Reader) throws -> Self { + let len: Int32 = try buf.readInt() + return String(bytes: try buf.readBytes(count: Int(len)), encoding: String.Encoding.utf8)! + } + + fileprivate func write(into buf: Writer) { + let len = Int32(self.utf8.count) + buf.writeInt(len) + buf.writeBytes(self.utf8) + } +} +// Helper code for OfflineWallet class is found in ObjectTemplate.swift +// Helper code for OnlineWallet class is found in ObjectTemplate.swift +// Helper code for PartiallySignedBitcoinTransaction class is found in ObjectTemplate.swift +// Helper code for Confirmation record is found in RecordTemplate.swift +// Helper code for ElectrumConfig record is found in RecordTemplate.swift +// Helper code for EsploraConfig record is found in RecordTemplate.swift +// Helper code for ExtendedKeyInfo record is found in RecordTemplate.swift +// Helper code for SledDbConfiguration record is found in RecordTemplate.swift +// Helper code for TransactionDetails record is found in RecordTemplate.swift +// Helper code for BlockchainConfig enum is found in EnumTemplate.swift +// Helper code for DatabaseConfig enum is found in EnumTemplate.swift +// Helper code for MnemonicType enum is found in EnumTemplate.swift +// Helper code for Network enum is found in EnumTemplate.swift +// Helper code for Transaction enum is found in EnumTemplate.swift +// Helper code for BdkError error is found in ErrorTemplate.swift + +fileprivate enum FfiConverterOptionUInt8: FfiConverterUsingByteBuffer { + typealias SwiftType = UInt8? + + static func write(_ value: SwiftType, into buf: Writer) { + FfiConverterOptional.write(value, into: buf) { item, buf in + item.write(into: buf) + } + } + + static func read(from buf: Reader) throws -> SwiftType { + try FfiConverterOptional.read(from: buf) { buf in + try UInt8.read(from: buf) + } + } +} + +fileprivate enum FfiConverterOptionUInt32: FfiConverterUsingByteBuffer { + typealias SwiftType = UInt32? + + static func write(_ value: SwiftType, into buf: Writer) { + FfiConverterOptional.write(value, into: buf) { item, buf in + item.write(into: buf) + } + } + + static func read(from buf: Reader) throws -> SwiftType { + try FfiConverterOptional.read(from: buf) { buf in + try UInt32.read(from: buf) + } + } +} + +fileprivate enum FfiConverterOptionUInt64: FfiConverterUsingByteBuffer { + typealias SwiftType = UInt64? + + static func write(_ value: SwiftType, into buf: Writer) { + FfiConverterOptional.write(value, into: buf) { item, buf in + item.write(into: buf) + } + } + + static func read(from buf: Reader) throws -> SwiftType { + try FfiConverterOptional.read(from: buf) { buf in + try UInt64.read(from: buf) + } + } +} + +fileprivate enum FfiConverterOptionFloat: FfiConverterUsingByteBuffer { + typealias SwiftType = Float? + + static func write(_ value: SwiftType, into buf: Writer) { + FfiConverterOptional.write(value, into: buf) { item, buf in + item.write(into: buf) + } + } + + static func read(from buf: Reader) throws -> SwiftType { + try FfiConverterOptional.read(from: buf) { buf in + try Float.read(from: buf) + } + } +} + +fileprivate enum FfiConverterOptionString: FfiConverterUsingByteBuffer { + typealias SwiftType = String? + + static func write(_ value: SwiftType, into buf: Writer) { + FfiConverterOptional.write(value, into: buf) { item, buf in + item.write(into: buf) + } + } + + static func read(from buf: Reader) throws -> SwiftType { + try FfiConverterOptional.read(from: buf) { buf in + try String.read(from: buf) + } + } +} + +fileprivate enum FfiConverterSequenceEnumTransaction: FfiConverterUsingByteBuffer { + typealias SwiftType = [Transaction] + + static func write(_ value: SwiftType, into buf: Writer) { + FfiConverterSequence.write(value, into: buf) { (item, buf) in + item.write(into: buf) + } + } + + static func read(from buf: Reader) throws -> SwiftType { + try FfiConverterSequence.read(from: buf) { buf in + try Transaction.read(from: buf) + } + } +} + + +/** + * Top level initializers and tear down methods. + * + * This is generated by uniffi. + */ +public enum BdkLifecycle { + /** + * Initialize the FFI and Rust library. This should be only called once per application. + */ + func initialize() { + + // No initialization code needed + + } +} \ No newline at end of file From aa84f5583e8af7f28510fa9122540afd11c8e20a Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Wed, 24 Nov 2021 00:17:34 -0800 Subject: [PATCH 07/33] Bump version to 0.1.2 --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index b149720..c85039e 100644 --- a/Package.swift +++ b/Package.swift @@ -24,7 +24,7 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages this package depends on. .binaryTarget( name: "bdkFFI", - url: "https://github.com/notmandatory/bdk-swift/releases/download/0.1.1/bdkFFI.xcframework.zip", + url: "https://github.com/notmandatory/bdk-swift/releases/download/0.1.2/bdkFFI.xcframework.zip", checksum: "a88d3c8a2267e9e8a953fe332a91bd3356f8317e3758499192001993969a9dad"), // .binaryTarget(name: "bdkFFI", path: "./bdkFFI.xcframework"), .target( From ee56748348173fe68575784125604be4f8467cf5 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Wed, 24 Nov 2021 12:31:59 -0800 Subject: [PATCH 08/33] Update to lastest bdk-ffi master branch --- bdk-ffi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bdk-ffi b/bdk-ffi index 4e087ef..6fe9bdd 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit 4e087ef21c69986090ad8157bba112842156b8b9 +Subproject commit 6fe9bddcfab97d061668da35cde2d12197014c7a From 05a6a21e9eb33212d32ba147a1e523eddf7171eb Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Wed, 24 Nov 2021 14:27:07 -0800 Subject: [PATCH 09/33] Update README with usage and publishing instructions --- README.md | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c49608d..0822ba9 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,76 @@ # bdk-swift -A description of this package. +This project builds a swift package that provides swift language bindings to the [`bdk`] +library. The swift language bindings are created by the [`bdk-ffi`] project which is +included as a git submodule of this repository. + +## How to Use + +To use the swift language bindings provided by the [`bdk-ffi`] project in your xcode iOS +or MacOS project add this github repository and select one of the published versions. You +may then import the `BitcoinDevKit` library. For example: + +```swift +import BitcoinDevKit + +... + +let desc = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)" +let config = DatabaseConfig.memory(junk: "") +let wallet = try OfflineWallet.init(descriptor: desc, network: Network.regtest, databaseConfig: config) +let address = wallet.getNewAddress() +``` + +## How to Build and Publish + +If you are a maintainer of this project or want to build and publish this project to your +own repo use the following steps: + +1. Clone this repo and init and update it's [`bdk-ffi`] submodule + ```shell + git clone https://github.com/bitcoindevkit/bdk-swift + git submodule update --init + ``` + +1. Follow the "General" `bdk-ffi` ["Getting Started (Developer)"] instructions. + +1. Install the latest version of xcode, download and install the advanced tools. + +1. Ensure Swift is installed + +1. Install required targets + ```shell + rustup target add aarch64-apple-ios x86_64-apple-ios + ``` + +1. Build [`bdk-ffi`] swift bindings and bdkFFI.xcframework.zip + ```shell + ./build.sh + ``` + +1. Update the `Package.swift` file with the new expected URL for the + `bdkFFI.xcframework.zip` file and new hash as shown at the end of the build.sh script. + For example: + ```swift + .binaryTarget( + name: "bdkFFI", + url: "https://github.com/bitcoindevkit/bdk-swift/releases/download/0.1.3/bdkFFI.xcframework.zip", + checksum: "c0b1e3ea09376b3f316d7d83575e1cd513fc4ad39ef8cf01120a3a1d7757fb97"), + ``` +1. Commit the changed `Package.swift` and tag it with the new version number. + ```shell + git add Package.swift + git commit -m "Bump version to 0.1.3" + git tag 0.1.3 -m "Release 0.1.3" + git push --tags + ``` + +1. Create a github release for your new tag. + +1. Upload the newly created zip to the new github release. + +1. Tests the new package in xcode. + +[`bdk`]: https://github.com/bitcoindevkit/bdk +[`bdk-ffi`]: https://github.com/bitcoindevkit/bdk-ffi +["Getting Started (Developer)"]: https://github.com/bitcoindevkit/bdk-ffi#getting-started-developer From dcefae806d46028b3f478e4acbf1ff2c6da9b09e Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Wed, 24 Nov 2021 14:27:33 -0800 Subject: [PATCH 10/33] Bump version to 0.1.3 --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index c85039e..1306bab 100644 --- a/Package.swift +++ b/Package.swift @@ -24,8 +24,8 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages this package depends on. .binaryTarget( name: "bdkFFI", - url: "https://github.com/notmandatory/bdk-swift/releases/download/0.1.2/bdkFFI.xcframework.zip", - checksum: "a88d3c8a2267e9e8a953fe332a91bd3356f8317e3758499192001993969a9dad"), + url: "https://github.com/notmandatory/bdk-swift/releases/download/0.1.3/bdkFFI.xcframework.zip", + checksum: "c0b1e3ea09376b3f316d7d83575e1cd513fc4ad39ef8cf01120a3a1d7757fb97"), // .binaryTarget(name: "bdkFFI", path: "./bdkFFI.xcframework"), .target( name: "BitcoinDevKit", From 250df250ff00c18d06840a9ee6e5b1f909fa84cd Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Wed, 24 Nov 2021 14:57:41 -0800 Subject: [PATCH 11/33] Update README --- README.md | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 0822ba9..c15f1aa 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,15 @@ # bdk-swift -This project builds a swift package that provides swift language bindings to the [`bdk`] -library. The swift language bindings are created by the [`bdk-ffi`] project which is -included as a git submodule of this repository. +This project builds a Swift package that provides [Swift] language bindings for the +[`bdk`] library. The Swift language bindings are created by the [`bdk-ffi`] project which +is included as a git submodule of this repository. ## How to Use -To use the swift language bindings provided by the [`bdk-ffi`] project in your xcode iOS -or MacOS project add this github repository and select one of the published versions. You -may then import the `BitcoinDevKit` library. For example: +To use the Swift language bindings for [`bdk`] in your [Xcode] iOS or MacOS project add +the github repository (https://github.com/bitcoindevkit/bdk-swift) and select one of the +release versions. You may then import and use the `BitcoinDevKit` library in your Swift +code. For example: ```swift import BitcoinDevKit @@ -24,9 +25,9 @@ let address = wallet.getNewAddress() ## How to Build and Publish If you are a maintainer of this project or want to build and publish this project to your -own repo use the following steps: +own Github repository use the following steps: -1. Clone this repo and init and update it's [`bdk-ffi`] submodule +1. Clone this repository and init and update it's [`bdk-ffi`] submodule. ```shell git clone https://github.com/bitcoindevkit/bdk-swift git submodule update --init @@ -34,16 +35,16 @@ own repo use the following steps: 1. Follow the "General" `bdk-ffi` ["Getting Started (Developer)"] instructions. -1. Install the latest version of xcode, download and install the advanced tools. +1. Install the latest version of [Xcode], download and install the advanced tools. -1. Ensure Swift is installed +1. Ensure Swift is installed. -1. Install required targets +1. Install required targets. ```shell rustup target add aarch64-apple-ios x86_64-apple-ios ``` -1. Build [`bdk-ffi`] swift bindings and bdkFFI.xcframework.zip +1. Build [`bdk-ffi`] Swift bindings and `bdkFFI.xcframework.zip`. ```shell ./build.sh ``` @@ -67,10 +68,13 @@ own repo use the following steps: 1. Create a github release for your new tag. -1. Upload the newly created zip to the new github release. +1. Upload the newly created zip to the new github release and publish the release. -1. Tests the new package in xcode. +1. Test the new package in Xcode. If you get an error you might need to reset the Xcode + package caches: File -> Packages -> Reset Package Caches. +[Swift]: https://developer.apple.com/swift/ +[Xcode]: https://developer.apple.com/documentation/Xcode [`bdk`]: https://github.com/bitcoindevkit/bdk [`bdk-ffi`]: https://github.com/bitcoindevkit/bdk-ffi ["Getting Started (Developer)"]: https://github.com/bitcoindevkit/bdk-ffi#getting-started-developer From a33e856b48379008b5c0b6cfa624f790474d2859 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Thu, 2 Dec 2021 22:09:01 -0800 Subject: [PATCH 12/33] Add M1 target support to build.sh --- .gitignore | 1 + Package.swift | 4 +- bdkFFI.xcframework/Info.plist | 29 ++++----- .../Headers/bdkFFI-umbrella.h | 0 .../bdkFFI.framework/Modules/module.modulemap | 0 build.sh | 61 ++++++++++++------- 6 files changed, 57 insertions(+), 38 deletions(-) rename bdkFFI.xcframework/{macos-x86_64 => macos-arm64_x86_64}/bdkFFI.framework/Headers/bdkFFI-umbrella.h (100%) rename bdkFFI.xcframework/{macos-x86_64 => macos-arm64_x86_64}/bdkFFI.framework/Modules/module.modulemap (100%) diff --git a/.gitignore b/.gitignore index 7a7671d..cf97457 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ DerivedData/ .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata bdkFFI.xcframework.zip bdkFFI +libbdkffi.a bdkFFI.h diff --git a/Package.swift b/Package.swift index 1306bab..52cba67 100644 --- a/Package.swift +++ b/Package.swift @@ -24,8 +24,8 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages this package depends on. .binaryTarget( name: "bdkFFI", - url: "https://github.com/notmandatory/bdk-swift/releases/download/0.1.3/bdkFFI.xcframework.zip", - checksum: "c0b1e3ea09376b3f316d7d83575e1cd513fc4ad39ef8cf01120a3a1d7757fb97"), + url: "https://github.com/notmandatory/bdk-swift/releases/download/0.1.7/bdkFFI.xcframework.zip", + checksum: "dc51c5c61b78e06fba45fe7d55978726f6f6bb609c2b369f12f3f2e5c24b9ed5"), // .binaryTarget(name: "bdkFFI", path: "./bdkFFI.xcframework"), .target( name: "BitcoinDevKit", diff --git a/bdkFFI.xcframework/Info.plist b/bdkFFI.xcframework/Info.plist index 3b0157a..cda8ded 100644 --- a/bdkFFI.xcframework/Info.plist +++ b/bdkFFI.xcframework/Info.plist @@ -6,27 +6,16 @@ LibraryIdentifier - macos-x86_64 - LibraryPath - bdkFFI.framework - SupportedArchitectures - - x86_64 - - SupportedPlatform - macos - - - LibraryIdentifier - ios-arm64 + macos-arm64_x86_64 LibraryPath bdkFFI.framework SupportedArchitectures arm64 + x86_64 SupportedPlatform - ios + macos LibraryIdentifier @@ -43,6 +32,18 @@ SupportedPlatformVariant simulator + + LibraryIdentifier + ios-arm64 + LibraryPath + bdkFFI.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + CFBundlePackageType XFWK diff --git a/bdkFFI.xcframework/macos-x86_64/bdkFFI.framework/Headers/bdkFFI-umbrella.h b/bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Headers/bdkFFI-umbrella.h similarity index 100% rename from bdkFFI.xcframework/macos-x86_64/bdkFFI.framework/Headers/bdkFFI-umbrella.h rename to bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Headers/bdkFFI-umbrella.h diff --git a/bdkFFI.xcframework/macos-x86_64/bdkFFI.framework/Modules/module.modulemap b/bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Modules/module.modulemap similarity index 100% rename from bdkFFI.xcframework/macos-x86_64/bdkFFI.framework/Modules/module.modulemap rename to bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Modules/module.modulemap diff --git a/build.sh b/build.sh index c278b29..d238346 100755 --- a/build.sh +++ b/build.sh @@ -6,47 +6,64 @@ pushd bdk-ffi echo "Confirm bdk-ffi rust lib builds" cargo build --release -## build bdk-ffi rust libs for apple targets -echo "Build bdk-ffi libs for apple targets" +echo "Generate bdk-ffi swift bindings" +uniffi-bindgen generate src/bdk.udl --no-format --out-dir ../Sources/BitcoinDevKit --language swift -TARGET_TRIPLES=("x86_64-apple-darwin" "x86_64-apple-ios" "aarch64-apple-ios") +## build bdk-ffi rust libs for apple targets and add to xcframework +echo "Build bdk-ffi libs for apple targets and add to xcframework" + +TARGET_TRIPLES=("x86_64-apple-darwin" "aarch64-apple-darwin" "x86_64-apple-ios" "aarch64-apple-ios") +#XCFRAMEWORK_LIBS="" for TARGET in ${TARGET_TRIPLES[@]}; do echo "Build bdk-ffi lib for target $TARGET" cargo build --release --target $TARGET + #XCFRAMEWORK_LIBS="$XCFRAMEWORK_LIBS -library target/$TARGET/release/libbdkffi.a" done +# special build for M1 ios simulator +cargo +nightly build --release -Z build-std --target aarch64-apple-ios-sim -echo "Generate bdk-ffi swift bindings" -uniffi-bindgen generate src/bdk.udl --no-format --out-dir ../Sources/BitcoinDevKit --language swift +echo "Create lipo static libs for ios-sim to support M1" +mkdir -p target/lipo-ios-sim/release +lipo target/aarch64-apple-ios-sim/release/libbdkffi.a target/x86_64-apple-ios/release/libbdkffi.a -create -output target/lipo-ios-sim/release/libbdkffi.a + +echo "Create lipo static libs for macos to support M1" +mkdir -p target/lipo-macos/release +lipo target/aarch64-apple-darwin/release/libbdkffi.a target/x86_64-apple-darwin/release/libbdkffi.a -create -output target/lipo-macos/release/libbdkffi.a + +#echo "Create xcframework with xcodebuild" +#xcodebuild -create-xcframework \ +# -library target/lipo-ios-sim/release/libbdkffi.a \ +# -library target/lipo-macos/release/libbdkffi.a \ +# -library target/aarch64-apple-ios/release/libbdkffi.a \ +# -output ../bdkFFI.xcframework + popd # rename bdk.swift bindings to BitcoinDevKit.swift mv Sources/BitcoinDevKit/bdk.swift Sources/BitcoinDevKit/BitcoinDevKit.swift -# copy bdkFFI.h to bdkFFI.xcframework platforms -PLATFORMS=("macos-x86_64" "ios-arm64_x86_64-simulator" "ios-arm64") -for PLATFORM in ${PLATFORMS[@]}; do - cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/$PLATFORM/bdkFFI.framework/Headers +XCFRAMEWORK_LIBS=("ios-arm64" "ios-arm64_x86_64-simulator" "macos-arm64_x86_64") +for LIB in ${XCFRAMEWORK_LIBS[@]}; do + # copy possibly updated header file + cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/$LIB/bdkFFI.framework/Headers done +echo "Copy libbdkffi.a files to bdkFFI.xcframework/bdkFFI" +cp bdk-ffi/target/aarch64-apple-ios/release/libbdkffi.a bdkFFI.xcframework/ios-arm64/bdkFFI.framework/bdkFFI +cp bdk-ffi/target/lipo-ios-sim/release/libbdkffi.a bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/bdkFFI +cp bdk-ffi/target/lipo-macos/release/libbdkffi.a bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/bdkFFI + # remove unneed .h and .modulemap files rm Sources/BitcoinDevKit/bdkFFI.h rm Sources/BitcoinDevkit/bdkFFI.modulemap -# add bdkFFI libs to bdkFFI.xcframework - -# macos-x86_64 platform -cp bdk-ffi/target/x86_64-apple-darwin/release/libbdkffi.a bdkFFI.xcframework/macos-x86_64/bdkFFI.framework/bdkFFI - -# ios-arm64 platform -cp bdk-ffi/target/aarch64-apple-ios/release/libbdkffi.a bdkFFI.xcframework/ios-arm64/bdkFFI.framework/bdkFFI - -# ios-arm64_x86_64-simulator, currently x86_64 only (need to make fat binary to add M1) -cp bdk-ffi/target/x86_64-apple-ios/release/libbdkffi.a bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/bdkFFI - # TODO add license info -# remove any existing bdkFFI.xcframework.zip -rm bdkFFI.xcframework.zip +if test -f "bdkFFI.xcframework.zip"; then + echo "Remove old bdkFFI.xcframework.zip" + rm bdkFFI.xcframework.zip +fi + # zip bdkFFI.xcframework directory into a bundle for distribution zip -9 -r bdkFFI.xcframework.zip bdkFFI.xcframework From e450668b9dcb33198fa678f8dfe9ddef406ceb3b Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Fri, 3 Dec 2021 11:35:44 -0800 Subject: [PATCH 13/33] Update .gitmodule to https url --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 9c7f2ac..96bdc69 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "bdk-ffi"] path = bdk-ffi - url = git@github.com:bitcoindevkit/bdk-ffi.git + url = https://github.com/bitcoindevkit/bdk-ffi.git From f2b857a609001b29f6663c9a2646a0d814d0e7e9 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Fri, 3 Dec 2021 12:35:58 -0800 Subject: [PATCH 14/33] Change bdkFFI xcframework download url to bitcoindevkit repo release --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 52cba67..ef01ea6 100644 --- a/Package.swift +++ b/Package.swift @@ -24,7 +24,7 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages this package depends on. .binaryTarget( name: "bdkFFI", - url: "https://github.com/notmandatory/bdk-swift/releases/download/0.1.7/bdkFFI.xcframework.zip", + url: "https://github.com/bitcoindevkit/bdk-swift/releases/download/0.1.4/bdkFFI.xcframework.zip", checksum: "dc51c5c61b78e06fba45fe7d55978726f6f6bb609c2b369f12f3f2e5c24b9ed5"), // .binaryTarget(name: "bdkFFI", path: "./bdkFFI.xcframework"), .target( From 2cd5fa6934a76f624a2242b04bb6c3587fef6493 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Wed, 2 Mar 2022 15:17:53 -0800 Subject: [PATCH 15/33] Update bdk-ffi to 0.3.1 --- Sources/BitcoinDevKit/BitcoinDevKit.swift | 274 ++++++++-------------- bdk-ffi | 2 +- 2 files changed, 93 insertions(+), 183 deletions(-) diff --git a/Sources/BitcoinDevKit/BitcoinDevKit.swift b/Sources/BitcoinDevKit/BitcoinDevKit.swift index 1c9432e..dcb7a69 100644 --- a/Sources/BitcoinDevKit/BitcoinDevKit.swift +++ b/Sources/BitcoinDevKit/BitcoinDevKit.swift @@ -19,13 +19,13 @@ fileprivate extension RustBuffer { } static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { - try! rustCall { ffi_bdk_2e4d_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } + try! rustCall { ffi_bdk_d04b_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } } // Frees the buffer in place. // The buffer must not be used after this is called. func deallocate() { - try! rustCall { ffi_bdk_2e4d_rustbuffer_free(self, $0) } + try! rustCall { ffi_bdk_d04b_rustbuffer_free(self, $0) } } } @@ -576,7 +576,7 @@ extension DatabaseConfig: Equatable, Hashable {} public enum Transaction { case unconfirmed(details: TransactionDetails ) - case confirmed(details: TransactionDetails, confirmation: Confirmation ) + case confirmed(details: TransactionDetails, confirmation: BlockTime ) } extension Transaction: ViaFfiUsingByteBuffer, ViaFfi { @@ -589,7 +589,7 @@ extension Transaction: ViaFfiUsingByteBuffer, ViaFfi { ) case 2: return .confirmed( details: try TransactionDetails.read(from: buf), - confirmation: try Confirmation.read(from: buf) + confirmation: try BlockTime.read(from: buf) ) default: throw UniffiInternalError.unexpectedEnumCase } @@ -669,7 +669,7 @@ extension BlockchainConfig: Equatable, Hashable {} // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. -public enum MnemonicType { +public enum WordCount { case words12 case words15 @@ -678,8 +678,8 @@ public enum MnemonicType { case words24 } -extension MnemonicType: ViaFfiUsingByteBuffer, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> MnemonicType { +extension WordCount: ViaFfiUsingByteBuffer, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> WordCount { let variant: Int32 = try buf.readInt() switch variant { @@ -720,168 +720,49 @@ extension MnemonicType: ViaFfiUsingByteBuffer, ViaFfi { } -extension MnemonicType: Equatable, Hashable {} +extension WordCount: Equatable, Hashable {} -public func generateExtendedKey(network: Network, mnemonicType: MnemonicType, password: String? ) throws -> ExtendedKeyInfo { +public func generateExtendedKey( network: Network, wordCount: WordCount, password: String? ) throws -> ExtendedKeyInfo { let _retval = try rustCallWithError(BdkError.self) { - bdk_2e4d_generate_extended_key(network.lower(), mnemonicType.lower(), FfiConverterOptionString.lower(password) , $0) + bdk_d04b_generate_extended_key(network.lower(), wordCount.lower(), FfiConverterOptionString.lower(password) , $0) } return try ExtendedKeyInfo.lift(_retval) } -public func restoreExtendedKey(network: Network, mnemonic: String, password: String? ) throws -> ExtendedKeyInfo { +public func restoreExtendedKey( network: Network, mnemonic: String, password: String? ) throws -> ExtendedKeyInfo { let _retval = try rustCallWithError(BdkError.self) { - bdk_2e4d_restore_extended_key(network.lower(), mnemonic.lower(), FfiConverterOptionString.lower(password) , $0) + bdk_d04b_restore_extended_key(network.lower(), mnemonic.lower(), FfiConverterOptionString.lower(password) , $0) } return try ExtendedKeyInfo.lift(_retval) } -public protocol OfflineWalletProtocol { +public protocol WalletProtocol { func getNewAddress() -> String func getLastUnusedAddress() -> String func getBalance() throws -> UInt64 - func sign(psbt: PartiallySignedBitcoinTransaction ) throws - func getTransactions() throws -> [Transaction] - -} - -public class OfflineWallet: OfflineWalletProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `ViaFfi` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init(descriptor: String, network: Network, databaseConfig: DatabaseConfig ) throws { - self.init(unsafeFromRawPointer: try - - - rustCallWithError(BdkError.self) { - - bdk_2e4d_OfflineWallet_new(descriptor.lower(), network.lower(), databaseConfig.lower() , $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_2e4d_OfflineWallet_object_free(pointer, $0) } - } - - - - - public func getNewAddress() -> String { - let _retval = try! - rustCall() { - - bdk_2e4d_OfflineWallet_get_new_address(self.pointer, $0 - ) -} - return try! String.lift(_retval) - } - public func getLastUnusedAddress() -> String { - let _retval = try! - rustCall() { - - bdk_2e4d_OfflineWallet_get_last_unused_address(self.pointer, $0 - ) -} - return try! String.lift(_retval) - } - public func getBalance() throws -> UInt64 { - let _retval = try - rustCallWithError(BdkError.self) { - - bdk_2e4d_OfflineWallet_get_balance(self.pointer, $0 - ) -} - return try UInt64.lift(_retval) - } - public func sign(psbt: PartiallySignedBitcoinTransaction ) throws { - try - rustCallWithError(BdkError.self) { - - bdk_2e4d_OfflineWallet_sign(self.pointer, psbt.lower() , $0 - ) -} - } - public func getTransactions() throws -> [Transaction] { - let _retval = try - rustCallWithError(BdkError.self) { - - bdk_2e4d_OfflineWallet_get_transactions(self.pointer, $0 - ) -} - return try FfiConverterSequenceEnumTransaction.lift(_retval) - } - -} - - -fileprivate extension OfflineWallet { - fileprivate typealias FfiType = UnsafeMutableRawPointer - - fileprivate static func read(from buf: Reader) throws -> Self { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try self.lift(ptr!) - } - - fileprivate func write(into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) - } - - fileprivate static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { - return Self(unsafeFromRawPointer: pointer) - } - - fileprivate func lower() -> UnsafeMutableRawPointer { - return self.pointer - } -} - -// Ideally this would be `fileprivate`, but Swift says: -// """ -// 'private' modifier cannot be used with extensions that declare protocol conformances -// """ -extension OfflineWallet : ViaFfi, Serializable {} - - -public protocol OnlineWalletProtocol { - func getNewAddress() -> String - func getLastUnusedAddress() -> String - func getBalance() throws -> UInt64 - func sign(psbt: PartiallySignedBitcoinTransaction ) throws + func sign( psbt: PartiallySignedBitcoinTransaction ) throws func getTransactions() throws -> [Transaction] func getNetwork() -> Network - func sync(progressUpdate: BdkProgress, maxAddressParam: UInt32? ) throws - func broadcast(psbt: PartiallySignedBitcoinTransaction ) throws -> Transaction + func sync( progressUpdate: BdkProgress, maxAddressParam: UInt32? ) throws + func broadcast( psbt: PartiallySignedBitcoinTransaction ) throws -> Transaction } -public class OnlineWallet: OnlineWalletProtocol { +public class Wallet: WalletProtocol { fileprivate let pointer: UnsafeMutableRawPointer // TODO: We'd like this to be `private` but for Swifty reasons, @@ -890,18 +771,18 @@ public class OnlineWallet: OnlineWalletProtocol { required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { self.pointer = pointer } - public convenience init(descriptor: String, changeDescriptor: String?, network: Network, databaseConfig: DatabaseConfig, blockchainConfig: BlockchainConfig ) throws { + public convenience init( descriptor: String, changeDescriptor: String?, network: Network, databaseConfig: DatabaseConfig, blockchainConfig: BlockchainConfig ) throws { self.init(unsafeFromRawPointer: try rustCallWithError(BdkError.self) { - bdk_2e4d_OnlineWallet_new(descriptor.lower(), FfiConverterOptionString.lower(changeDescriptor), network.lower(), databaseConfig.lower(), blockchainConfig.lower() , $0) + bdk_d04b_Wallet_new(descriptor.lower(), FfiConverterOptionString.lower(changeDescriptor), network.lower(), databaseConfig.lower(), blockchainConfig.lower() , $0) }) } deinit { - try! rustCall { ffi_bdk_2e4d_OnlineWallet_object_free(pointer, $0) } + try! rustCall { ffi_bdk_d04b_Wallet_object_free(pointer, $0) } } @@ -911,7 +792,7 @@ public class OnlineWallet: OnlineWalletProtocol { let _retval = try! rustCall() { - bdk_2e4d_OnlineWallet_get_new_address(self.pointer, $0 + bdk_d04b_Wallet_get_new_address(self.pointer, $0 ) } return try! String.lift(_retval) @@ -920,7 +801,7 @@ public class OnlineWallet: OnlineWalletProtocol { let _retval = try! rustCall() { - bdk_2e4d_OnlineWallet_get_last_unused_address(self.pointer, $0 + bdk_d04b_Wallet_get_last_unused_address(self.pointer, $0 ) } return try! String.lift(_retval) @@ -929,16 +810,16 @@ public class OnlineWallet: OnlineWalletProtocol { let _retval = try rustCallWithError(BdkError.self) { - bdk_2e4d_OnlineWallet_get_balance(self.pointer, $0 + bdk_d04b_Wallet_get_balance(self.pointer, $0 ) } return try UInt64.lift(_retval) } - public func sign(psbt: PartiallySignedBitcoinTransaction ) throws { + public func sign( psbt: PartiallySignedBitcoinTransaction ) throws { try rustCallWithError(BdkError.self) { - bdk_2e4d_OnlineWallet_sign(self.pointer, psbt.lower() , $0 + bdk_d04b_Wallet_sign(self.pointer, psbt.lower() , $0 ) } } @@ -946,7 +827,7 @@ public class OnlineWallet: OnlineWalletProtocol { let _retval = try rustCallWithError(BdkError.self) { - bdk_2e4d_OnlineWallet_get_transactions(self.pointer, $0 + bdk_d04b_Wallet_get_transactions(self.pointer, $0 ) } return try FfiConverterSequenceEnumTransaction.lift(_retval) @@ -955,24 +836,24 @@ public class OnlineWallet: OnlineWalletProtocol { let _retval = try! rustCall() { - bdk_2e4d_OnlineWallet_get_network(self.pointer, $0 + bdk_d04b_Wallet_get_network(self.pointer, $0 ) } return try! Network.lift(_retval) } - public func sync(progressUpdate: BdkProgress, maxAddressParam: UInt32? ) throws { + public func sync( progressUpdate: BdkProgress, maxAddressParam: UInt32? ) throws { try rustCallWithError(BdkError.self) { - bdk_2e4d_OnlineWallet_sync(self.pointer, ffiConverterCallbackInterfaceBdkProgress.lower(progressUpdate), FfiConverterOptionUInt32.lower(maxAddressParam) , $0 + bdk_d04b_Wallet_sync(self.pointer, ffiConverterCallbackInterfaceBdkProgress.lower(progressUpdate), FfiConverterOptionUInt32.lower(maxAddressParam) , $0 ) } } - public func broadcast(psbt: PartiallySignedBitcoinTransaction ) throws -> Transaction { + public func broadcast( psbt: PartiallySignedBitcoinTransaction ) throws -> Transaction { let _retval = try rustCallWithError(BdkError.self) { - bdk_2e4d_OnlineWallet_broadcast(self.pointer, psbt.lower() , $0 + bdk_d04b_Wallet_broadcast(self.pointer, psbt.lower() , $0 ) } return try Transaction.lift(_retval) @@ -981,10 +862,10 @@ public class OnlineWallet: OnlineWalletProtocol { } -fileprivate extension OnlineWallet { - fileprivate typealias FfiType = UnsafeMutableRawPointer +fileprivate extension Wallet { + typealias FfiType = UnsafeMutableRawPointer - fileprivate static func read(from buf: Reader) throws -> Self { + static func read(from buf: Reader) throws -> Self { let v: UInt64 = try buf.readInt() // The Rust code won't compile if a pointer won't fit in a UInt64. // We have to go via `UInt` because that's the thing that's the size of a pointer. @@ -995,17 +876,17 @@ fileprivate extension OnlineWallet { return try self.lift(ptr!) } - fileprivate func write(into buf: Writer) { + func write(into buf: Writer) { // This fiddling is because `Int` is the thing that's the same size as a pointer. // The Rust code won't compile if a pointer won't fit in a `UInt64`. buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) } - fileprivate static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { + static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { return Self(unsafeFromRawPointer: pointer) } - fileprivate func lower() -> UnsafeMutableRawPointer { + func lower() -> UnsafeMutableRawPointer { return self.pointer } } @@ -1014,10 +895,11 @@ fileprivate extension OnlineWallet { // """ // 'private' modifier cannot be used with extensions that declare protocol conformances // """ -extension OnlineWallet : ViaFfi, Serializable {} +extension Wallet : ViaFfi, Serializable {} public protocol PartiallySignedBitcoinTransactionProtocol { + func serialize() -> String } @@ -1030,31 +912,50 @@ public class PartiallySignedBitcoinTransaction: PartiallySignedBitcoinTransactio required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { self.pointer = pointer } - public convenience init(wallet: OnlineWallet, recipient: String, amount: UInt64, feeRate: Float? ) throws { + public convenience init( wallet: Wallet, recipient: String, amount: UInt64, feeRate: Float? ) throws { self.init(unsafeFromRawPointer: try rustCallWithError(BdkError.self) { - bdk_2e4d_PartiallySignedBitcoinTransaction_new(wallet.lower(), recipient.lower(), amount.lower(), FfiConverterOptionFloat.lower(feeRate) , $0) + bdk_d04b_PartiallySignedBitcoinTransaction_new(wallet.lower(), recipient.lower(), amount.lower(), FfiConverterOptionFloat.lower(feeRate) , $0) }) } deinit { - try! rustCall { ffi_bdk_2e4d_PartiallySignedBitcoinTransaction_object_free(pointer, $0) } + try! rustCall { ffi_bdk_d04b_PartiallySignedBitcoinTransaction_object_free(pointer, $0) } } + public static func deserialize( psbtBase64: String ) throws -> PartiallySignedBitcoinTransaction { + return PartiallySignedBitcoinTransaction(unsafeFromRawPointer: try + + + rustCallWithError(BdkError.self) { + + bdk_d04b_PartiallySignedBitcoinTransaction_deserialize(psbtBase64.lower() , $0) +}) + } + + public func serialize() -> String { + let _retval = try! + rustCall() { + + bdk_d04b_PartiallySignedBitcoinTransaction_serialize(self.pointer, $0 + ) +} + return try! String.lift(_retval) + } } fileprivate extension PartiallySignedBitcoinTransaction { - fileprivate typealias FfiType = UnsafeMutableRawPointer + typealias FfiType = UnsafeMutableRawPointer - fileprivate static func read(from buf: Reader) throws -> Self { + static func read(from buf: Reader) throws -> Self { let v: UInt64 = try buf.readInt() // The Rust code won't compile if a pointer won't fit in a UInt64. // We have to go via `UInt` because that's the thing that's the size of a pointer. @@ -1065,17 +966,17 @@ fileprivate extension PartiallySignedBitcoinTransaction { return try self.lift(ptr!) } - fileprivate func write(into buf: Writer) { + func write(into buf: Writer) { // This fiddling is because `Int` is the thing that's the same size as a pointer. // The Rust code won't compile if a pointer won't fit in a `UInt64`. buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) } - fileprivate static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { + static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { return Self(unsafeFromRawPointer: pointer) } - fileprivate func lower() -> UnsafeMutableRawPointer { + func lower() -> UnsafeMutableRawPointer { return self.pointer } } @@ -1196,7 +1097,7 @@ fileprivate extension TransactionDetails { extension TransactionDetails: ViaFfiUsingByteBuffer, ViaFfi {} -public struct Confirmation { +public struct BlockTime { public var height: UInt32 public var timestamp: UInt64 @@ -1209,8 +1110,8 @@ public struct Confirmation { } -extension Confirmation: Equatable, Hashable { - public static func ==(lhs: Confirmation, rhs: Confirmation) -> Bool { +extension BlockTime: Equatable, Hashable { + public static func ==(lhs: BlockTime, rhs: BlockTime) -> Bool { if lhs.height != rhs.height { return false } @@ -1227,9 +1128,9 @@ extension Confirmation: Equatable, Hashable { } -fileprivate extension Confirmation { - static func read(from buf: Reader) throws -> Confirmation { - return try Confirmation( +fileprivate extension BlockTime { + static func read(from buf: Reader) throws -> BlockTime { + return try BlockTime( height: UInt32.read(from: buf), timestamp: UInt64.read(from: buf) ) @@ -1241,7 +1142,7 @@ fileprivate extension Confirmation { } } -extension Confirmation: ViaFfiUsingByteBuffer, ViaFfi {} +extension BlockTime: ViaFfiUsingByteBuffer, ViaFfi {} public struct ElectrumConfig { public var url: String @@ -1868,13 +1769,13 @@ extension BdkError: Error { } // Declaration and FfiConverters for BdkProgress Callback Interface public protocol BdkProgress : AnyObject { - func update(progress: Float, message: String? ) + func update( progress: Float, message: String? ) } // The ForeignCallback that is passed to Rust. fileprivate let foreignCallbackCallbackInterfaceBdkProgress : ForeignCallback = - { (handle: Handle, method: Int32, args: RustBuffer) -> RustBuffer in + { (handle: Handle, method: Int32, args: RustBuffer, out_buf: UnsafeMutablePointer) -> Int32 in func invokeUpdate(_ swiftCallbackInterface: BdkProgress, _ args: RustBuffer) throws -> RustBuffer { defer { args.deallocate() } @@ -1894,20 +1795,30 @@ fileprivate let foreignCallbackCallbackInterfaceBdkProgress : ForeignCallback = switch method { case IDX_CALLBACK_FREE: ffiConverterCallbackInterfaceBdkProgress.drop(handle: handle) - return RustBuffer() - case 1: return try! invokeUpdate(cb, args) + // No return value. + // See docs of ForeignCallback in `uniffi/src/ffi/foreigncallbacks.rs` + return 0 + case 1: + let buffer = try! invokeUpdate(cb, args) + out_buf.pointee = buffer + // Value written to out buffer. + // See docs of ForeignCallback in `uniffi/src/ffi/foreigncallbacks.rs` + return 1 // This should never happen, because an out of bounds method index won't // ever be used. Once we can catch errors, we should return an InternalError. // https://github.com/mozilla/uniffi-rs/issues/351 - default: return RustBuffer() + default: + // An unexpected error happened. + // See docs of ForeignCallback in `uniffi/src/ffi/foreigncallbacks.rs` + return -1 } } // The ffiConverter which transforms the Callbacks in to Handles to pass to Rust. private let ffiConverterCallbackInterfaceBdkProgress: FfiConverterCallbackInterface = { try! rustCall { (err: UnsafeMutablePointer) in - ffi_bdk_2e4d_BdkProgress_init_callback(foreignCallbackCallbackInterfaceBdkProgress, err) + ffi_bdk_d04b_BdkProgress_init_callback(foreignCallbackCallbackInterfaceBdkProgress, err) } return FfiConverterCallbackInterface() }() @@ -1983,10 +1894,9 @@ extension String: ViaFfi { buf.writeBytes(self.utf8) } } -// Helper code for OfflineWallet class is found in ObjectTemplate.swift -// Helper code for OnlineWallet class is found in ObjectTemplate.swift // Helper code for PartiallySignedBitcoinTransaction class is found in ObjectTemplate.swift -// Helper code for Confirmation record is found in RecordTemplate.swift +// Helper code for Wallet class is found in ObjectTemplate.swift +// Helper code for BlockTime record is found in RecordTemplate.swift // Helper code for ElectrumConfig record is found in RecordTemplate.swift // Helper code for EsploraConfig record is found in RecordTemplate.swift // Helper code for ExtendedKeyInfo record is found in RecordTemplate.swift @@ -1994,9 +1904,9 @@ extension String: ViaFfi { // Helper code for TransactionDetails record is found in RecordTemplate.swift // Helper code for BlockchainConfig enum is found in EnumTemplate.swift // Helper code for DatabaseConfig enum is found in EnumTemplate.swift -// Helper code for MnemonicType enum is found in EnumTemplate.swift // Helper code for Network enum is found in EnumTemplate.swift // Helper code for Transaction enum is found in EnumTemplate.swift +// Helper code for WordCount enum is found in EnumTemplate.swift // Helper code for BdkError error is found in ErrorTemplate.swift fileprivate enum FfiConverterOptionUInt8: FfiConverterUsingByteBuffer { diff --git a/bdk-ffi b/bdk-ffi index 6fe9bdd..89d58db 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit 6fe9bddcfab97d061668da35cde2d12197014c7a +Subproject commit 89d58db02a7b04eba9e18c9c84213845ed01d2dc From 61c75b24bd92ab9b0277127b88852ec186b18004 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Wed, 2 Mar 2022 20:17:11 -0800 Subject: [PATCH 16/33] Add example project to README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index c15f1aa..6acd9ef 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,10 @@ let wallet = try OfflineWallet.init(descriptor: desc, network: Network.regtest, let address = wallet.getNewAddress() ``` +### Example Projects + +* [BdkSwiftSample](https://github.com/futurepaul/BdkSwiftSample) + ## How to Build and Publish If you are a maintainer of this project or want to build and publish this project to your From 91b290e4745d28da7af71d4ca2f69956dd2434b4 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Wed, 2 Mar 2022 20:29:38 -0800 Subject: [PATCH 17/33] Bump version to 0.2.0 --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index ef01ea6..3b1a4ed 100644 --- a/Package.swift +++ b/Package.swift @@ -24,8 +24,8 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages this package depends on. .binaryTarget( name: "bdkFFI", - url: "https://github.com/bitcoindevkit/bdk-swift/releases/download/0.1.4/bdkFFI.xcframework.zip", - checksum: "dc51c5c61b78e06fba45fe7d55978726f6f6bb609c2b369f12f3f2e5c24b9ed5"), + url: "https://github.com/bitcoindevkit/bdk-swift/releases/download/0.2.0/bdkFFI.xcframework.zip", + checksum: "db20d82b5dcd663b5154445f6a17f81e14fdc9f9c81ce8d71f76c34e91e42182"), // .binaryTarget(name: "bdkFFI", path: "./bdkFFI.xcframework"), .target( name: "BitcoinDevKit", From e6223be90529fa0120d4df6a8078a3599f631a4f Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Fri, 13 May 2022 13:45:48 -0700 Subject: [PATCH 18/33] Update to bdk-ffi 0.6.0 --- README.md | 6 +- Sources/BitcoinDevKit/BitcoinDevKit.swift | 584 ++++++++++++++---- .../BitcoinDevKitTests.swift | 4 +- bdk-ffi | 2 +- build.sh | 4 +- 5 files changed, 482 insertions(+), 118 deletions(-) diff --git a/README.md b/README.md index 6acd9ef..b5a73bf 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,10 @@ own Github repository use the following steps: 1. Install required targets. ```shell - rustup target add aarch64-apple-ios x86_64-apple-ios - ``` + rustup target add aarch64-apple-ios x86_64-apple-ios + rustup target add aarch64-apple-ios-sim --toolchain nightly + rustup component add rust-src --toolchain nightly-aarch64-apple-darwin + ``` 1. Build [`bdk-ffi`] Swift bindings and `bdkFFI.xcframework.zip`. ```shell diff --git a/Sources/BitcoinDevKit/BitcoinDevKit.swift b/Sources/BitcoinDevKit/BitcoinDevKit.swift index dcb7a69..2e046f8 100644 --- a/Sources/BitcoinDevKit/BitcoinDevKit.swift +++ b/Sources/BitcoinDevKit/BitcoinDevKit.swift @@ -19,13 +19,13 @@ fileprivate extension RustBuffer { } static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { - try! rustCall { ffi_bdk_d04b_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } + try! rustCall { ffi_bdk_360_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } } // Frees the buffer in place. // The buffer must not be used after this is called. func deallocate() { - try! rustCall { ffi_bdk_d04b_rustbuffer_free(self, $0) } + try! rustCall { ffi_bdk_360_rustbuffer_free(self, $0) } } } @@ -528,8 +528,9 @@ extension Network: Equatable, Hashable {} public enum DatabaseConfig { - case memory(junk: String ) + case memory case sled(config: SledDbConfiguration ) + case sqlite(config: SqliteDbConfiguration ) } extension DatabaseConfig: ViaFfiUsingByteBuffer, ViaFfi { @@ -537,12 +538,13 @@ extension DatabaseConfig: ViaFfiUsingByteBuffer, ViaFfi { let variant: Int32 = try buf.readInt() switch variant { - case 1: return .memory( - junk: try String.read(from: buf) - ) + case 1: return .memory case 2: return .sled( config: try SledDbConfiguration.read(from: buf) ) + case 3: return .sqlite( + config: try SqliteDbConfiguration.read(from: buf) + ) default: throw UniffiInternalError.unexpectedEnumCase } } @@ -551,10 +553,8 @@ extension DatabaseConfig: ViaFfiUsingByteBuffer, ViaFfi { switch self { - case let .memory(junk): + case .memory: buf.writeInt(Int32(1)) - junk.write(into: buf) - case let .sled(config): @@ -562,6 +562,12 @@ extension DatabaseConfig: ViaFfiUsingByteBuffer, ViaFfi { config.write(into: buf) + + case let .sqlite(config): + buf.writeInt(Int32(3)) + config.write(into: buf) + + } } } @@ -730,7 +736,7 @@ public func generateExtendedKey( network: Network, wordCount: WordCount, passw rustCallWithError(BdkError.self) { - bdk_d04b_generate_extended_key(network.lower(), wordCount.lower(), FfiConverterOptionString.lower(password) , $0) + bdk_360_generate_extended_key(network.lower(), wordCount.lower(), FfiConverterOptionString.lower(password) , $0) } return try ExtendedKeyInfo.lift(_retval) } @@ -743,13 +749,92 @@ public func restoreExtendedKey( network: Network, mnemonic: String, password: rustCallWithError(BdkError.self) { - bdk_d04b_restore_extended_key(network.lower(), mnemonic.lower(), FfiConverterOptionString.lower(password) , $0) + bdk_360_restore_extended_key(network.lower(), mnemonic.lower(), FfiConverterOptionString.lower(password) , $0) } return try ExtendedKeyInfo.lift(_retval) } +public protocol BlockchainProtocol { + func broadcast( psbt: PartiallySignedBitcoinTransaction ) throws + +} + +public class Blockchain: BlockchainProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `ViaFfi` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init( config: BlockchainConfig ) throws { + self.init(unsafeFromRawPointer: try + + + rustCallWithError(BdkError.self) { + + bdk_360_Blockchain_new(config.lower() , $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_360_Blockchain_object_free(pointer, $0) } + } + + + + + public func broadcast( psbt: PartiallySignedBitcoinTransaction ) throws { + try + rustCallWithError(BdkError.self) { + + bdk_360_Blockchain_broadcast(self.pointer, psbt.lower() , $0 + ) +} + } + +} + + +fileprivate extension Blockchain { + typealias FfiType = UnsafeMutableRawPointer + + static func read(from buf: Reader) throws -> Self { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try self.lift(ptr!) + } + + func write(into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) + } + + static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { + return Self(unsafeFromRawPointer: pointer) + } + + func lower() -> UnsafeMutableRawPointer { + return self.pointer + } +} + +// Ideally this would be `fileprivate`, but Swift says: +// """ +// 'private' modifier cannot be used with extensions that declare protocol conformances +// """ +extension Blockchain : ViaFfi, Serializable {} + + public protocol WalletProtocol { func getNewAddress() -> String func getLastUnusedAddress() -> String @@ -757,8 +842,7 @@ public protocol WalletProtocol { func sign( psbt: PartiallySignedBitcoinTransaction ) throws func getTransactions() throws -> [Transaction] func getNetwork() -> Network - func sync( progressUpdate: BdkProgress, maxAddressParam: UInt32? ) throws - func broadcast( psbt: PartiallySignedBitcoinTransaction ) throws -> Transaction + func sync( blockchain: Blockchain, progress: Progress? ) throws } @@ -771,18 +855,18 @@ public class Wallet: WalletProtocol { required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { self.pointer = pointer } - public convenience init( descriptor: String, changeDescriptor: String?, network: Network, databaseConfig: DatabaseConfig, blockchainConfig: BlockchainConfig ) throws { + public convenience init( descriptor: String, changeDescriptor: String?, network: Network, databaseConfig: DatabaseConfig ) throws { self.init(unsafeFromRawPointer: try rustCallWithError(BdkError.self) { - bdk_d04b_Wallet_new(descriptor.lower(), FfiConverterOptionString.lower(changeDescriptor), network.lower(), databaseConfig.lower(), blockchainConfig.lower() , $0) + bdk_360_Wallet_new(descriptor.lower(), FfiConverterOptionString.lower(changeDescriptor), network.lower(), databaseConfig.lower() , $0) }) } deinit { - try! rustCall { ffi_bdk_d04b_Wallet_object_free(pointer, $0) } + try! rustCall { ffi_bdk_360_Wallet_object_free(pointer, $0) } } @@ -792,7 +876,7 @@ public class Wallet: WalletProtocol { let _retval = try! rustCall() { - bdk_d04b_Wallet_get_new_address(self.pointer, $0 + bdk_360_Wallet_get_new_address(self.pointer, $0 ) } return try! String.lift(_retval) @@ -801,7 +885,7 @@ public class Wallet: WalletProtocol { let _retval = try! rustCall() { - bdk_d04b_Wallet_get_last_unused_address(self.pointer, $0 + bdk_360_Wallet_get_last_unused_address(self.pointer, $0 ) } return try! String.lift(_retval) @@ -810,7 +894,7 @@ public class Wallet: WalletProtocol { let _retval = try rustCallWithError(BdkError.self) { - bdk_d04b_Wallet_get_balance(self.pointer, $0 + bdk_360_Wallet_get_balance(self.pointer, $0 ) } return try UInt64.lift(_retval) @@ -819,7 +903,7 @@ public class Wallet: WalletProtocol { try rustCallWithError(BdkError.self) { - bdk_d04b_Wallet_sign(self.pointer, psbt.lower() , $0 + bdk_360_Wallet_sign(self.pointer, psbt.lower() , $0 ) } } @@ -827,7 +911,7 @@ public class Wallet: WalletProtocol { let _retval = try rustCallWithError(BdkError.self) { - bdk_d04b_Wallet_get_transactions(self.pointer, $0 + bdk_360_Wallet_get_transactions(self.pointer, $0 ) } return try FfiConverterSequenceEnumTransaction.lift(_retval) @@ -836,28 +920,19 @@ public class Wallet: WalletProtocol { let _retval = try! rustCall() { - bdk_d04b_Wallet_get_network(self.pointer, $0 + bdk_360_Wallet_get_network(self.pointer, $0 ) } return try! Network.lift(_retval) } - public func sync( progressUpdate: BdkProgress, maxAddressParam: UInt32? ) throws { + public func sync( blockchain: Blockchain, progress: Progress? ) throws { try rustCallWithError(BdkError.self) { - bdk_d04b_Wallet_sync(self.pointer, ffiConverterCallbackInterfaceBdkProgress.lower(progressUpdate), FfiConverterOptionUInt32.lower(maxAddressParam) , $0 + bdk_360_Wallet_sync(self.pointer, blockchain.lower(), FfiConverterOptionCallbackInterfaceProgress.lower(progress) , $0 ) } } - public func broadcast( psbt: PartiallySignedBitcoinTransaction ) throws -> Transaction { - let _retval = try - rustCallWithError(BdkError.self) { - - bdk_d04b_Wallet_broadcast(self.pointer, psbt.lower() , $0 - ) -} - return try Transaction.lift(_retval) - } } @@ -900,6 +975,7 @@ extension Wallet : ViaFfi, Serializable {} public protocol PartiallySignedBitcoinTransactionProtocol { func serialize() -> String + func txid() -> String } @@ -912,38 +988,37 @@ public class PartiallySignedBitcoinTransaction: PartiallySignedBitcoinTransactio required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { self.pointer = pointer } - public convenience init( wallet: Wallet, recipient: String, amount: UInt64, feeRate: Float? ) throws { + public convenience init( psbtBase64: String ) throws { self.init(unsafeFromRawPointer: try rustCallWithError(BdkError.self) { - bdk_d04b_PartiallySignedBitcoinTransaction_new(wallet.lower(), recipient.lower(), amount.lower(), FfiConverterOptionFloat.lower(feeRate) , $0) + bdk_360_PartiallySignedBitcoinTransaction_new(psbtBase64.lower() , $0) }) } deinit { - try! rustCall { ffi_bdk_d04b_PartiallySignedBitcoinTransaction_object_free(pointer, $0) } + try! rustCall { ffi_bdk_360_PartiallySignedBitcoinTransaction_object_free(pointer, $0) } } - public static func deserialize( psbtBase64: String ) throws -> PartiallySignedBitcoinTransaction { - return PartiallySignedBitcoinTransaction(unsafeFromRawPointer: try - - - rustCallWithError(BdkError.self) { - - bdk_d04b_PartiallySignedBitcoinTransaction_deserialize(psbtBase64.lower() , $0) -}) - } - public func serialize() -> String { let _retval = try! rustCall() { - bdk_d04b_PartiallySignedBitcoinTransaction_serialize(self.pointer, $0 + bdk_360_PartiallySignedBitcoinTransaction_serialize(self.pointer, $0 + ) +} + return try! String.lift(_retval) + } + public func txid() -> String { + let _retval = try! + rustCall() { + + bdk_360_PartiallySignedBitcoinTransaction_txid(self.pointer, $0 ) } return try! String.lift(_retval) @@ -987,6 +1062,256 @@ fileprivate extension PartiallySignedBitcoinTransaction { // """ extension PartiallySignedBitcoinTransaction : ViaFfi, Serializable {} + +public protocol TxBuilderProtocol { + func addRecipient( address: String, amount: UInt64 ) -> TxBuilder + func feeRate( satPerVbyte: Float ) -> TxBuilder + func drainWallet() -> TxBuilder + func drainTo( address: String ) -> TxBuilder + func enableRbf() -> TxBuilder + func enableRbfWithSequence( nsequence: UInt32 ) -> TxBuilder + func finish( wallet: Wallet ) throws -> PartiallySignedBitcoinTransaction + +} + +public class TxBuilder: TxBuilderProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `ViaFfi` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init() { + self.init(unsafeFromRawPointer: try! + + + rustCall() { + + bdk_360_TxBuilder_new( $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_360_TxBuilder_object_free(pointer, $0) } + } + + + + + public func addRecipient( address: String, amount: UInt64 ) -> TxBuilder { + let _retval = try! + rustCall() { + + bdk_360_TxBuilder_add_recipient(self.pointer, address.lower(), amount.lower() , $0 + ) +} + return try! TxBuilder.lift(_retval) + } + public func feeRate( satPerVbyte: Float ) -> TxBuilder { + let _retval = try! + rustCall() { + + bdk_360_TxBuilder_fee_rate(self.pointer, satPerVbyte.lower() , $0 + ) +} + return try! TxBuilder.lift(_retval) + } + public func drainWallet() -> TxBuilder { + let _retval = try! + rustCall() { + + bdk_360_TxBuilder_drain_wallet(self.pointer, $0 + ) +} + return try! TxBuilder.lift(_retval) + } + public func drainTo( address: String ) -> TxBuilder { + let _retval = try! + rustCall() { + + bdk_360_TxBuilder_drain_to(self.pointer, address.lower() , $0 + ) +} + return try! TxBuilder.lift(_retval) + } + public func enableRbf() -> TxBuilder { + let _retval = try! + rustCall() { + + bdk_360_TxBuilder_enable_rbf(self.pointer, $0 + ) +} + return try! TxBuilder.lift(_retval) + } + public func enableRbfWithSequence( nsequence: UInt32 ) -> TxBuilder { + let _retval = try! + rustCall() { + + bdk_360_TxBuilder_enable_rbf_with_sequence(self.pointer, nsequence.lower() , $0 + ) +} + return try! TxBuilder.lift(_retval) + } + public func finish( wallet: Wallet ) throws -> PartiallySignedBitcoinTransaction { + let _retval = try + rustCallWithError(BdkError.self) { + + bdk_360_TxBuilder_finish(self.pointer, wallet.lower() , $0 + ) +} + return try PartiallySignedBitcoinTransaction.lift(_retval) + } + +} + + +fileprivate extension TxBuilder { + typealias FfiType = UnsafeMutableRawPointer + + static func read(from buf: Reader) throws -> Self { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try self.lift(ptr!) + } + + func write(into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) + } + + static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { + return Self(unsafeFromRawPointer: pointer) + } + + func lower() -> UnsafeMutableRawPointer { + return self.pointer + } +} + +// Ideally this would be `fileprivate`, but Swift says: +// """ +// 'private' modifier cannot be used with extensions that declare protocol conformances +// """ +extension TxBuilder : ViaFfi, Serializable {} + + +public protocol BumpFeeTxBuilderProtocol { + func allowShrinking( address: String ) -> BumpFeeTxBuilder + func enableRbf() -> BumpFeeTxBuilder + func enableRbfWithSequence( nsequence: UInt32 ) -> BumpFeeTxBuilder + func finish( wallet: Wallet ) throws -> PartiallySignedBitcoinTransaction + +} + +public class BumpFeeTxBuilder: BumpFeeTxBuilderProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `ViaFfi` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init( txid: String, newFeeRate: Float ) { + self.init(unsafeFromRawPointer: try! + + + rustCall() { + + bdk_360_BumpFeeTxBuilder_new(txid.lower(), newFeeRate.lower() , $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_360_BumpFeeTxBuilder_object_free(pointer, $0) } + } + + + + + public func allowShrinking( address: String ) -> BumpFeeTxBuilder { + let _retval = try! + rustCall() { + + bdk_360_BumpFeeTxBuilder_allow_shrinking(self.pointer, address.lower() , $0 + ) +} + return try! BumpFeeTxBuilder.lift(_retval) + } + public func enableRbf() -> BumpFeeTxBuilder { + let _retval = try! + rustCall() { + + bdk_360_BumpFeeTxBuilder_enable_rbf(self.pointer, $0 + ) +} + return try! BumpFeeTxBuilder.lift(_retval) + } + public func enableRbfWithSequence( nsequence: UInt32 ) -> BumpFeeTxBuilder { + let _retval = try! + rustCall() { + + bdk_360_BumpFeeTxBuilder_enable_rbf_with_sequence(self.pointer, nsequence.lower() , $0 + ) +} + return try! BumpFeeTxBuilder.lift(_retval) + } + public func finish( wallet: Wallet ) throws -> PartiallySignedBitcoinTransaction { + let _retval = try + rustCallWithError(BdkError.self) { + + bdk_360_BumpFeeTxBuilder_finish(self.pointer, wallet.lower() , $0 + ) +} + return try PartiallySignedBitcoinTransaction.lift(_retval) + } + +} + + +fileprivate extension BumpFeeTxBuilder { + typealias FfiType = UnsafeMutableRawPointer + + static func read(from buf: Reader) throws -> Self { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try self.lift(ptr!) + } + + func write(into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) + } + + static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { + return Self(unsafeFromRawPointer: pointer) + } + + func lower() -> UnsafeMutableRawPointer { + return self.pointer + } +} + +// Ideally this would be `fileprivate`, but Swift says: +// """ +// 'private' modifier cannot be used with extensions that declare protocol conformances +// """ +extension BumpFeeTxBuilder : ViaFfi, Serializable {} + public struct SledDbConfiguration { public var path: String public var treeName: String @@ -1034,16 +1359,55 @@ fileprivate extension SledDbConfiguration { extension SledDbConfiguration: ViaFfiUsingByteBuffer, ViaFfi {} +public struct SqliteDbConfiguration { + public var path: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(path: String ) { + self.path = path + } +} + + +extension SqliteDbConfiguration: Equatable, Hashable { + public static func ==(lhs: SqliteDbConfiguration, rhs: SqliteDbConfiguration) -> Bool { + if lhs.path != rhs.path { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(path) + } +} + + +fileprivate extension SqliteDbConfiguration { + static func read(from buf: Reader) throws -> SqliteDbConfiguration { + return try SqliteDbConfiguration( + path: String.read(from: buf) + ) + } + + func write(into buf: Writer) { + self.path.write(into: buf) + } +} + +extension SqliteDbConfiguration: ViaFfiUsingByteBuffer, ViaFfi {} + public struct TransactionDetails { - public var fees: UInt64? + public var fee: UInt64? public var received: UInt64 public var sent: UInt64 public var txid: String // Default memberwise initializers are never public by default, so we // declare one manually. - public init(fees: UInt64?, received: UInt64, sent: UInt64, txid: String ) { - self.fees = fees + public init(fee: UInt64?, received: UInt64, sent: UInt64, txid: String ) { + self.fee = fee self.received = received self.sent = sent self.txid = txid @@ -1053,7 +1417,7 @@ public struct TransactionDetails { extension TransactionDetails: Equatable, Hashable { public static func ==(lhs: TransactionDetails, rhs: TransactionDetails) -> Bool { - if lhs.fees != rhs.fees { + if lhs.fee != rhs.fee { return false } if lhs.received != rhs.received { @@ -1069,7 +1433,7 @@ extension TransactionDetails: Equatable, Hashable { } public func hash(into hasher: inout Hasher) { - hasher.combine(fees) + hasher.combine(fee) hasher.combine(received) hasher.combine(sent) hasher.combine(txid) @@ -1080,7 +1444,7 @@ extension TransactionDetails: Equatable, Hashable { fileprivate extension TransactionDetails { static func read(from buf: Reader) throws -> TransactionDetails { return try TransactionDetails( - fees: FfiConverterOptionUInt64.read(from: buf), + fee: FfiConverterOptionUInt64.read(from: buf), received: UInt64.read(from: buf), sent: UInt64.read(from: buf), txid: String.read(from: buf) @@ -1088,7 +1452,7 @@ fileprivate extension TransactionDetails { } func write(into buf: Writer) { - FfiConverterOptionUInt64.write(self.fees, into: buf) + FfiConverterOptionUInt64.write(self.fee, into: buf) self.received.write(into: buf) self.sent.write(into: buf) self.txid.write(into: buf) @@ -1218,18 +1582,18 @@ extension ElectrumConfig: ViaFfiUsingByteBuffer, ViaFfi {} public struct EsploraConfig { public var baseUrl: String public var proxy: String? - public var timeoutRead: UInt64 - public var timeoutWrite: UInt64 + public var concurrency: UInt8? public var stopGap: UInt64 + public var timeout: UInt64? // Default memberwise initializers are never public by default, so we // declare one manually. - public init(baseUrl: String, proxy: String?, timeoutRead: UInt64, timeoutWrite: UInt64, stopGap: UInt64 ) { + public init(baseUrl: String, proxy: String?, concurrency: UInt8?, stopGap: UInt64, timeout: UInt64? ) { self.baseUrl = baseUrl self.proxy = proxy - self.timeoutRead = timeoutRead - self.timeoutWrite = timeoutWrite + self.concurrency = concurrency self.stopGap = stopGap + self.timeout = timeout } } @@ -1242,24 +1606,24 @@ extension EsploraConfig: Equatable, Hashable { if lhs.proxy != rhs.proxy { return false } - if lhs.timeoutRead != rhs.timeoutRead { - return false - } - if lhs.timeoutWrite != rhs.timeoutWrite { + if lhs.concurrency != rhs.concurrency { return false } if lhs.stopGap != rhs.stopGap { return false } + if lhs.timeout != rhs.timeout { + return false + } return true } public func hash(into hasher: inout Hasher) { hasher.combine(baseUrl) hasher.combine(proxy) - hasher.combine(timeoutRead) - hasher.combine(timeoutWrite) + hasher.combine(concurrency) hasher.combine(stopGap) + hasher.combine(timeout) } } @@ -1269,18 +1633,18 @@ fileprivate extension EsploraConfig { return try EsploraConfig( baseUrl: String.read(from: buf), proxy: FfiConverterOptionString.read(from: buf), - timeoutRead: UInt64.read(from: buf), - timeoutWrite: UInt64.read(from: buf), - stopGap: UInt64.read(from: buf) + concurrency: FfiConverterOptionUInt8.read(from: buf), + stopGap: UInt64.read(from: buf), + timeout: FfiConverterOptionUInt64.read(from: buf) ) } func write(into buf: Writer) { self.baseUrl.write(into: buf) FfiConverterOptionString.write(self.proxy, into: buf) - self.timeoutRead.write(into: buf) - self.timeoutWrite.write(into: buf) + FfiConverterOptionUInt8.write(self.concurrency, into: buf) self.stopGap.write(into: buf) + FfiConverterOptionUInt64.write(self.timeout, into: buf) } } @@ -1462,6 +1826,9 @@ public enum BdkError { // Simple error enums only carry a message case Sled(message: String) + // Simple error enums only carry a message + case Rusqlite(message: String) + } extension BdkError: ViaFfiUsingByteBuffer, ViaFfi { @@ -1628,6 +1995,10 @@ extension BdkError: ViaFfiUsingByteBuffer, ViaFfi { message: try String.read(from: buf) ) + case 40: return .Rusqlite( + message: try String.read(from: buf) + ) + default: throw UniffiInternalError.unexpectedEnumCase } @@ -1756,6 +2127,9 @@ extension BdkError: ViaFfiUsingByteBuffer, ViaFfi { case let .Sled(message): buf.writeInt(Int32(39)) message.write(into: buf) + case let .Rusqlite(message): + buf.writeInt(Int32(40)) + message.write(into: buf) } } } @@ -1766,17 +2140,17 @@ extension BdkError: Equatable, Hashable {} extension BdkError: Error { } -// Declaration and FfiConverters for BdkProgress Callback Interface +// Declaration and FfiConverters for Progress Callback Interface -public protocol BdkProgress : AnyObject { +public protocol Progress : AnyObject { func update( progress: Float, message: String? ) } // The ForeignCallback that is passed to Rust. -fileprivate let foreignCallbackCallbackInterfaceBdkProgress : ForeignCallback = +fileprivate let foreignCallbackCallbackInterfaceProgress : ForeignCallback = { (handle: Handle, method: Int32, args: RustBuffer, out_buf: UnsafeMutablePointer) -> Int32 in - func invokeUpdate(_ swiftCallbackInterface: BdkProgress, _ args: RustBuffer) throws -> RustBuffer { + func invokeUpdate(_ swiftCallbackInterface: Progress, _ args: RustBuffer) throws -> RustBuffer { defer { args.deallocate() } let reader = Reader(data: Data(rustBuffer: args)) @@ -1791,10 +2165,10 @@ fileprivate let foreignCallbackCallbackInterfaceBdkProgress : ForeignCallback = } - let cb = try! ffiConverterCallbackInterfaceBdkProgress.lift(handle) + let cb = try! ffiConverterCallbackInterfaceProgress.lift(handle) switch method { case IDX_CALLBACK_FREE: - ffiConverterCallbackInterfaceBdkProgress.drop(handle: handle) + ffiConverterCallbackInterfaceProgress.drop(handle: handle) // No return value. // See docs of ForeignCallback in `uniffi/src/ffi/foreigncallbacks.rs` return 0 @@ -1816,11 +2190,11 @@ fileprivate let foreignCallbackCallbackInterfaceBdkProgress : ForeignCallback = } // The ffiConverter which transforms the Callbacks in to Handles to pass to Rust. -private let ffiConverterCallbackInterfaceBdkProgress: FfiConverterCallbackInterface = { +private let ffiConverterCallbackInterfaceProgress: FfiConverterCallbackInterface = { try! rustCall { (err: UnsafeMutablePointer) in - ffi_bdk_d04b_BdkProgress_init_callback(foreignCallbackCallbackInterfaceBdkProgress, err) + ffi_bdk_360_Progress_init_callback(foreignCallbackCallbackInterfaceProgress, err) } - return FfiConverterCallbackInterface() + return FfiConverterCallbackInterface() }() extension UInt8: Primitive, ViaFfi { fileprivate static func read(from buf: Reader) throws -> Self { @@ -1894,13 +2268,17 @@ extension String: ViaFfi { buf.writeBytes(self.utf8) } } +// Helper code for Blockchain class is found in ObjectTemplate.swift +// Helper code for BumpFeeTxBuilder class is found in ObjectTemplate.swift // Helper code for PartiallySignedBitcoinTransaction class is found in ObjectTemplate.swift +// Helper code for TxBuilder class is found in ObjectTemplate.swift // Helper code for Wallet class is found in ObjectTemplate.swift // Helper code for BlockTime record is found in RecordTemplate.swift // Helper code for ElectrumConfig record is found in RecordTemplate.swift // Helper code for EsploraConfig record is found in RecordTemplate.swift // Helper code for ExtendedKeyInfo record is found in RecordTemplate.swift // Helper code for SledDbConfiguration record is found in RecordTemplate.swift +// Helper code for SqliteDbConfiguration record is found in RecordTemplate.swift // Helper code for TransactionDetails record is found in RecordTemplate.swift // Helper code for BlockchainConfig enum is found in EnumTemplate.swift // Helper code for DatabaseConfig enum is found in EnumTemplate.swift @@ -1925,22 +2303,6 @@ fileprivate enum FfiConverterOptionUInt8: FfiConverterUsingByteBuffer { } } -fileprivate enum FfiConverterOptionUInt32: FfiConverterUsingByteBuffer { - typealias SwiftType = UInt32? - - static func write(_ value: SwiftType, into buf: Writer) { - FfiConverterOptional.write(value, into: buf) { item, buf in - item.write(into: buf) - } - } - - static func read(from buf: Reader) throws -> SwiftType { - try FfiConverterOptional.read(from: buf) { buf in - try UInt32.read(from: buf) - } - } -} - fileprivate enum FfiConverterOptionUInt64: FfiConverterUsingByteBuffer { typealias SwiftType = UInt64? @@ -1957,22 +2319,6 @@ fileprivate enum FfiConverterOptionUInt64: FfiConverterUsingByteBuffer { } } -fileprivate enum FfiConverterOptionFloat: FfiConverterUsingByteBuffer { - typealias SwiftType = Float? - - static func write(_ value: SwiftType, into buf: Writer) { - FfiConverterOptional.write(value, into: buf) { item, buf in - item.write(into: buf) - } - } - - static func read(from buf: Reader) throws -> SwiftType { - try FfiConverterOptional.read(from: buf) { buf in - try Float.read(from: buf) - } - } -} - fileprivate enum FfiConverterOptionString: FfiConverterUsingByteBuffer { typealias SwiftType = String? @@ -1989,6 +2335,22 @@ fileprivate enum FfiConverterOptionString: FfiConverterUsingByteBuffer { } } +fileprivate enum FfiConverterOptionCallbackInterfaceProgress: FfiConverterUsingByteBuffer { + typealias SwiftType = Progress? + + static func write(_ value: SwiftType, into buf: Writer) { + FfiConverterOptional.write(value, into: buf) { item, buf in + ffiConverterCallbackInterfaceProgress.write(item, into: buf) + } + } + + static func read(from buf: Reader) throws -> SwiftType { + try FfiConverterOptional.read(from: buf) { buf in + try ffiConverterCallbackInterfaceProgress.read(from: buf) + } + } +} + fileprivate enum FfiConverterSequenceEnumTransaction: FfiConverterUsingByteBuffer { typealias SwiftType = [Transaction] diff --git a/Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift b/Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift index 88b9a69..76475a7 100644 --- a/Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift +++ b/Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift @@ -4,8 +4,8 @@ import XCTest final class BitcoinDevKitTests: XCTestCase { func testMemoryWalletNewAddress() throws { let desc = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)" - let config = DatabaseConfig.memory(junk: "") - let wallet = try OfflineWallet.init(descriptor: desc, network: Network.regtest, databaseConfig: config) + let databaseConfig = DatabaseConfig.memory + let wallet = try Wallet.init(descriptor: desc, changeDescriptor: nil, network: Network.regtest, databaseConfig: databaseConfig) let address = wallet.getNewAddress() XCTAssertEqual(address, "bcrt1qzg4mckdh50nwdm9hkzq06528rsu73hjxytqkxs") } diff --git a/bdk-ffi b/bdk-ffi index 89d58db..30e54ac 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit 89d58db02a7b04eba9e18c9c84213845ed01d2dc +Subproject commit 30e54ac067f68e8c22d652837b4d5901c12e3384 diff --git a/build.sh b/build.sh index d238346..f18881d 100755 --- a/build.sh +++ b/build.sh @@ -7,7 +7,7 @@ echo "Confirm bdk-ffi rust lib builds" cargo build --release echo "Generate bdk-ffi swift bindings" -uniffi-bindgen generate src/bdk.udl --no-format --out-dir ../Sources/BitcoinDevKit --language swift +cargo run --package bdk-ffi-bindgen -- --language swift --out-dir ../Sources/BitcoinDevKit ## build bdk-ffi rust libs for apple targets and add to xcframework echo "Build bdk-ffi libs for apple targets and add to xcframework" @@ -36,7 +36,7 @@ lipo target/aarch64-apple-darwin/release/libbdkffi.a target/x86_64-apple-darwin/ # -library target/lipo-macos/release/libbdkffi.a \ # -library target/aarch64-apple-ios/release/libbdkffi.a \ # -output ../bdkFFI.xcframework - + popd # rename bdk.swift bindings to BitcoinDevKit.swift From 5622b070479578490c43cb2f31200215a2c1d1b6 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Fri, 13 May 2022 14:13:08 -0700 Subject: [PATCH 19/33] Update Package binaryTarget for release 0.3.0 --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 3b1a4ed..1c80244 100644 --- a/Package.swift +++ b/Package.swift @@ -24,8 +24,8 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages this package depends on. .binaryTarget( name: "bdkFFI", - url: "https://github.com/bitcoindevkit/bdk-swift/releases/download/0.2.0/bdkFFI.xcframework.zip", - checksum: "db20d82b5dcd663b5154445f6a17f81e14fdc9f9c81ce8d71f76c34e91e42182"), + url: "https://github.com/bitcoindevkit/bdk-swift/releases/download/0.3.0/bdkFFI.xcframework.zip", + checksum: "7d4a2fdeb03fb3eff107e45ee3148dd9b67966406c82d6e3c19f653c27180cfd"), // .binaryTarget(name: "bdkFFI", path: "./bdkFFI.xcframework"), .target( name: "BitcoinDevKit", From 0dfaf3fd356e6c4a653ac9a1c69567126350197c Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Thu, 23 Jun 2022 11:03:26 -0700 Subject: [PATCH 20/33] Update instructions for installing required rust targets --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b5a73bf..f258b43 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,8 @@ own Github repository use the following steps: 1. Install required targets. ```shell rustup target add aarch64-apple-ios x86_64-apple-ios - rustup target add aarch64-apple-ios-sim --toolchain nightly - rustup component add rust-src --toolchain nightly-aarch64-apple-darwin + rustup target add aarch64-apple-ios-sim --toolchain nightly + rustup target add aarch64-apple-darwin x86_64-apple-darwin ``` 1. Build [`bdk-ffi`] Swift bindings and `bdkFFI.xcframework.zip`. From fe59f29cbc115e7ed4959ae86971a0a5a5dd8e63 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Thu, 23 Jun 2022 11:03:45 -0700 Subject: [PATCH 21/33] Update to bdk-ffi 0.7.0 --- Package.swift | 10 +- Sources/BitcoinDevKit/BitcoinDevKit.swift | 408 +++++++++++------- .../BitcoinDevKitTests.swift | 4 +- bdk-ffi | 2 +- 4 files changed, 261 insertions(+), 163 deletions(-) diff --git a/Package.swift b/Package.swift index 1c80244..99f7ea6 100644 --- a/Package.swift +++ b/Package.swift @@ -22,11 +22,11 @@ let package = Package( targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. - .binaryTarget( - name: "bdkFFI", - url: "https://github.com/bitcoindevkit/bdk-swift/releases/download/0.3.0/bdkFFI.xcframework.zip", - checksum: "7d4a2fdeb03fb3eff107e45ee3148dd9b67966406c82d6e3c19f653c27180cfd"), -// .binaryTarget(name: "bdkFFI", path: "./bdkFFI.xcframework"), +// .binaryTarget( +// name: "bdkFFI", +// url: "https://github.com/bitcoindevkit/bdk-swift/releases/download/0.3.0/bdkFFI.xcframework.zip", +// checksum: "7d4a2fdeb03fb3eff107e45ee3148dd9b67966406c82d6e3c19f653c27180cfd"), + .binaryTarget(name: "bdkFFI", path: "./bdkFFI.xcframework"), .target( name: "BitcoinDevKit", dependencies: ["bdkFFI"]), diff --git a/Sources/BitcoinDevKit/BitcoinDevKit.swift b/Sources/BitcoinDevKit/BitcoinDevKit.swift index 2e046f8..90a02f5 100644 --- a/Sources/BitcoinDevKit/BitcoinDevKit.swift +++ b/Sources/BitcoinDevKit/BitcoinDevKit.swift @@ -19,13 +19,13 @@ fileprivate extension RustBuffer { } static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { - try! rustCall { ffi_bdk_360_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } + try! rustCall { ffi_bdk_1c1_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } } // Frees the buffer in place. // The buffer must not be used after this is called. func deallocate() { - try! rustCall { ffi_bdk_360_rustbuffer_free(self, $0) } + try! rustCall { ffi_bdk_1c1_rustbuffer_free(self, $0) } } } @@ -472,6 +472,45 @@ fileprivate class FfiConverterCallbackInterface { } } +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum AddressIndex { + + case new + case lastUnused +} + +extension AddressIndex: ViaFfiUsingByteBuffer, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> AddressIndex { + let variant: Int32 = try buf.readInt() + switch variant { + + case 1: return .new + case 2: return .lastUnused + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + fileprivate func write(into buf: Writer) { + switch self { + + + case .new: + buf.writeInt(Int32(1)) + + + case .lastUnused: + buf.writeInt(Int32(2)) + + } + } +} + + +extension AddressIndex: Equatable, Hashable {} + + // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. @@ -625,53 +664,6 @@ extension Transaction: ViaFfiUsingByteBuffer, ViaFfi { extension Transaction: Equatable, Hashable {} -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - -public enum BlockchainConfig { - - case electrum(config: ElectrumConfig ) - case esplora(config: EsploraConfig ) -} - -extension BlockchainConfig: ViaFfiUsingByteBuffer, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> BlockchainConfig { - let variant: Int32 = try buf.readInt() - switch variant { - - case 1: return .electrum( - config: try ElectrumConfig.read(from: buf) - ) - case 2: return .esplora( - config: try EsploraConfig.read(from: buf) - ) - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - fileprivate func write(into buf: Writer) { - switch self { - - - case let .electrum(config): - buf.writeInt(Int32(1)) - config.write(into: buf) - - - - case let .esplora(config): - buf.writeInt(Int32(2)) - config.write(into: buf) - - - } - } -} - - -extension BlockchainConfig: Equatable, Hashable {} - - // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. @@ -729,6 +721,53 @@ extension WordCount: ViaFfiUsingByteBuffer, ViaFfi { extension WordCount: Equatable, Hashable {} +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum BlockchainConfig { + + case electrum(config: ElectrumConfig ) + case esplora(config: EsploraConfig ) +} + +extension BlockchainConfig: ViaFfiUsingByteBuffer, ViaFfi { + fileprivate static func read(from buf: Reader) throws -> BlockchainConfig { + let variant: Int32 = try buf.readInt() + switch variant { + + case 1: return .electrum( + config: try ElectrumConfig.read(from: buf) + ) + case 2: return .esplora( + config: try EsploraConfig.read(from: buf) + ) + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + fileprivate func write(into buf: Writer) { + switch self { + + + case let .electrum(config): + buf.writeInt(Int32(1)) + config.write(into: buf) + + + + case let .esplora(config): + buf.writeInt(Int32(2)) + config.write(into: buf) + + + } + } +} + + +extension BlockchainConfig: Equatable, Hashable {} + + public func generateExtendedKey( network: Network, wordCount: WordCount, password: String? ) throws -> ExtendedKeyInfo { let _retval = try @@ -736,7 +775,7 @@ public func generateExtendedKey( network: Network, wordCount: WordCount, passw rustCallWithError(BdkError.self) { - bdk_360_generate_extended_key(network.lower(), wordCount.lower(), FfiConverterOptionString.lower(password) , $0) + bdk_1c1_generate_extended_key(network.lower(), wordCount.lower(), FfiConverterOptionString.lower(password) , $0) } return try ExtendedKeyInfo.lift(_retval) } @@ -749,7 +788,7 @@ public func restoreExtendedKey( network: Network, mnemonic: String, password: rustCallWithError(BdkError.self) { - bdk_360_restore_extended_key(network.lower(), mnemonic.lower(), FfiConverterOptionString.lower(password) , $0) + bdk_1c1_restore_extended_key(network.lower(), mnemonic.lower(), FfiConverterOptionString.lower(password) , $0) } return try ExtendedKeyInfo.lift(_retval) } @@ -776,12 +815,12 @@ public class Blockchain: BlockchainProtocol { rustCallWithError(BdkError.self) { - bdk_360_Blockchain_new(config.lower() , $0) + bdk_1c1_Blockchain_new(config.lower() , $0) }) } deinit { - try! rustCall { ffi_bdk_360_Blockchain_object_free(pointer, $0) } + try! rustCall { ffi_bdk_1c1_Blockchain_object_free(pointer, $0) } } @@ -791,7 +830,7 @@ public class Blockchain: BlockchainProtocol { try rustCallWithError(BdkError.self) { - bdk_360_Blockchain_broadcast(self.pointer, psbt.lower() , $0 + bdk_1c1_Blockchain_broadcast(self.pointer, psbt.lower() , $0 ) } } @@ -836,10 +875,9 @@ extension Blockchain : ViaFfi, Serializable {} public protocol WalletProtocol { - func getNewAddress() -> String - func getLastUnusedAddress() -> String + func getAddress( addressIndex: AddressIndex ) throws -> AddressInfo func getBalance() throws -> UInt64 - func sign( psbt: PartiallySignedBitcoinTransaction ) throws + func sign( psbt: PartiallySignedBitcoinTransaction ) throws -> Bool func getTransactions() throws -> [Transaction] func getNetwork() -> Network func sync( blockchain: Blockchain, progress: Progress? ) throws @@ -861,57 +899,49 @@ public class Wallet: WalletProtocol { rustCallWithError(BdkError.self) { - bdk_360_Wallet_new(descriptor.lower(), FfiConverterOptionString.lower(changeDescriptor), network.lower(), databaseConfig.lower() , $0) + bdk_1c1_Wallet_new(descriptor.lower(), FfiConverterOptionString.lower(changeDescriptor), network.lower(), databaseConfig.lower() , $0) }) } deinit { - try! rustCall { ffi_bdk_360_Wallet_object_free(pointer, $0) } + try! rustCall { ffi_bdk_1c1_Wallet_object_free(pointer, $0) } } - public func getNewAddress() -> String { - let _retval = try! - rustCall() { + public func getAddress( addressIndex: AddressIndex ) throws -> AddressInfo { + let _retval = try + rustCallWithError(BdkError.self) { - bdk_360_Wallet_get_new_address(self.pointer, $0 + bdk_1c1_Wallet_get_address(self.pointer, addressIndex.lower() , $0 ) } - return try! String.lift(_retval) - } - public func getLastUnusedAddress() -> String { - let _retval = try! - rustCall() { - - bdk_360_Wallet_get_last_unused_address(self.pointer, $0 - ) -} - return try! String.lift(_retval) + return try AddressInfo.lift(_retval) } public func getBalance() throws -> UInt64 { let _retval = try rustCallWithError(BdkError.self) { - bdk_360_Wallet_get_balance(self.pointer, $0 + bdk_1c1_Wallet_get_balance(self.pointer, $0 ) } return try UInt64.lift(_retval) } - public func sign( psbt: PartiallySignedBitcoinTransaction ) throws { - try + public func sign( psbt: PartiallySignedBitcoinTransaction ) throws -> Bool { + let _retval = try rustCallWithError(BdkError.self) { - bdk_360_Wallet_sign(self.pointer, psbt.lower() , $0 + bdk_1c1_Wallet_sign(self.pointer, psbt.lower() , $0 ) } + return try Bool.lift(_retval) } public func getTransactions() throws -> [Transaction] { let _retval = try rustCallWithError(BdkError.self) { - bdk_360_Wallet_get_transactions(self.pointer, $0 + bdk_1c1_Wallet_get_transactions(self.pointer, $0 ) } return try FfiConverterSequenceEnumTransaction.lift(_retval) @@ -920,7 +950,7 @@ public class Wallet: WalletProtocol { let _retval = try! rustCall() { - bdk_360_Wallet_get_network(self.pointer, $0 + bdk_1c1_Wallet_get_network(self.pointer, $0 ) } return try! Network.lift(_retval) @@ -929,7 +959,7 @@ public class Wallet: WalletProtocol { try rustCallWithError(BdkError.self) { - bdk_360_Wallet_sync(self.pointer, blockchain.lower(), FfiConverterOptionCallbackInterfaceProgress.lower(progress) , $0 + bdk_1c1_Wallet_sync(self.pointer, blockchain.lower(), FfiConverterOptionCallbackInterfaceProgress.lower(progress) , $0 ) } } @@ -994,12 +1024,12 @@ public class PartiallySignedBitcoinTransaction: PartiallySignedBitcoinTransactio rustCallWithError(BdkError.self) { - bdk_360_PartiallySignedBitcoinTransaction_new(psbtBase64.lower() , $0) + bdk_1c1_PartiallySignedBitcoinTransaction_new(psbtBase64.lower() , $0) }) } deinit { - try! rustCall { ffi_bdk_360_PartiallySignedBitcoinTransaction_object_free(pointer, $0) } + try! rustCall { ffi_bdk_1c1_PartiallySignedBitcoinTransaction_object_free(pointer, $0) } } @@ -1009,7 +1039,7 @@ public class PartiallySignedBitcoinTransaction: PartiallySignedBitcoinTransactio let _retval = try! rustCall() { - bdk_360_PartiallySignedBitcoinTransaction_serialize(self.pointer, $0 + bdk_1c1_PartiallySignedBitcoinTransaction_serialize(self.pointer, $0 ) } return try! String.lift(_retval) @@ -1018,7 +1048,7 @@ public class PartiallySignedBitcoinTransaction: PartiallySignedBitcoinTransactio let _retval = try! rustCall() { - bdk_360_PartiallySignedBitcoinTransaction_txid(self.pointer, $0 + bdk_1c1_PartiallySignedBitcoinTransaction_txid(self.pointer, $0 ) } return try! String.lift(_retval) @@ -1089,12 +1119,12 @@ public class TxBuilder: TxBuilderProtocol { rustCall() { - bdk_360_TxBuilder_new( $0) + bdk_1c1_TxBuilder_new( $0) }) } deinit { - try! rustCall { ffi_bdk_360_TxBuilder_object_free(pointer, $0) } + try! rustCall { ffi_bdk_1c1_TxBuilder_object_free(pointer, $0) } } @@ -1104,7 +1134,7 @@ public class TxBuilder: TxBuilderProtocol { let _retval = try! rustCall() { - bdk_360_TxBuilder_add_recipient(self.pointer, address.lower(), amount.lower() , $0 + bdk_1c1_TxBuilder_add_recipient(self.pointer, address.lower(), amount.lower() , $0 ) } return try! TxBuilder.lift(_retval) @@ -1113,7 +1143,7 @@ public class TxBuilder: TxBuilderProtocol { let _retval = try! rustCall() { - bdk_360_TxBuilder_fee_rate(self.pointer, satPerVbyte.lower() , $0 + bdk_1c1_TxBuilder_fee_rate(self.pointer, satPerVbyte.lower() , $0 ) } return try! TxBuilder.lift(_retval) @@ -1122,7 +1152,7 @@ public class TxBuilder: TxBuilderProtocol { let _retval = try! rustCall() { - bdk_360_TxBuilder_drain_wallet(self.pointer, $0 + bdk_1c1_TxBuilder_drain_wallet(self.pointer, $0 ) } return try! TxBuilder.lift(_retval) @@ -1131,7 +1161,7 @@ public class TxBuilder: TxBuilderProtocol { let _retval = try! rustCall() { - bdk_360_TxBuilder_drain_to(self.pointer, address.lower() , $0 + bdk_1c1_TxBuilder_drain_to(self.pointer, address.lower() , $0 ) } return try! TxBuilder.lift(_retval) @@ -1140,7 +1170,7 @@ public class TxBuilder: TxBuilderProtocol { let _retval = try! rustCall() { - bdk_360_TxBuilder_enable_rbf(self.pointer, $0 + bdk_1c1_TxBuilder_enable_rbf(self.pointer, $0 ) } return try! TxBuilder.lift(_retval) @@ -1149,7 +1179,7 @@ public class TxBuilder: TxBuilderProtocol { let _retval = try! rustCall() { - bdk_360_TxBuilder_enable_rbf_with_sequence(self.pointer, nsequence.lower() , $0 + bdk_1c1_TxBuilder_enable_rbf_with_sequence(self.pointer, nsequence.lower() , $0 ) } return try! TxBuilder.lift(_retval) @@ -1158,7 +1188,7 @@ public class TxBuilder: TxBuilderProtocol { let _retval = try rustCallWithError(BdkError.self) { - bdk_360_TxBuilder_finish(self.pointer, wallet.lower() , $0 + bdk_1c1_TxBuilder_finish(self.pointer, wallet.lower() , $0 ) } return try PartiallySignedBitcoinTransaction.lift(_retval) @@ -1226,12 +1256,12 @@ public class BumpFeeTxBuilder: BumpFeeTxBuilderProtocol { rustCall() { - bdk_360_BumpFeeTxBuilder_new(txid.lower(), newFeeRate.lower() , $0) + bdk_1c1_BumpFeeTxBuilder_new(txid.lower(), newFeeRate.lower() , $0) }) } deinit { - try! rustCall { ffi_bdk_360_BumpFeeTxBuilder_object_free(pointer, $0) } + try! rustCall { ffi_bdk_1c1_BumpFeeTxBuilder_object_free(pointer, $0) } } @@ -1241,7 +1271,7 @@ public class BumpFeeTxBuilder: BumpFeeTxBuilderProtocol { let _retval = try! rustCall() { - bdk_360_BumpFeeTxBuilder_allow_shrinking(self.pointer, address.lower() , $0 + bdk_1c1_BumpFeeTxBuilder_allow_shrinking(self.pointer, address.lower() , $0 ) } return try! BumpFeeTxBuilder.lift(_retval) @@ -1250,7 +1280,7 @@ public class BumpFeeTxBuilder: BumpFeeTxBuilderProtocol { let _retval = try! rustCall() { - bdk_360_BumpFeeTxBuilder_enable_rbf(self.pointer, $0 + bdk_1c1_BumpFeeTxBuilder_enable_rbf(self.pointer, $0 ) } return try! BumpFeeTxBuilder.lift(_retval) @@ -1259,7 +1289,7 @@ public class BumpFeeTxBuilder: BumpFeeTxBuilderProtocol { let _retval = try! rustCall() { - bdk_360_BumpFeeTxBuilder_enable_rbf_with_sequence(self.pointer, nsequence.lower() , $0 + bdk_1c1_BumpFeeTxBuilder_enable_rbf_with_sequence(self.pointer, nsequence.lower() , $0 ) } return try! BumpFeeTxBuilder.lift(_retval) @@ -1268,7 +1298,7 @@ public class BumpFeeTxBuilder: BumpFeeTxBuilderProtocol { let _retval = try rustCallWithError(BdkError.self) { - bdk_360_BumpFeeTxBuilder_finish(self.pointer, wallet.lower() , $0 + bdk_1c1_BumpFeeTxBuilder_finish(self.pointer, wallet.lower() , $0 ) } return try PartiallySignedBitcoinTransaction.lift(_retval) @@ -1312,6 +1342,53 @@ fileprivate extension BumpFeeTxBuilder { // """ extension BumpFeeTxBuilder : ViaFfi, Serializable {} +public struct AddressInfo { + public var index: UInt32 + public var address: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(index: UInt32, address: String ) { + self.index = index + self.address = address + } +} + + +extension AddressInfo: Equatable, Hashable { + public static func ==(lhs: AddressInfo, rhs: AddressInfo) -> Bool { + if lhs.index != rhs.index { + return false + } + if lhs.address != rhs.address { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(index) + hasher.combine(address) + } +} + + +fileprivate extension AddressInfo { + static func read(from buf: Reader) throws -> AddressInfo { + return try AddressInfo( + index: UInt32.read(from: buf), + address: String.read(from: buf) + ) + } + + func write(into buf: Writer) { + self.index.write(into: buf) + self.address.write(into: buf) + } +} + +extension AddressInfo: ViaFfiUsingByteBuffer, ViaFfi {} + public struct SledDbConfiguration { public var path: String public var treeName: String @@ -1508,6 +1585,61 @@ fileprivate extension BlockTime { extension BlockTime: ViaFfiUsingByteBuffer, ViaFfi {} +public struct ExtendedKeyInfo { + public var mnemonic: String + public var xprv: String + public var fingerprint: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(mnemonic: String, xprv: String, fingerprint: String ) { + self.mnemonic = mnemonic + self.xprv = xprv + self.fingerprint = fingerprint + } +} + + +extension ExtendedKeyInfo: Equatable, Hashable { + public static func ==(lhs: ExtendedKeyInfo, rhs: ExtendedKeyInfo) -> Bool { + if lhs.mnemonic != rhs.mnemonic { + return false + } + if lhs.xprv != rhs.xprv { + return false + } + if lhs.fingerprint != rhs.fingerprint { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(mnemonic) + hasher.combine(xprv) + hasher.combine(fingerprint) + } +} + + +fileprivate extension ExtendedKeyInfo { + static func read(from buf: Reader) throws -> ExtendedKeyInfo { + return try ExtendedKeyInfo( + mnemonic: String.read(from: buf), + xprv: String.read(from: buf), + fingerprint: String.read(from: buf) + ) + } + + func write(into buf: Writer) { + self.mnemonic.write(into: buf) + self.xprv.write(into: buf) + self.fingerprint.write(into: buf) + } +} + +extension ExtendedKeyInfo: ViaFfiUsingByteBuffer, ViaFfi {} + public struct ElectrumConfig { public var url: String public var socks5: String? @@ -1650,61 +1782,6 @@ fileprivate extension EsploraConfig { extension EsploraConfig: ViaFfiUsingByteBuffer, ViaFfi {} -public struct ExtendedKeyInfo { - public var mnemonic: String - public var xprv: String - public var fingerprint: String - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(mnemonic: String, xprv: String, fingerprint: String ) { - self.mnemonic = mnemonic - self.xprv = xprv - self.fingerprint = fingerprint - } -} - - -extension ExtendedKeyInfo: Equatable, Hashable { - public static func ==(lhs: ExtendedKeyInfo, rhs: ExtendedKeyInfo) -> Bool { - if lhs.mnemonic != rhs.mnemonic { - return false - } - if lhs.xprv != rhs.xprv { - return false - } - if lhs.fingerprint != rhs.fingerprint { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(mnemonic) - hasher.combine(xprv) - hasher.combine(fingerprint) - } -} - - -fileprivate extension ExtendedKeyInfo { - static func read(from buf: Reader) throws -> ExtendedKeyInfo { - return try ExtendedKeyInfo( - mnemonic: String.read(from: buf), - xprv: String.read(from: buf), - fingerprint: String.read(from: buf) - ) - } - - func write(into buf: Writer) { - self.mnemonic.write(into: buf) - self.xprv.write(into: buf) - self.fingerprint.write(into: buf) - } -} - -extension ExtendedKeyInfo: ViaFfiUsingByteBuffer, ViaFfi {} - public enum BdkError { @@ -2192,7 +2269,7 @@ fileprivate let foreignCallbackCallbackInterfaceProgress : ForeignCallback = // The ffiConverter which transforms the Callbacks in to Handles to pass to Rust. private let ffiConverterCallbackInterfaceProgress: FfiConverterCallbackInterface = { try! rustCall { (err: UnsafeMutablePointer) in - ffi_bdk_360_Progress_init_callback(foreignCallbackCallbackInterfaceProgress, err) + ffi_bdk_1c1_Progress_init_callback(foreignCallbackCallbackInterfaceProgress, err) } return FfiConverterCallbackInterface() }() @@ -2232,6 +2309,25 @@ extension Float: Primitive, ViaFfi { buf.writeFloat(self.lower()) } } +extension Bool: ViaFfi { + fileprivate typealias FfiType = Int8 + + fileprivate static func read(from buf: Reader) throws -> Self { + return try self.lift(buf.readInt()) + } + + fileprivate func write(into buf: Writer) { + buf.writeInt(self.lower()) + } + + fileprivate static func lift(_ v: FfiType) throws -> Self { + return v != 0 + } + + fileprivate func lower() -> FfiType { + return self ? 1 : 0 + } +} extension String: ViaFfi { fileprivate typealias FfiType = RustBuffer @@ -2273,6 +2369,7 @@ extension String: ViaFfi { // Helper code for PartiallySignedBitcoinTransaction class is found in ObjectTemplate.swift // Helper code for TxBuilder class is found in ObjectTemplate.swift // Helper code for Wallet class is found in ObjectTemplate.swift +// Helper code for AddressInfo record is found in RecordTemplate.swift // Helper code for BlockTime record is found in RecordTemplate.swift // Helper code for ElectrumConfig record is found in RecordTemplate.swift // Helper code for EsploraConfig record is found in RecordTemplate.swift @@ -2280,6 +2377,7 @@ extension String: ViaFfi { // Helper code for SledDbConfiguration record is found in RecordTemplate.swift // Helper code for SqliteDbConfiguration record is found in RecordTemplate.swift // Helper code for TransactionDetails record is found in RecordTemplate.swift +// Helper code for AddressIndex enum is found in EnumTemplate.swift // Helper code for BlockchainConfig enum is found in EnumTemplate.swift // Helper code for DatabaseConfig enum is found in EnumTemplate.swift // Helper code for Network enum is found in EnumTemplate.swift diff --git a/Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift b/Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift index 76475a7..c25e25d 100644 --- a/Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift +++ b/Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift @@ -6,7 +6,7 @@ final class BitcoinDevKitTests: XCTestCase { let desc = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)" let databaseConfig = DatabaseConfig.memory let wallet = try Wallet.init(descriptor: desc, changeDescriptor: nil, network: Network.regtest, databaseConfig: databaseConfig) - let address = wallet.getNewAddress() - XCTAssertEqual(address, "bcrt1qzg4mckdh50nwdm9hkzq06528rsu73hjxytqkxs") + let addressInfo = try wallet.getAddress(addressIndex: AddressIndex.new) + XCTAssertEqual(addressInfo.address, "bcrt1qzg4mckdh50nwdm9hkzq06528rsu73hjxytqkxs") } } diff --git a/bdk-ffi b/bdk-ffi index 30e54ac..80ed21e 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit 30e54ac067f68e8c22d652837b4d5901c12e3384 +Subproject commit 80ed21e4c9e61d6224e074258229a4d6da6cc049 From 7ba5f3757db60de3db531f3dc1c77c9cee07a1d3 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Fri, 21 Oct 2022 17:18:30 -0500 Subject: [PATCH 22/33] Updated bdk-ffi to v0.10.0 (bdk 0.23) --- README.md | 15 +- Sources/BitcoinDevKit/BitcoinDevKit.swift | 4352 +++++++++++++-------- bdk-ffi | 2 +- 3 files changed, 2632 insertions(+), 1737 deletions(-) diff --git a/README.md b/README.md index f258b43..bfd258e 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,10 @@ code. For example: import BitcoinDevKit ... - let desc = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)" -let config = DatabaseConfig.memory(junk: "") -let wallet = try OfflineWallet.init(descriptor: desc, network: Network.regtest, databaseConfig: config) -let address = wallet.getNewAddress() +let databaseConfig = DatabaseConfig.memory +let wallet = try Wallet.init(descriptor: desc, changeDescriptor: nil, network: Network.regtest, databaseConfig: databaseConfig) +let addressInfo = try wallet.getAddress(addressIndex: AddressIndex.new) ``` ### Example Projects @@ -59,10 +58,10 @@ own Github repository use the following steps: `bdkFFI.xcframework.zip` file and new hash as shown at the end of the build.sh script. For example: ```swift - .binaryTarget( - name: "bdkFFI", - url: "https://github.com/bitcoindevkit/bdk-swift/releases/download/0.1.3/bdkFFI.xcframework.zip", - checksum: "c0b1e3ea09376b3f316d7d83575e1cd513fc4ad39ef8cf01120a3a1d7757fb97"), + .binaryTarget( + name: "bdkFFI", + url: "https://github.com/bitcoindevkit/bdk-swift/releases/download/0.1.3/bdkFFI.xcframework.zip", + checksum: "c0b1e3ea09376b3f316d7d83575e1cd513fc4ad39ef8cf01120a3a1d7757fb97"), ``` 1. Commit the changed `Package.swift` and tag it with the new version number. ```shell diff --git a/Sources/BitcoinDevKit/BitcoinDevKit.swift b/Sources/BitcoinDevKit/BitcoinDevKit.swift index 90a02f5..9ab21b7 100644 --- a/Sources/BitcoinDevKit/BitcoinDevKit.swift +++ b/Sources/BitcoinDevKit/BitcoinDevKit.swift @@ -19,13 +19,13 @@ fileprivate extension RustBuffer { } static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { - try! rustCall { ffi_bdk_1c1_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } + try! rustCall { ffi_bdk_1724_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } } // Frees the buffer in place. // The buffer must not be used after this is called. func deallocate() { - try! rustCall { ffi_bdk_1c1_rustbuffer_free(self, $0) } + try! rustCall { ffi_bdk_1724_rustbuffer_free(self, $0) } } } @@ -147,57 +147,50 @@ fileprivate class Writer { } } - -// Types conforming to `Serializable` can be read and written in a bytebuffer. -fileprivate protocol Serializable { - func write(into: Writer) - static func read(from: Reader) throws -> Self -} - -// Types confirming to `ViaFfi` can be transferred back-and-for over the FFI. -// This is analogous to the Rust trait of the same name. -fileprivate protocol ViaFfi: Serializable { +// Protocol for types that transfer other types across the FFI. This is +// analogous go the Rust trait of the same name. +fileprivate protocol FfiConverter { associatedtype FfiType - static func lift(_ v: FfiType) throws -> Self - func lower() -> FfiType + associatedtype SwiftType + + static func lift(_ value: FfiType) throws -> SwiftType + static func lower(_ value: SwiftType) -> FfiType + static func read(from buf: Reader) throws -> SwiftType + static func write(_ value: SwiftType, into buf: Writer) } // Types conforming to `Primitive` pass themselves directly over the FFI. -fileprivate protocol Primitive {} +fileprivate protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType { } -extension Primitive { - fileprivate typealias FfiType = Self - - fileprivate static func lift(_ v: Self) throws -> Self { - return v +extension FfiConverterPrimitive { + static func lift(_ value: FfiType) throws -> SwiftType { + return value } - fileprivate func lower() -> Self { - return self + static func lower(_ value: SwiftType) -> FfiType { + return value } } -// Types conforming to `ViaFfiUsingByteBuffer` lift and lower into a bytebuffer. -// Use this for complex types where it's hard to write a custom lift/lower. -fileprivate protocol ViaFfiUsingByteBuffer: Serializable {} +// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. +// Used for complex types where it's hard to write a custom lift/lower. +fileprivate protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} -extension ViaFfiUsingByteBuffer { - fileprivate typealias FfiType = RustBuffer - - fileprivate static func lift(_ buf: FfiType) throws -> Self { - let reader = Reader(data: Data(rustBuffer: buf)) - let value = try Self.read(from: reader) - if reader.hasRemaining() { - throw UniffiInternalError.incompleteData - } - buf.deallocate() - return value +extension FfiConverterRustBuffer { + static func lift(_ buf: RustBuffer) throws -> SwiftType { + let reader = Reader(data: Data(rustBuffer: buf)) + let value = try read(from: reader) + if reader.hasRemaining() { + throw UniffiInternalError.incompleteData + } + buf.deallocate() + return value } - fileprivate func lower() -> FfiType { - let writer = Writer() - self.write(into: writer) - return RustBuffer(bytes: writer.bytes) + static func lower(_ value: SwiftType) -> RustBuffer { + let writer = Writer() + write(value, into: writer) + return RustBuffer(bytes: writer.bytes) } } // An error type for FFI errors. These errors occur at the UniFFI level, not @@ -252,8 +245,11 @@ private func rustCall(_ callback: (UnsafeMutablePointer) -> T }) } -private func rustCallWithError(_ errorClass: E.Type, _ callback: (UnsafeMutablePointer) -> T) throws -> T { - try makeRustCall(callback, errorHandler: { return try E.lift($0) }) +private func rustCallWithError + (_ errorFfiConverter: F.Type, _ callback: (UnsafeMutablePointer) -> T) throws -> T + where F.SwiftType: Error, F.FfiType == RustBuffer + { + try makeRustCall(callback, errorHandler: { return try errorFfiConverter.lift($0) }) } private func makeRustCall(_ callback: (UnsafeMutablePointer) -> T, errorHandler: (RustBuffer) throws -> Error) throws -> T { @@ -271,7 +267,7 @@ private func makeRustCall(_ callback: (UnsafeMutablePointer) // with the message. But if that code panics, then it just sends back // an empty buffer. if callStatus.errorBuf.len > 0 { - throw UniffiInternalError.rustPanic(try String.lift(callStatus.errorBuf)) + throw UniffiInternalError.rustPanic(try FfiConverterString.lift(callStatus.errorBuf)) } else { callStatus.errorBuf.deallocate() throw UniffiInternalError.rustPanic("Rust panic") @@ -281,226 +277,1968 @@ private func makeRustCall(_ callback: (UnsafeMutablePointer) throw UniffiInternalError.unexpectedRustCallStatusCode } } -// Protocols for converters we'll implement in templates - -fileprivate protocol FfiConverter { - associatedtype SwiftType - associatedtype FfiType - - static func lift(_ ffiValue: FfiType) throws -> SwiftType - static func lower(_ value: SwiftType) -> FfiType - - static func read(from: Reader) throws -> SwiftType - static func write(_ value: SwiftType, into: Writer) -} - -fileprivate protocol FfiConverterUsingByteBuffer: FfiConverter where FfiType == RustBuffer { - // Empty, because we want to declare some helper methods in the extension below. -} - -extension FfiConverterUsingByteBuffer { - static func lower(_ value: SwiftType) -> FfiType { - let writer = Writer() - Self.write(value, into: writer) - return RustBuffer(bytes: writer.bytes) - } - - static func lift(_ buf: FfiType) throws -> SwiftType { - let reader = Reader(data: Data(rustBuffer: buf)) - let value = try Self.read(from: reader) - if reader.hasRemaining() { - throw UniffiInternalError.incompleteData - } - buf.deallocate() - return value - } -} - -// Helpers for structural types. Note that because of canonical_names, it /should/ be impossible -// to make another `FfiConverterSequence` etc just using the UDL. -fileprivate enum FfiConverterSequence { - static func write(_ value: [T], into buf: Writer, writeItem: (T, Writer) -> Void) { - let len = Int32(value.count) - buf.writeInt(len) - for item in value { - writeItem(item, buf) - } - } - - static func read(from buf: Reader, readItem: (Reader) throws -> T) throws -> [T] { - let len: Int32 = try buf.readInt() - var seq = [T]() - seq.reserveCapacity(Int(len)) - for _ in 0 ..< len { - seq.append(try readItem(buf)) - } - return seq - } -} - -fileprivate enum FfiConverterOptional { - static func write(_ value: T?, into buf: Writer, writeItem: (T, Writer) -> Void) { - guard let value = value else { - buf.writeInt(Int8(0)) - return - } - buf.writeInt(Int8(1)) - writeItem(value, buf) - } - - static func read(from buf: Reader, readItem: (Reader) throws -> T) throws -> T? { - switch try buf.readInt() as Int8 { - case 0: return nil - case 1: return try readItem(buf) - default: throw UniffiInternalError.unexpectedOptionalTag - } - } -} - -fileprivate enum FfiConverterDictionary { - static func write(_ value: [String: T], into buf: Writer, writeItem: (String, T, Writer) -> Void) { - let len = Int32(value.count) - buf.writeInt(len) - for (key, value) in value { - writeItem(key, value, buf) - } - } - - static func read(from buf: Reader, readItem: (Reader) throws -> (String, T)) throws -> [String: T] { - let len: Int32 = try buf.readInt() - var dict = [String: T]() - dict.reserveCapacity(Int(len)) - for _ in 0..(f: () throws -> T) rethrows -> T { - self.lock() - defer { self.unlock() } - return try f() +fileprivate struct FfiConverterUInt8: FfiConverterPrimitive { + typealias FfiType = UInt8 + typealias SwiftType = UInt8 + + static func read(from buf: Reader) throws -> UInt8 { + return try lift(buf.readInt()) + } + + static func write(_ value: UInt8, into buf: Writer) { + buf.writeInt(lower(value)) } } -fileprivate typealias Handle = UInt64 -fileprivate class ConcurrentHandleMap { - private var leftMap: [Handle: T] = [:] - private var counter: [Handle: UInt64] = [:] - private var rightMap: [ObjectIdentifier: Handle] = [:] +fileprivate struct FfiConverterUInt32: FfiConverterPrimitive { + typealias FfiType = UInt32 + typealias SwiftType = UInt32 - private let lock = NSLock() - private var currentHandle: Handle = 0 - private let stride: Handle = 1 + static func read(from buf: Reader) throws -> UInt32 { + return try lift(buf.readInt()) + } - func insert(obj: T) -> Handle { - lock.withLock { - let id = ObjectIdentifier(obj as AnyObject) - let handle = rightMap[id] ?? { - currentHandle += stride - let handle = currentHandle - leftMap[handle] = obj - rightMap[id] = handle - return handle - }() - counter[handle] = (counter[handle] ?? 0) + 1 - return handle + static func write(_ value: SwiftType, into buf: Writer) { + buf.writeInt(lower(value)) + } +} + +fileprivate struct FfiConverterUInt64: FfiConverterPrimitive { + typealias FfiType = UInt64 + typealias SwiftType = UInt64 + + static func read(from buf: Reader) throws -> UInt64 { + return try lift(buf.readInt()) + } + + static func write(_ value: SwiftType, into buf: Writer) { + buf.writeInt(lower(value)) + } +} + +fileprivate struct FfiConverterFloat: FfiConverterPrimitive { + typealias FfiType = Float + typealias SwiftType = Float + + static func read(from buf: Reader) throws -> Float { + return try lift(buf.readFloat()) + } + + static func write(_ value: Float, into buf: Writer) { + buf.writeFloat(lower(value)) + } +} + +fileprivate struct FfiConverterBool : FfiConverter { + typealias FfiType = Int8 + typealias SwiftType = Bool + + static func lift(_ value: Int8) throws -> Bool { + return value != 0 + } + + static func lower(_ value: Bool) -> Int8 { + return value ? 1 : 0 + } + + static func read(from buf: Reader) throws -> Bool { + return try lift(buf.readInt()) + } + + static func write(_ value: Bool, into buf: Writer) { + buf.writeInt(lower(value)) + } +} + +fileprivate struct FfiConverterString: FfiConverter { + typealias SwiftType = String + typealias FfiType = RustBuffer + + static func lift(_ value: RustBuffer) throws -> String { + defer { + value.deallocate() } - } - - func get(handle: Handle) -> T? { - lock.withLock { - leftMap[handle] + if value.data == nil { + return String() } + let bytes = UnsafeBufferPointer(start: value.data!, count: Int(value.len)) + return String(bytes: bytes, encoding: String.Encoding.utf8)! } - func delete(handle: Handle) { - remove(handle: handle) - } - - @discardableResult - func remove(handle: Handle) -> T? { - lock.withLock { - defer { counter[handle] = (counter[handle] ?? 1) - 1 } - guard counter[handle] == 1 else { return leftMap[handle] } - let obj = leftMap.removeValue(forKey: handle) - if let obj = obj { - rightMap.removeValue(forKey: ObjectIdentifier(obj as AnyObject)) + static func lower(_ value: String) -> RustBuffer { + return value.utf8CString.withUnsafeBufferPointer { ptr in + // The swift string gives us int8_t, we want uint8_t. + ptr.withMemoryRebound(to: UInt8.self) { ptr in + // The swift string gives us a trailing null byte, we don't want it. + let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) + return RustBuffer.from(buf) } - return obj } } + + static func read(from buf: Reader) throws -> String { + let len: Int32 = try buf.readInt() + return String(bytes: try buf.readBytes(count: Int(len)), encoding: String.Encoding.utf8)! + } + + static func write(_ value: String, into buf: Writer) { + let len = Int32(value.utf8.count) + buf.writeInt(len) + buf.writeBytes(value.utf8) + } } -// 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 -fileprivate class FfiConverterCallbackInterface { - fileprivate let handleMap = ConcurrentHandleMap() +public protocol AddressProtocol { + func `scriptPubkey`() -> Script + +} - func drop(handle: Handle) { - handleMap.remove(handle: handle) +public class Address: AddressProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(`address`: String) throws { + self.init(unsafeFromRawPointer: try + + rustCallWithError(FfiConverterTypeBdkError.self) { + + bdk_1724_Address_new( + FfiConverterString.lower(`address`), $0) +}) } - func lift(_ handle: Handle) throws -> CallbackInterface { - guard let callback = handleMap.get(handle: handle) else { - throw UniffiInternalError.unexpectedStaleHandle + deinit { + try! rustCall { ffi_bdk_1724_Address_object_free(pointer, $0) } + } + + + + + public func `scriptPubkey`() -> Script { + return try! FfiConverterTypeScript.lift( + try! + rustCall() { + + bdk_1724_Address_script_pubkey(self.pointer, $0 + ) +} + ) + } + +} + + +fileprivate struct FfiConverterTypeAddress: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = Address + + static func read(from buf: Reader) throws -> Address { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer } - return callback + return try lift(ptr!) } - func read(from buf: Reader) throws -> CallbackInterface { - let handle: Handle = try buf.readInt() - return try lift(handle) + static func write(_ value: Address, into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) } - func lower(_ v: CallbackInterface) -> Handle { - let handle = handleMap.insert(obj: v) - return handle - // assert(handleMap.get(handle: obj) == v, "Handle map is not returning the object we just placed there. This is a bug in the HandleMap.") + static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Address { + return Address(unsafeFromRawPointer: pointer) } - func write(_ v: CallbackInterface, into buf: Writer) { - buf.writeInt(lower(v)) + static func lower(_ value: Address) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public protocol BlockchainProtocol { + func `broadcast`(`psbt`: PartiallySignedBitcoinTransaction) throws + func `getHeight`() throws -> UInt32 + func `getBlockHash`(`height`: UInt32) throws -> String + +} + +public class Blockchain: BlockchainProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(`config`: BlockchainConfig) throws { + self.init(unsafeFromRawPointer: try + + rustCallWithError(FfiConverterTypeBdkError.self) { + + bdk_1724_Blockchain_new( + FfiConverterTypeBlockchainConfig.lower(`config`), $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_1724_Blockchain_object_free(pointer, $0) } + } + + + + + public func `broadcast`(`psbt`: PartiallySignedBitcoinTransaction) throws { + try + rustCallWithError(FfiConverterTypeBdkError.self) { + bdk_1724_Blockchain_broadcast(self.pointer, + FfiConverterTypePartiallySignedBitcoinTransaction.lower(`psbt`), $0 + ) +} + } + public func `getHeight`() throws -> UInt32 { + return try FfiConverterUInt32.lift( + try + rustCallWithError(FfiConverterTypeBdkError.self) { + bdk_1724_Blockchain_get_height(self.pointer, $0 + ) +} + ) + } + public func `getBlockHash`(`height`: UInt32) throws -> String { + return try FfiConverterString.lift( + try + rustCallWithError(FfiConverterTypeBdkError.self) { + bdk_1724_Blockchain_get_block_hash(self.pointer, + FfiConverterUInt32.lower(`height`), $0 + ) +} + ) + } + +} + + +fileprivate struct FfiConverterTypeBlockchain: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = Blockchain + + static func read(from buf: Reader) throws -> Blockchain { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + static func write(_ value: Blockchain, into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Blockchain { + return Blockchain(unsafeFromRawPointer: pointer) + } + + static func lower(_ value: Blockchain) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public protocol BumpFeeTxBuilderProtocol { + func `allowShrinking`(`address`: String) -> BumpFeeTxBuilder + func `enableRbf`() -> BumpFeeTxBuilder + func `enableRbfWithSequence`(`nsequence`: UInt32) -> BumpFeeTxBuilder + func `finish`(`wallet`: Wallet) throws -> PartiallySignedBitcoinTransaction + +} + +public class BumpFeeTxBuilder: BumpFeeTxBuilderProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(`txid`: String, `newFeeRate`: Float) { + self.init(unsafeFromRawPointer: try! + + rustCall() { + + bdk_1724_BumpFeeTxBuilder_new( + FfiConverterString.lower(`txid`), + FfiConverterFloat.lower(`newFeeRate`), $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_1724_BumpFeeTxBuilder_object_free(pointer, $0) } + } + + + + + public func `allowShrinking`(`address`: String) -> BumpFeeTxBuilder { + return try! FfiConverterTypeBumpFeeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_BumpFeeTxBuilder_allow_shrinking(self.pointer, + FfiConverterString.lower(`address`), $0 + ) +} + ) + } + public func `enableRbf`() -> BumpFeeTxBuilder { + return try! FfiConverterTypeBumpFeeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_BumpFeeTxBuilder_enable_rbf(self.pointer, $0 + ) +} + ) + } + public func `enableRbfWithSequence`(`nsequence`: UInt32) -> BumpFeeTxBuilder { + return try! FfiConverterTypeBumpFeeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_BumpFeeTxBuilder_enable_rbf_with_sequence(self.pointer, + FfiConverterUInt32.lower(`nsequence`), $0 + ) +} + ) + } + public func `finish`(`wallet`: Wallet) throws -> PartiallySignedBitcoinTransaction { + return try FfiConverterTypePartiallySignedBitcoinTransaction.lift( + try + rustCallWithError(FfiConverterTypeBdkError.self) { + bdk_1724_BumpFeeTxBuilder_finish(self.pointer, + FfiConverterTypeWallet.lower(`wallet`), $0 + ) +} + ) + } + +} + + +fileprivate struct FfiConverterTypeBumpFeeTxBuilder: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = BumpFeeTxBuilder + + static func read(from buf: Reader) throws -> BumpFeeTxBuilder { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + static func write(_ value: BumpFeeTxBuilder, into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + static func lift(_ pointer: UnsafeMutableRawPointer) throws -> BumpFeeTxBuilder { + return BumpFeeTxBuilder(unsafeFromRawPointer: pointer) + } + + static func lower(_ value: BumpFeeTxBuilder) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public protocol DerivationPathProtocol { + +} + +public class DerivationPath: DerivationPathProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(`path`: String) throws { + self.init(unsafeFromRawPointer: try + + rustCallWithError(FfiConverterTypeBdkError.self) { + + bdk_1724_DerivationPath_new( + FfiConverterString.lower(`path`), $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_1724_DerivationPath_object_free(pointer, $0) } + } + + + + + +} + + +fileprivate struct FfiConverterTypeDerivationPath: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = DerivationPath + + static func read(from buf: Reader) throws -> DerivationPath { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + static func write(_ value: DerivationPath, into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + static func lift(_ pointer: UnsafeMutableRawPointer) throws -> DerivationPath { + return DerivationPath(unsafeFromRawPointer: pointer) + } + + static func lower(_ value: DerivationPath) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public protocol DescriptorPublicKeyProtocol { + func `derive`(`path`: DerivationPath) throws -> DescriptorPublicKey + func `extend`(`path`: DerivationPath) -> DescriptorPublicKey + func `asString`() -> String + +} + +public class DescriptorPublicKey: DescriptorPublicKeyProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + deinit { + try! rustCall { ffi_bdk_1724_DescriptorPublicKey_object_free(pointer, $0) } + } + + + + + public func `derive`(`path`: DerivationPath) throws -> DescriptorPublicKey { + return try FfiConverterTypeDescriptorPublicKey.lift( + try + rustCallWithError(FfiConverterTypeBdkError.self) { + bdk_1724_DescriptorPublicKey_derive(self.pointer, + FfiConverterTypeDerivationPath.lower(`path`), $0 + ) +} + ) + } + public func `extend`(`path`: DerivationPath) -> DescriptorPublicKey { + return try! FfiConverterTypeDescriptorPublicKey.lift( + try! + rustCall() { + + bdk_1724_DescriptorPublicKey_extend(self.pointer, + FfiConverterTypeDerivationPath.lower(`path`), $0 + ) +} + ) + } + public func `asString`() -> String { + return try! FfiConverterString.lift( + try! + rustCall() { + + bdk_1724_DescriptorPublicKey_as_string(self.pointer, $0 + ) +} + ) + } + +} + + +fileprivate struct FfiConverterTypeDescriptorPublicKey: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = DescriptorPublicKey + + static func read(from buf: Reader) throws -> DescriptorPublicKey { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + static func write(_ value: DescriptorPublicKey, into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + static func lift(_ pointer: UnsafeMutableRawPointer) throws -> DescriptorPublicKey { + return DescriptorPublicKey(unsafeFromRawPointer: pointer) + } + + static func lower(_ value: DescriptorPublicKey) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public protocol DescriptorSecretKeyProtocol { + func `derive`(`path`: DerivationPath) throws -> DescriptorSecretKey + func `extend`(`path`: DerivationPath) -> DescriptorSecretKey + func `asPublic`() -> DescriptorPublicKey + func `secretBytes`() -> [UInt8] + func `asString`() -> String + +} + +public class DescriptorSecretKey: DescriptorSecretKeyProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(`network`: Network, `mnemonic`: String, `password`: String?) throws { + self.init(unsafeFromRawPointer: try + + rustCallWithError(FfiConverterTypeBdkError.self) { + + bdk_1724_DescriptorSecretKey_new( + FfiConverterTypeNetwork.lower(`network`), + FfiConverterString.lower(`mnemonic`), + FfiConverterOptionString.lower(`password`), $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_1724_DescriptorSecretKey_object_free(pointer, $0) } + } + + + + + public func `derive`(`path`: DerivationPath) throws -> DescriptorSecretKey { + return try FfiConverterTypeDescriptorSecretKey.lift( + try + rustCallWithError(FfiConverterTypeBdkError.self) { + bdk_1724_DescriptorSecretKey_derive(self.pointer, + FfiConverterTypeDerivationPath.lower(`path`), $0 + ) +} + ) + } + public func `extend`(`path`: DerivationPath) -> DescriptorSecretKey { + return try! FfiConverterTypeDescriptorSecretKey.lift( + try! + rustCall() { + + bdk_1724_DescriptorSecretKey_extend(self.pointer, + FfiConverterTypeDerivationPath.lower(`path`), $0 + ) +} + ) + } + public func `asPublic`() -> DescriptorPublicKey { + return try! FfiConverterTypeDescriptorPublicKey.lift( + try! + rustCall() { + + bdk_1724_DescriptorSecretKey_as_public(self.pointer, $0 + ) +} + ) + } + public func `secretBytes`() -> [UInt8] { + return try! FfiConverterSequenceUInt8.lift( + try! + rustCall() { + + bdk_1724_DescriptorSecretKey_secret_bytes(self.pointer, $0 + ) +} + ) + } + public func `asString`() -> String { + return try! FfiConverterString.lift( + try! + rustCall() { + + bdk_1724_DescriptorSecretKey_as_string(self.pointer, $0 + ) +} + ) + } + +} + + +fileprivate struct FfiConverterTypeDescriptorSecretKey: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = DescriptorSecretKey + + static func read(from buf: Reader) throws -> DescriptorSecretKey { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + static func write(_ value: DescriptorSecretKey, into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + static func lift(_ pointer: UnsafeMutableRawPointer) throws -> DescriptorSecretKey { + return DescriptorSecretKey(unsafeFromRawPointer: pointer) + } + + static func lower(_ value: DescriptorSecretKey) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public protocol PartiallySignedBitcoinTransactionProtocol { + func `serialize`() -> String + func `txid`() -> String + func `extractTx`() -> [UInt8] + func `combine`(`other`: PartiallySignedBitcoinTransaction) throws -> PartiallySignedBitcoinTransaction + +} + +public class PartiallySignedBitcoinTransaction: PartiallySignedBitcoinTransactionProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(`psbtBase64`: String) throws { + self.init(unsafeFromRawPointer: try + + rustCallWithError(FfiConverterTypeBdkError.self) { + + bdk_1724_PartiallySignedBitcoinTransaction_new( + FfiConverterString.lower(`psbtBase64`), $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_1724_PartiallySignedBitcoinTransaction_object_free(pointer, $0) } + } + + + + + public func `serialize`() -> String { + return try! FfiConverterString.lift( + try! + rustCall() { + + bdk_1724_PartiallySignedBitcoinTransaction_serialize(self.pointer, $0 + ) +} + ) + } + public func `txid`() -> String { + return try! FfiConverterString.lift( + try! + rustCall() { + + bdk_1724_PartiallySignedBitcoinTransaction_txid(self.pointer, $0 + ) +} + ) + } + public func `extractTx`() -> [UInt8] { + return try! FfiConverterSequenceUInt8.lift( + try! + rustCall() { + + bdk_1724_PartiallySignedBitcoinTransaction_extract_tx(self.pointer, $0 + ) +} + ) + } + public func `combine`(`other`: PartiallySignedBitcoinTransaction) throws -> PartiallySignedBitcoinTransaction { + return try FfiConverterTypePartiallySignedBitcoinTransaction.lift( + try + rustCallWithError(FfiConverterTypeBdkError.self) { + bdk_1724_PartiallySignedBitcoinTransaction_combine(self.pointer, + FfiConverterTypePartiallySignedBitcoinTransaction.lower(`other`), $0 + ) +} + ) + } + +} + + +fileprivate struct FfiConverterTypePartiallySignedBitcoinTransaction: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = PartiallySignedBitcoinTransaction + + static func read(from buf: Reader) throws -> PartiallySignedBitcoinTransaction { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + static func write(_ value: PartiallySignedBitcoinTransaction, into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + static func lift(_ pointer: UnsafeMutableRawPointer) throws -> PartiallySignedBitcoinTransaction { + return PartiallySignedBitcoinTransaction(unsafeFromRawPointer: pointer) + } + + static func lower(_ value: PartiallySignedBitcoinTransaction) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public protocol ScriptProtocol { + +} + +public class Script: ScriptProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(`rawOutputScript`: [UInt8]) { + self.init(unsafeFromRawPointer: try! + + rustCall() { + + bdk_1724_Script_new( + FfiConverterSequenceUInt8.lower(`rawOutputScript`), $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_1724_Script_object_free(pointer, $0) } + } + + + + + +} + + +fileprivate struct FfiConverterTypeScript: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = Script + + static func read(from buf: Reader) throws -> Script { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + static func write(_ value: Script, into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Script { + return Script(unsafeFromRawPointer: pointer) + } + + static func lower(_ value: Script) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public protocol TxBuilderProtocol { + func `addRecipient`(`script`: Script, `amount`: UInt64) -> TxBuilder + func `addUnspendable`(`unspendable`: OutPoint) -> TxBuilder + func `addUtxo`(`outpoint`: OutPoint) -> TxBuilder + func `addUtxos`(`outpoints`: [OutPoint]) -> TxBuilder + func `doNotSpendChange`() -> TxBuilder + func `manuallySelectedOnly`() -> TxBuilder + func `onlySpendChange`() -> TxBuilder + func `unspendable`(`unspendable`: [OutPoint]) -> TxBuilder + func `feeRate`(`satPerVbyte`: Float) -> TxBuilder + func `feeAbsolute`(`feeAmount`: UInt64) -> TxBuilder + func `drainWallet`() -> TxBuilder + func `drainTo`(`address`: String) -> TxBuilder + func `enableRbf`() -> TxBuilder + func `enableRbfWithSequence`(`nsequence`: UInt32) -> TxBuilder + func `addData`(`data`: [UInt8]) -> TxBuilder + func `setRecipients`(`recipients`: [ScriptAmount]) -> TxBuilder + func `finish`(`wallet`: Wallet) throws -> TxBuilderResult + +} + +public class TxBuilder: TxBuilderProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init() { + self.init(unsafeFromRawPointer: try! + + rustCall() { + + bdk_1724_TxBuilder_new($0) +}) + } + + deinit { + try! rustCall { ffi_bdk_1724_TxBuilder_object_free(pointer, $0) } + } + + + + + public func `addRecipient`(`script`: Script, `amount`: UInt64) -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_add_recipient(self.pointer, + FfiConverterTypeScript.lower(`script`), + FfiConverterUInt64.lower(`amount`), $0 + ) +} + ) + } + public func `addUnspendable`(`unspendable`: OutPoint) -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_add_unspendable(self.pointer, + FfiConverterTypeOutPoint.lower(`unspendable`), $0 + ) +} + ) + } + public func `addUtxo`(`outpoint`: OutPoint) -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_add_utxo(self.pointer, + FfiConverterTypeOutPoint.lower(`outpoint`), $0 + ) +} + ) + } + public func `addUtxos`(`outpoints`: [OutPoint]) -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_add_utxos(self.pointer, + FfiConverterSequenceTypeOutPoint.lower(`outpoints`), $0 + ) +} + ) + } + public func `doNotSpendChange`() -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_do_not_spend_change(self.pointer, $0 + ) +} + ) + } + public func `manuallySelectedOnly`() -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_manually_selected_only(self.pointer, $0 + ) +} + ) + } + public func `onlySpendChange`() -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_only_spend_change(self.pointer, $0 + ) +} + ) + } + public func `unspendable`(`unspendable`: [OutPoint]) -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_unspendable(self.pointer, + FfiConverterSequenceTypeOutPoint.lower(`unspendable`), $0 + ) +} + ) + } + public func `feeRate`(`satPerVbyte`: Float) -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_fee_rate(self.pointer, + FfiConverterFloat.lower(`satPerVbyte`), $0 + ) +} + ) + } + public func `feeAbsolute`(`feeAmount`: UInt64) -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_fee_absolute(self.pointer, + FfiConverterUInt64.lower(`feeAmount`), $0 + ) +} + ) + } + public func `drainWallet`() -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_drain_wallet(self.pointer, $0 + ) +} + ) + } + public func `drainTo`(`address`: String) -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_drain_to(self.pointer, + FfiConverterString.lower(`address`), $0 + ) +} + ) + } + public func `enableRbf`() -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_enable_rbf(self.pointer, $0 + ) +} + ) + } + public func `enableRbfWithSequence`(`nsequence`: UInt32) -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_enable_rbf_with_sequence(self.pointer, + FfiConverterUInt32.lower(`nsequence`), $0 + ) +} + ) + } + public func `addData`(`data`: [UInt8]) -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_add_data(self.pointer, + FfiConverterSequenceUInt8.lower(`data`), $0 + ) +} + ) + } + public func `setRecipients`(`recipients`: [ScriptAmount]) -> TxBuilder { + return try! FfiConverterTypeTxBuilder.lift( + try! + rustCall() { + + bdk_1724_TxBuilder_set_recipients(self.pointer, + FfiConverterSequenceTypeScriptAmount.lower(`recipients`), $0 + ) +} + ) + } + public func `finish`(`wallet`: Wallet) throws -> TxBuilderResult { + return try FfiConverterTypeTxBuilderResult.lift( + try + rustCallWithError(FfiConverterTypeBdkError.self) { + bdk_1724_TxBuilder_finish(self.pointer, + FfiConverterTypeWallet.lower(`wallet`), $0 + ) +} + ) + } + +} + + +fileprivate struct FfiConverterTypeTxBuilder: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = TxBuilder + + static func read(from buf: Reader) throws -> TxBuilder { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + static func write(_ value: TxBuilder, into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + static func lift(_ pointer: UnsafeMutableRawPointer) throws -> TxBuilder { + return TxBuilder(unsafeFromRawPointer: pointer) + } + + static func lower(_ value: TxBuilder) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public protocol WalletProtocol { + func `getAddress`(`addressIndex`: AddressIndex) throws -> AddressInfo + func `getBalance`() throws -> Balance + func `sign`(`psbt`: PartiallySignedBitcoinTransaction) throws -> Bool + func `listTransactions`() throws -> [TransactionDetails] + func `network`() -> Network + func `sync`(`blockchain`: Blockchain, `progress`: Progress?) throws + func `listUnspent`() throws -> [LocalUtxo] + +} + +public class Wallet: WalletProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(`descriptor`: String, `changeDescriptor`: String?, `network`: Network, `databaseConfig`: DatabaseConfig) throws { + self.init(unsafeFromRawPointer: try + + rustCallWithError(FfiConverterTypeBdkError.self) { + + bdk_1724_Wallet_new( + FfiConverterString.lower(`descriptor`), + FfiConverterOptionString.lower(`changeDescriptor`), + FfiConverterTypeNetwork.lower(`network`), + FfiConverterTypeDatabaseConfig.lower(`databaseConfig`), $0) +}) + } + + deinit { + try! rustCall { ffi_bdk_1724_Wallet_object_free(pointer, $0) } + } + + + + + public func `getAddress`(`addressIndex`: AddressIndex) throws -> AddressInfo { + return try FfiConverterTypeAddressInfo.lift( + try + rustCallWithError(FfiConverterTypeBdkError.self) { + bdk_1724_Wallet_get_address(self.pointer, + FfiConverterTypeAddressIndex.lower(`addressIndex`), $0 + ) +} + ) + } + public func `getBalance`() throws -> Balance { + return try FfiConverterTypeBalance.lift( + try + rustCallWithError(FfiConverterTypeBdkError.self) { + bdk_1724_Wallet_get_balance(self.pointer, $0 + ) +} + ) + } + public func `sign`(`psbt`: PartiallySignedBitcoinTransaction) throws -> Bool { + return try FfiConverterBool.lift( + try + rustCallWithError(FfiConverterTypeBdkError.self) { + bdk_1724_Wallet_sign(self.pointer, + FfiConverterTypePartiallySignedBitcoinTransaction.lower(`psbt`), $0 + ) +} + ) + } + public func `listTransactions`() throws -> [TransactionDetails] { + return try FfiConverterSequenceTypeTransactionDetails.lift( + try + rustCallWithError(FfiConverterTypeBdkError.self) { + bdk_1724_Wallet_list_transactions(self.pointer, $0 + ) +} + ) + } + public func `network`() -> Network { + return try! FfiConverterTypeNetwork.lift( + try! + rustCall() { + + bdk_1724_Wallet_network(self.pointer, $0 + ) +} + ) + } + public func `sync`(`blockchain`: Blockchain, `progress`: Progress?) throws { + try + rustCallWithError(FfiConverterTypeBdkError.self) { + bdk_1724_Wallet_sync(self.pointer, + FfiConverterTypeBlockchain.lower(`blockchain`), + FfiConverterOptionCallbackInterfaceProgress.lower(`progress`), $0 + ) +} + } + public func `listUnspent`() throws -> [LocalUtxo] { + return try FfiConverterSequenceTypeLocalUtxo.lift( + try + rustCallWithError(FfiConverterTypeBdkError.self) { + bdk_1724_Wallet_list_unspent(self.pointer, $0 + ) +} + ) + } + +} + + +fileprivate struct FfiConverterTypeWallet: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = Wallet + + static func read(from buf: Reader) throws -> Wallet { + let v: UInt64 = try buf.readInt() + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + static func write(_ value: Wallet, into buf: Writer) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Wallet { + return Wallet(unsafeFromRawPointer: pointer) + } + + static func lower(_ value: Wallet) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public struct AddressInfo { + public var `index`: UInt32 + public var `address`: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(`index`: UInt32, `address`: String) { + self.`index` = `index` + self.`address` = `address` + } +} + + +extension AddressInfo: Equatable, Hashable { + public static func ==(lhs: AddressInfo, rhs: AddressInfo) -> Bool { + if lhs.`index` != rhs.`index` { + return false + } + if lhs.`address` != rhs.`address` { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(`index`) + hasher.combine(`address`) + } +} + + +fileprivate struct FfiConverterTypeAddressInfo: FfiConverterRustBuffer { + fileprivate static func read(from buf: Reader) throws -> AddressInfo { + return try AddressInfo( + `index`: FfiConverterUInt32.read(from: buf), + `address`: FfiConverterString.read(from: buf) + ) + } + + fileprivate static func write(_ value: AddressInfo, into buf: Writer) { + FfiConverterUInt32.write(value.`index`, into: buf) + FfiConverterString.write(value.`address`, into: buf) + } +} + + +public struct Balance { + public var `immature`: UInt64 + public var `trustedPending`: UInt64 + public var `untrustedPending`: UInt64 + public var `confirmed`: UInt64 + public var `spendable`: UInt64 + public var `total`: UInt64 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(`immature`: UInt64, `trustedPending`: UInt64, `untrustedPending`: UInt64, `confirmed`: UInt64, `spendable`: UInt64, `total`: UInt64) { + self.`immature` = `immature` + self.`trustedPending` = `trustedPending` + self.`untrustedPending` = `untrustedPending` + self.`confirmed` = `confirmed` + self.`spendable` = `spendable` + self.`total` = `total` + } +} + + +extension Balance: Equatable, Hashable { + public static func ==(lhs: Balance, rhs: Balance) -> Bool { + if lhs.`immature` != rhs.`immature` { + return false + } + if lhs.`trustedPending` != rhs.`trustedPending` { + return false + } + if lhs.`untrustedPending` != rhs.`untrustedPending` { + return false + } + if lhs.`confirmed` != rhs.`confirmed` { + return false + } + if lhs.`spendable` != rhs.`spendable` { + return false + } + if lhs.`total` != rhs.`total` { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(`immature`) + hasher.combine(`trustedPending`) + hasher.combine(`untrustedPending`) + hasher.combine(`confirmed`) + hasher.combine(`spendable`) + hasher.combine(`total`) + } +} + + +fileprivate struct FfiConverterTypeBalance: FfiConverterRustBuffer { + fileprivate static func read(from buf: Reader) throws -> Balance { + return try Balance( + `immature`: FfiConverterUInt64.read(from: buf), + `trustedPending`: FfiConverterUInt64.read(from: buf), + `untrustedPending`: FfiConverterUInt64.read(from: buf), + `confirmed`: FfiConverterUInt64.read(from: buf), + `spendable`: FfiConverterUInt64.read(from: buf), + `total`: FfiConverterUInt64.read(from: buf) + ) + } + + fileprivate static func write(_ value: Balance, into buf: Writer) { + FfiConverterUInt64.write(value.`immature`, into: buf) + FfiConverterUInt64.write(value.`trustedPending`, into: buf) + FfiConverterUInt64.write(value.`untrustedPending`, into: buf) + FfiConverterUInt64.write(value.`confirmed`, into: buf) + FfiConverterUInt64.write(value.`spendable`, into: buf) + FfiConverterUInt64.write(value.`total`, into: buf) + } +} + + +public struct BlockTime { + public var `height`: UInt32 + public var `timestamp`: UInt64 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(`height`: UInt32, `timestamp`: UInt64) { + self.`height` = `height` + self.`timestamp` = `timestamp` + } +} + + +extension BlockTime: Equatable, Hashable { + public static func ==(lhs: BlockTime, rhs: BlockTime) -> Bool { + if lhs.`height` != rhs.`height` { + return false + } + if lhs.`timestamp` != rhs.`timestamp` { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(`height`) + hasher.combine(`timestamp`) + } +} + + +fileprivate struct FfiConverterTypeBlockTime: FfiConverterRustBuffer { + fileprivate static func read(from buf: Reader) throws -> BlockTime { + return try BlockTime( + `height`: FfiConverterUInt32.read(from: buf), + `timestamp`: FfiConverterUInt64.read(from: buf) + ) + } + + fileprivate static func write(_ value: BlockTime, into buf: Writer) { + FfiConverterUInt32.write(value.`height`, into: buf) + FfiConverterUInt64.write(value.`timestamp`, into: buf) + } +} + + +public struct ElectrumConfig { + public var `url`: String + public var `socks5`: String? + public var `retry`: UInt8 + public var `timeout`: UInt8? + public var `stopGap`: UInt64 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(`url`: String, `socks5`: String?, `retry`: UInt8, `timeout`: UInt8?, `stopGap`: UInt64) { + self.`url` = `url` + self.`socks5` = `socks5` + self.`retry` = `retry` + self.`timeout` = `timeout` + self.`stopGap` = `stopGap` + } +} + + +extension ElectrumConfig: Equatable, Hashable { + public static func ==(lhs: ElectrumConfig, rhs: ElectrumConfig) -> Bool { + if lhs.`url` != rhs.`url` { + return false + } + if lhs.`socks5` != rhs.`socks5` { + return false + } + if lhs.`retry` != rhs.`retry` { + return false + } + if lhs.`timeout` != rhs.`timeout` { + return false + } + if lhs.`stopGap` != rhs.`stopGap` { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(`url`) + hasher.combine(`socks5`) + hasher.combine(`retry`) + hasher.combine(`timeout`) + hasher.combine(`stopGap`) + } +} + + +fileprivate struct FfiConverterTypeElectrumConfig: FfiConverterRustBuffer { + fileprivate static func read(from buf: Reader) throws -> ElectrumConfig { + return try ElectrumConfig( + `url`: FfiConverterString.read(from: buf), + `socks5`: FfiConverterOptionString.read(from: buf), + `retry`: FfiConverterUInt8.read(from: buf), + `timeout`: FfiConverterOptionUInt8.read(from: buf), + `stopGap`: FfiConverterUInt64.read(from: buf) + ) + } + + fileprivate static func write(_ value: ElectrumConfig, into buf: Writer) { + FfiConverterString.write(value.`url`, into: buf) + FfiConverterOptionString.write(value.`socks5`, into: buf) + FfiConverterUInt8.write(value.`retry`, into: buf) + FfiConverterOptionUInt8.write(value.`timeout`, into: buf) + FfiConverterUInt64.write(value.`stopGap`, into: buf) + } +} + + +public struct EsploraConfig { + public var `baseUrl`: String + public var `proxy`: String? + public var `concurrency`: UInt8? + public var `stopGap`: UInt64 + public var `timeout`: UInt64? + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(`baseUrl`: String, `proxy`: String?, `concurrency`: UInt8?, `stopGap`: UInt64, `timeout`: UInt64?) { + self.`baseUrl` = `baseUrl` + self.`proxy` = `proxy` + self.`concurrency` = `concurrency` + self.`stopGap` = `stopGap` + self.`timeout` = `timeout` + } +} + + +extension EsploraConfig: Equatable, Hashable { + public static func ==(lhs: EsploraConfig, rhs: EsploraConfig) -> Bool { + if lhs.`baseUrl` != rhs.`baseUrl` { + return false + } + if lhs.`proxy` != rhs.`proxy` { + return false + } + if lhs.`concurrency` != rhs.`concurrency` { + return false + } + if lhs.`stopGap` != rhs.`stopGap` { + return false + } + if lhs.`timeout` != rhs.`timeout` { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(`baseUrl`) + hasher.combine(`proxy`) + hasher.combine(`concurrency`) + hasher.combine(`stopGap`) + hasher.combine(`timeout`) + } +} + + +fileprivate struct FfiConverterTypeEsploraConfig: FfiConverterRustBuffer { + fileprivate static func read(from buf: Reader) throws -> EsploraConfig { + return try EsploraConfig( + `baseUrl`: FfiConverterString.read(from: buf), + `proxy`: FfiConverterOptionString.read(from: buf), + `concurrency`: FfiConverterOptionUInt8.read(from: buf), + `stopGap`: FfiConverterUInt64.read(from: buf), + `timeout`: FfiConverterOptionUInt64.read(from: buf) + ) + } + + fileprivate static func write(_ value: EsploraConfig, into buf: Writer) { + FfiConverterString.write(value.`baseUrl`, into: buf) + FfiConverterOptionString.write(value.`proxy`, into: buf) + FfiConverterOptionUInt8.write(value.`concurrency`, into: buf) + FfiConverterUInt64.write(value.`stopGap`, into: buf) + FfiConverterOptionUInt64.write(value.`timeout`, into: buf) + } +} + + +public struct LocalUtxo { + public var `outpoint`: OutPoint + public var `txout`: TxOut + public var `keychain`: KeychainKind + public var `isSpent`: Bool + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(`outpoint`: OutPoint, `txout`: TxOut, `keychain`: KeychainKind, `isSpent`: Bool) { + self.`outpoint` = `outpoint` + self.`txout` = `txout` + self.`keychain` = `keychain` + self.`isSpent` = `isSpent` + } +} + + +extension LocalUtxo: Equatable, Hashable { + public static func ==(lhs: LocalUtxo, rhs: LocalUtxo) -> Bool { + if lhs.`outpoint` != rhs.`outpoint` { + return false + } + if lhs.`txout` != rhs.`txout` { + return false + } + if lhs.`keychain` != rhs.`keychain` { + return false + } + if lhs.`isSpent` != rhs.`isSpent` { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(`outpoint`) + hasher.combine(`txout`) + hasher.combine(`keychain`) + hasher.combine(`isSpent`) + } +} + + +fileprivate struct FfiConverterTypeLocalUtxo: FfiConverterRustBuffer { + fileprivate static func read(from buf: Reader) throws -> LocalUtxo { + return try LocalUtxo( + `outpoint`: FfiConverterTypeOutPoint.read(from: buf), + `txout`: FfiConverterTypeTxOut.read(from: buf), + `keychain`: FfiConverterTypeKeychainKind.read(from: buf), + `isSpent`: FfiConverterBool.read(from: buf) + ) + } + + fileprivate static func write(_ value: LocalUtxo, into buf: Writer) { + FfiConverterTypeOutPoint.write(value.`outpoint`, into: buf) + FfiConverterTypeTxOut.write(value.`txout`, into: buf) + FfiConverterTypeKeychainKind.write(value.`keychain`, into: buf) + FfiConverterBool.write(value.`isSpent`, into: buf) + } +} + + +public struct OutPoint { + public var `txid`: String + public var `vout`: UInt32 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(`txid`: String, `vout`: UInt32) { + self.`txid` = `txid` + self.`vout` = `vout` + } +} + + +extension OutPoint: Equatable, Hashable { + public static func ==(lhs: OutPoint, rhs: OutPoint) -> Bool { + if lhs.`txid` != rhs.`txid` { + return false + } + if lhs.`vout` != rhs.`vout` { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(`txid`) + hasher.combine(`vout`) + } +} + + +fileprivate struct FfiConverterTypeOutPoint: FfiConverterRustBuffer { + fileprivate static func read(from buf: Reader) throws -> OutPoint { + return try OutPoint( + `txid`: FfiConverterString.read(from: buf), + `vout`: FfiConverterUInt32.read(from: buf) + ) + } + + fileprivate static func write(_ value: OutPoint, into buf: Writer) { + FfiConverterString.write(value.`txid`, into: buf) + FfiConverterUInt32.write(value.`vout`, into: buf) + } +} + + +public struct ScriptAmount { + public var `script`: Script + public var `amount`: UInt64 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(`script`: Script, `amount`: UInt64) { + self.`script` = `script` + self.`amount` = `amount` + } +} + + + +fileprivate struct FfiConverterTypeScriptAmount: FfiConverterRustBuffer { + fileprivate static func read(from buf: Reader) throws -> ScriptAmount { + return try ScriptAmount( + `script`: FfiConverterTypeScript.read(from: buf), + `amount`: FfiConverterUInt64.read(from: buf) + ) + } + + fileprivate static func write(_ value: ScriptAmount, into buf: Writer) { + FfiConverterTypeScript.write(value.`script`, into: buf) + FfiConverterUInt64.write(value.`amount`, into: buf) + } +} + + +public struct SledDbConfiguration { + public var `path`: String + public var `treeName`: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(`path`: String, `treeName`: String) { + self.`path` = `path` + self.`treeName` = `treeName` + } +} + + +extension SledDbConfiguration: Equatable, Hashable { + public static func ==(lhs: SledDbConfiguration, rhs: SledDbConfiguration) -> Bool { + if lhs.`path` != rhs.`path` { + return false + } + if lhs.`treeName` != rhs.`treeName` { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(`path`) + hasher.combine(`treeName`) + } +} + + +fileprivate struct FfiConverterTypeSledDbConfiguration: FfiConverterRustBuffer { + fileprivate static func read(from buf: Reader) throws -> SledDbConfiguration { + return try SledDbConfiguration( + `path`: FfiConverterString.read(from: buf), + `treeName`: FfiConverterString.read(from: buf) + ) + } + + fileprivate static func write(_ value: SledDbConfiguration, into buf: Writer) { + FfiConverterString.write(value.`path`, into: buf) + FfiConverterString.write(value.`treeName`, into: buf) + } +} + + +public struct SqliteDbConfiguration { + public var `path`: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(`path`: String) { + self.`path` = `path` + } +} + + +extension SqliteDbConfiguration: Equatable, Hashable { + public static func ==(lhs: SqliteDbConfiguration, rhs: SqliteDbConfiguration) -> Bool { + if lhs.`path` != rhs.`path` { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(`path`) + } +} + + +fileprivate struct FfiConverterTypeSqliteDbConfiguration: FfiConverterRustBuffer { + fileprivate static func read(from buf: Reader) throws -> SqliteDbConfiguration { + return try SqliteDbConfiguration( + `path`: FfiConverterString.read(from: buf) + ) + } + + fileprivate static func write(_ value: SqliteDbConfiguration, into buf: Writer) { + FfiConverterString.write(value.`path`, into: buf) + } +} + + +public struct TransactionDetails { + public var `fee`: UInt64? + public var `received`: UInt64 + public var `sent`: UInt64 + public var `txid`: String + public var `confirmationTime`: BlockTime? + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(`fee`: UInt64?, `received`: UInt64, `sent`: UInt64, `txid`: String, `confirmationTime`: BlockTime?) { + self.`fee` = `fee` + self.`received` = `received` + self.`sent` = `sent` + self.`txid` = `txid` + self.`confirmationTime` = `confirmationTime` + } +} + + +extension TransactionDetails: Equatable, Hashable { + public static func ==(lhs: TransactionDetails, rhs: TransactionDetails) -> Bool { + if lhs.`fee` != rhs.`fee` { + return false + } + if lhs.`received` != rhs.`received` { + return false + } + if lhs.`sent` != rhs.`sent` { + return false + } + if lhs.`txid` != rhs.`txid` { + return false + } + if lhs.`confirmationTime` != rhs.`confirmationTime` { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(`fee`) + hasher.combine(`received`) + hasher.combine(`sent`) + hasher.combine(`txid`) + hasher.combine(`confirmationTime`) + } +} + + +fileprivate struct FfiConverterTypeTransactionDetails: FfiConverterRustBuffer { + fileprivate static func read(from buf: Reader) throws -> TransactionDetails { + return try TransactionDetails( + `fee`: FfiConverterOptionUInt64.read(from: buf), + `received`: FfiConverterUInt64.read(from: buf), + `sent`: FfiConverterUInt64.read(from: buf), + `txid`: FfiConverterString.read(from: buf), + `confirmationTime`: FfiConverterOptionTypeBlockTime.read(from: buf) + ) + } + + fileprivate static func write(_ value: TransactionDetails, into buf: Writer) { + FfiConverterOptionUInt64.write(value.`fee`, into: buf) + FfiConverterUInt64.write(value.`received`, into: buf) + FfiConverterUInt64.write(value.`sent`, into: buf) + FfiConverterString.write(value.`txid`, into: buf) + FfiConverterOptionTypeBlockTime.write(value.`confirmationTime`, into: buf) + } +} + + +public struct TxBuilderResult { + public var `psbt`: PartiallySignedBitcoinTransaction + public var `transactionDetails`: TransactionDetails + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(`psbt`: PartiallySignedBitcoinTransaction, `transactionDetails`: TransactionDetails) { + self.`psbt` = `psbt` + self.`transactionDetails` = `transactionDetails` + } +} + + + +fileprivate struct FfiConverterTypeTxBuilderResult: FfiConverterRustBuffer { + fileprivate static func read(from buf: Reader) throws -> TxBuilderResult { + return try TxBuilderResult( + `psbt`: FfiConverterTypePartiallySignedBitcoinTransaction.read(from: buf), + `transactionDetails`: FfiConverterTypeTransactionDetails.read(from: buf) + ) + } + + fileprivate static func write(_ value: TxBuilderResult, into buf: Writer) { + FfiConverterTypePartiallySignedBitcoinTransaction.write(value.`psbt`, into: buf) + FfiConverterTypeTransactionDetails.write(value.`transactionDetails`, into: buf) + } +} + + +public struct TxOut { + public var `value`: UInt64 + public var `address`: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(`value`: UInt64, `address`: String) { + self.`value` = `value` + self.`address` = `address` + } +} + + +extension TxOut: Equatable, Hashable { + public static func ==(lhs: TxOut, rhs: TxOut) -> Bool { + if lhs.`value` != rhs.`value` { + return false + } + if lhs.`address` != rhs.`address` { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(`value`) + hasher.combine(`address`) + } +} + + +fileprivate struct FfiConverterTypeTxOut: FfiConverterRustBuffer { + fileprivate static func read(from buf: Reader) throws -> TxOut { + return try TxOut( + `value`: FfiConverterUInt64.read(from: buf), + `address`: FfiConverterString.read(from: buf) + ) + } + + fileprivate static func write(_ value: TxOut, into buf: Writer) { + FfiConverterUInt64.write(value.`value`, into: buf) + FfiConverterString.write(value.`address`, into: buf) } } // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - public enum AddressIndex { - case new - case lastUnused + case `new` + case `lastUnused` } -extension AddressIndex: ViaFfiUsingByteBuffer, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> AddressIndex { +fileprivate struct FfiConverterTypeAddressIndex: FfiConverterRustBuffer { + typealias SwiftType = AddressIndex + + static func read(from buf: Reader) throws -> AddressIndex { let variant: Int32 = try buf.readInt() switch variant { - case 1: return .new - case 2: return .lastUnused + case 1: return .`new` + + case 2: return .`lastUnused` + default: throw UniffiInternalError.unexpectedEnumCase } } - fileprivate func write(into buf: Writer) { - switch self { + static func write(_ value: AddressIndex, into buf: Writer) { + switch value { - case .new: + case .`new`: buf.writeInt(Int32(1)) - case .lastUnused: + case .`lastUnused`: buf.writeInt(Int32(2)) } @@ -513,45 +2251,195 @@ extension AddressIndex: Equatable, Hashable {} // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - -public enum Network { +public enum BlockchainConfig { - case bitcoin - case testnet - case signet - case regtest + case `electrum`(`config`: ElectrumConfig) + case `esplora`(`config`: EsploraConfig) } -extension Network: ViaFfiUsingByteBuffer, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> Network { +fileprivate struct FfiConverterTypeBlockchainConfig: FfiConverterRustBuffer { + typealias SwiftType = BlockchainConfig + + static func read(from buf: Reader) throws -> BlockchainConfig { let variant: Int32 = try buf.readInt() switch variant { - case 1: return .bitcoin - case 2: return .testnet - case 3: return .signet - case 4: return .regtest + case 1: return .`electrum`( + `config`: try FfiConverterTypeElectrumConfig.read(from: buf) + ) + + case 2: return .`esplora`( + `config`: try FfiConverterTypeEsploraConfig.read(from: buf) + ) + default: throw UniffiInternalError.unexpectedEnumCase } } - fileprivate func write(into buf: Writer) { - switch self { + static func write(_ value: BlockchainConfig, into buf: Writer) { + switch value { - case .bitcoin: + case let .`electrum`(`config`): + buf.writeInt(Int32(1)) + FfiConverterTypeElectrumConfig.write(`config`, into: buf) + + + case let .`esplora`(`config`): + buf.writeInt(Int32(2)) + FfiConverterTypeEsploraConfig.write(`config`, into: buf) + + } + } +} + + +extension BlockchainConfig: Equatable, Hashable {} + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. +public enum DatabaseConfig { + + case `memory` + case `sled`(`config`: SledDbConfiguration) + case `sqlite`(`config`: SqliteDbConfiguration) +} + +fileprivate struct FfiConverterTypeDatabaseConfig: FfiConverterRustBuffer { + typealias SwiftType = DatabaseConfig + + static func read(from buf: Reader) throws -> DatabaseConfig { + let variant: Int32 = try buf.readInt() + switch variant { + + case 1: return .`memory` + + case 2: return .`sled`( + `config`: try FfiConverterTypeSledDbConfiguration.read(from: buf) + ) + + case 3: return .`sqlite`( + `config`: try FfiConverterTypeSqliteDbConfiguration.read(from: buf) + ) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + static func write(_ value: DatabaseConfig, into buf: Writer) { + switch value { + + + case .`memory`: buf.writeInt(Int32(1)) - case .testnet: + case let .`sled`(`config`): + buf.writeInt(Int32(2)) + FfiConverterTypeSledDbConfiguration.write(`config`, into: buf) + + + case let .`sqlite`(`config`): + buf.writeInt(Int32(3)) + FfiConverterTypeSqliteDbConfiguration.write(`config`, into: buf) + + } + } +} + + +extension DatabaseConfig: Equatable, Hashable {} + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. +public enum KeychainKind { + + case `external` + case `internal` +} + +fileprivate struct FfiConverterTypeKeychainKind: FfiConverterRustBuffer { + typealias SwiftType = KeychainKind + + static func read(from buf: Reader) throws -> KeychainKind { + let variant: Int32 = try buf.readInt() + switch variant { + + case 1: return .`external` + + case 2: return .`internal` + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + static func write(_ value: KeychainKind, into buf: Writer) { + switch value { + + + case .`external`: + buf.writeInt(Int32(1)) + + + case .`internal`: + buf.writeInt(Int32(2)) + + } + } +} + + +extension KeychainKind: Equatable, Hashable {} + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. +public enum Network { + + case `bitcoin` + case `testnet` + case `signet` + case `regtest` +} + +fileprivate struct FfiConverterTypeNetwork: FfiConverterRustBuffer { + typealias SwiftType = Network + + static func read(from buf: Reader) throws -> Network { + let variant: Int32 = try buf.readInt() + switch variant { + + case 1: return .`bitcoin` + + case 2: return .`testnet` + + case 3: return .`signet` + + case 4: return .`regtest` + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + static func write(_ value: Network, into buf: Writer) { + switch value { + + + case .`bitcoin`: + buf.writeInt(Int32(1)) + + + case .`testnet`: buf.writeInt(Int32(2)) - case .signet: + case .`signet`: buf.writeInt(Int32(3)) - case .regtest: + case .`regtest`: buf.writeInt(Int32(4)) } @@ -564,153 +2452,57 @@ extension Network: Equatable, Hashable {} // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - -public enum DatabaseConfig { - - case memory - case sled(config: SledDbConfiguration ) - case sqlite(config: SqliteDbConfiguration ) -} - -extension DatabaseConfig: ViaFfiUsingByteBuffer, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> DatabaseConfig { - let variant: Int32 = try buf.readInt() - switch variant { - - case 1: return .memory - case 2: return .sled( - config: try SledDbConfiguration.read(from: buf) - ) - case 3: return .sqlite( - config: try SqliteDbConfiguration.read(from: buf) - ) - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - fileprivate func write(into buf: Writer) { - switch self { - - - case .memory: - buf.writeInt(Int32(1)) - - - case let .sled(config): - buf.writeInt(Int32(2)) - config.write(into: buf) - - - - case let .sqlite(config): - buf.writeInt(Int32(3)) - config.write(into: buf) - - - } - } -} - - -extension DatabaseConfig: Equatable, Hashable {} - - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - -public enum Transaction { - - case unconfirmed(details: TransactionDetails ) - case confirmed(details: TransactionDetails, confirmation: BlockTime ) -} - -extension Transaction: ViaFfiUsingByteBuffer, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> Transaction { - let variant: Int32 = try buf.readInt() - switch variant { - - case 1: return .unconfirmed( - details: try TransactionDetails.read(from: buf) - ) - case 2: return .confirmed( - details: try TransactionDetails.read(from: buf), - confirmation: try BlockTime.read(from: buf) - ) - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - fileprivate func write(into buf: Writer) { - switch self { - - - case let .unconfirmed(details): - buf.writeInt(Int32(1)) - details.write(into: buf) - - - - case let .confirmed(details,confirmation): - buf.writeInt(Int32(2)) - details.write(into: buf) - confirmation.write(into: buf) - - - } - } -} - - -extension Transaction: Equatable, Hashable {} - - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - public enum WordCount { - case words12 - case words15 - case words18 - case words21 - case words24 + case `words12` + case `words15` + case `words18` + case `words21` + case `words24` } -extension WordCount: ViaFfiUsingByteBuffer, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> WordCount { +fileprivate struct FfiConverterTypeWordCount: FfiConverterRustBuffer { + typealias SwiftType = WordCount + + static func read(from buf: Reader) throws -> WordCount { let variant: Int32 = try buf.readInt() switch variant { - case 1: return .words12 - case 2: return .words15 - case 3: return .words18 - case 4: return .words21 - case 5: return .words24 + case 1: return .`words12` + + case 2: return .`words15` + + case 3: return .`words18` + + case 4: return .`words21` + + case 5: return .`words24` + default: throw UniffiInternalError.unexpectedEnumCase } } - fileprivate func write(into buf: Writer) { - switch self { + static func write(_ value: WordCount, into buf: Writer) { + switch value { - case .words12: + case .`words12`: buf.writeInt(Int32(1)) - case .words15: + case .`words15`: buf.writeInt(Int32(2)) - case .words18: + case .`words18`: buf.writeInt(Int32(3)) - case .words21: + case .`words21`: buf.writeInt(Int32(4)) - case .words24: + case .`words24`: buf.writeInt(Int32(5)) } @@ -721,1066 +2513,6 @@ extension WordCount: ViaFfiUsingByteBuffer, ViaFfi { extension WordCount: Equatable, Hashable {} -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - -public enum BlockchainConfig { - - case electrum(config: ElectrumConfig ) - case esplora(config: EsploraConfig ) -} - -extension BlockchainConfig: ViaFfiUsingByteBuffer, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> BlockchainConfig { - let variant: Int32 = try buf.readInt() - switch variant { - - case 1: return .electrum( - config: try ElectrumConfig.read(from: buf) - ) - case 2: return .esplora( - config: try EsploraConfig.read(from: buf) - ) - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - fileprivate func write(into buf: Writer) { - switch self { - - - case let .electrum(config): - buf.writeInt(Int32(1)) - config.write(into: buf) - - - - case let .esplora(config): - buf.writeInt(Int32(2)) - config.write(into: buf) - - - } - } -} - - -extension BlockchainConfig: Equatable, Hashable {} - - - -public func generateExtendedKey( network: Network, wordCount: WordCount, password: String? ) throws -> ExtendedKeyInfo { - let _retval = try - - - rustCallWithError(BdkError.self) { - - bdk_1c1_generate_extended_key(network.lower(), wordCount.lower(), FfiConverterOptionString.lower(password) , $0) -} - return try ExtendedKeyInfo.lift(_retval) -} - - - -public func restoreExtendedKey( network: Network, mnemonic: String, password: String? ) throws -> ExtendedKeyInfo { - let _retval = try - - - rustCallWithError(BdkError.self) { - - bdk_1c1_restore_extended_key(network.lower(), mnemonic.lower(), FfiConverterOptionString.lower(password) , $0) -} - return try ExtendedKeyInfo.lift(_retval) -} - - - -public protocol BlockchainProtocol { - func broadcast( psbt: PartiallySignedBitcoinTransaction ) throws - -} - -public class Blockchain: BlockchainProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `ViaFfi` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init( config: BlockchainConfig ) throws { - self.init(unsafeFromRawPointer: try - - - rustCallWithError(BdkError.self) { - - bdk_1c1_Blockchain_new(config.lower() , $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_1c1_Blockchain_object_free(pointer, $0) } - } - - - - - public func broadcast( psbt: PartiallySignedBitcoinTransaction ) throws { - try - rustCallWithError(BdkError.self) { - - bdk_1c1_Blockchain_broadcast(self.pointer, psbt.lower() , $0 - ) -} - } - -} - - -fileprivate extension Blockchain { - typealias FfiType = UnsafeMutableRawPointer - - static func read(from buf: Reader) throws -> Self { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try self.lift(ptr!) - } - - func write(into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) - } - - static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { - return Self(unsafeFromRawPointer: pointer) - } - - func lower() -> UnsafeMutableRawPointer { - return self.pointer - } -} - -// Ideally this would be `fileprivate`, but Swift says: -// """ -// 'private' modifier cannot be used with extensions that declare protocol conformances -// """ -extension Blockchain : ViaFfi, Serializable {} - - -public protocol WalletProtocol { - func getAddress( addressIndex: AddressIndex ) throws -> AddressInfo - func getBalance() throws -> UInt64 - func sign( psbt: PartiallySignedBitcoinTransaction ) throws -> Bool - func getTransactions() throws -> [Transaction] - func getNetwork() -> Network - func sync( blockchain: Blockchain, progress: Progress? ) throws - -} - -public class Wallet: WalletProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `ViaFfi` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init( descriptor: String, changeDescriptor: String?, network: Network, databaseConfig: DatabaseConfig ) throws { - self.init(unsafeFromRawPointer: try - - - rustCallWithError(BdkError.self) { - - bdk_1c1_Wallet_new(descriptor.lower(), FfiConverterOptionString.lower(changeDescriptor), network.lower(), databaseConfig.lower() , $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_1c1_Wallet_object_free(pointer, $0) } - } - - - - - public func getAddress( addressIndex: AddressIndex ) throws -> AddressInfo { - let _retval = try - rustCallWithError(BdkError.self) { - - bdk_1c1_Wallet_get_address(self.pointer, addressIndex.lower() , $0 - ) -} - return try AddressInfo.lift(_retval) - } - public func getBalance() throws -> UInt64 { - let _retval = try - rustCallWithError(BdkError.self) { - - bdk_1c1_Wallet_get_balance(self.pointer, $0 - ) -} - return try UInt64.lift(_retval) - } - public func sign( psbt: PartiallySignedBitcoinTransaction ) throws -> Bool { - let _retval = try - rustCallWithError(BdkError.self) { - - bdk_1c1_Wallet_sign(self.pointer, psbt.lower() , $0 - ) -} - return try Bool.lift(_retval) - } - public func getTransactions() throws -> [Transaction] { - let _retval = try - rustCallWithError(BdkError.self) { - - bdk_1c1_Wallet_get_transactions(self.pointer, $0 - ) -} - return try FfiConverterSequenceEnumTransaction.lift(_retval) - } - public func getNetwork() -> Network { - let _retval = try! - rustCall() { - - bdk_1c1_Wallet_get_network(self.pointer, $0 - ) -} - return try! Network.lift(_retval) - } - public func sync( blockchain: Blockchain, progress: Progress? ) throws { - try - rustCallWithError(BdkError.self) { - - bdk_1c1_Wallet_sync(self.pointer, blockchain.lower(), FfiConverterOptionCallbackInterfaceProgress.lower(progress) , $0 - ) -} - } - -} - - -fileprivate extension Wallet { - typealias FfiType = UnsafeMutableRawPointer - - static func read(from buf: Reader) throws -> Self { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try self.lift(ptr!) - } - - func write(into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) - } - - static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { - return Self(unsafeFromRawPointer: pointer) - } - - func lower() -> UnsafeMutableRawPointer { - return self.pointer - } -} - -// Ideally this would be `fileprivate`, but Swift says: -// """ -// 'private' modifier cannot be used with extensions that declare protocol conformances -// """ -extension Wallet : ViaFfi, Serializable {} - - -public protocol PartiallySignedBitcoinTransactionProtocol { - func serialize() -> String - func txid() -> String - -} - -public class PartiallySignedBitcoinTransaction: PartiallySignedBitcoinTransactionProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `ViaFfi` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init( psbtBase64: String ) throws { - self.init(unsafeFromRawPointer: try - - - rustCallWithError(BdkError.self) { - - bdk_1c1_PartiallySignedBitcoinTransaction_new(psbtBase64.lower() , $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_1c1_PartiallySignedBitcoinTransaction_object_free(pointer, $0) } - } - - - - - public func serialize() -> String { - let _retval = try! - rustCall() { - - bdk_1c1_PartiallySignedBitcoinTransaction_serialize(self.pointer, $0 - ) -} - return try! String.lift(_retval) - } - public func txid() -> String { - let _retval = try! - rustCall() { - - bdk_1c1_PartiallySignedBitcoinTransaction_txid(self.pointer, $0 - ) -} - return try! String.lift(_retval) - } - -} - - -fileprivate extension PartiallySignedBitcoinTransaction { - typealias FfiType = UnsafeMutableRawPointer - - static func read(from buf: Reader) throws -> Self { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try self.lift(ptr!) - } - - func write(into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) - } - - static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { - return Self(unsafeFromRawPointer: pointer) - } - - func lower() -> UnsafeMutableRawPointer { - return self.pointer - } -} - -// Ideally this would be `fileprivate`, but Swift says: -// """ -// 'private' modifier cannot be used with extensions that declare protocol conformances -// """ -extension PartiallySignedBitcoinTransaction : ViaFfi, Serializable {} - - -public protocol TxBuilderProtocol { - func addRecipient( address: String, amount: UInt64 ) -> TxBuilder - func feeRate( satPerVbyte: Float ) -> TxBuilder - func drainWallet() -> TxBuilder - func drainTo( address: String ) -> TxBuilder - func enableRbf() -> TxBuilder - func enableRbfWithSequence( nsequence: UInt32 ) -> TxBuilder - func finish( wallet: Wallet ) throws -> PartiallySignedBitcoinTransaction - -} - -public class TxBuilder: TxBuilderProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `ViaFfi` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init() { - self.init(unsafeFromRawPointer: try! - - - rustCall() { - - bdk_1c1_TxBuilder_new( $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_1c1_TxBuilder_object_free(pointer, $0) } - } - - - - - public func addRecipient( address: String, amount: UInt64 ) -> TxBuilder { - let _retval = try! - rustCall() { - - bdk_1c1_TxBuilder_add_recipient(self.pointer, address.lower(), amount.lower() , $0 - ) -} - return try! TxBuilder.lift(_retval) - } - public func feeRate( satPerVbyte: Float ) -> TxBuilder { - let _retval = try! - rustCall() { - - bdk_1c1_TxBuilder_fee_rate(self.pointer, satPerVbyte.lower() , $0 - ) -} - return try! TxBuilder.lift(_retval) - } - public func drainWallet() -> TxBuilder { - let _retval = try! - rustCall() { - - bdk_1c1_TxBuilder_drain_wallet(self.pointer, $0 - ) -} - return try! TxBuilder.lift(_retval) - } - public func drainTo( address: String ) -> TxBuilder { - let _retval = try! - rustCall() { - - bdk_1c1_TxBuilder_drain_to(self.pointer, address.lower() , $0 - ) -} - return try! TxBuilder.lift(_retval) - } - public func enableRbf() -> TxBuilder { - let _retval = try! - rustCall() { - - bdk_1c1_TxBuilder_enable_rbf(self.pointer, $0 - ) -} - return try! TxBuilder.lift(_retval) - } - public func enableRbfWithSequence( nsequence: UInt32 ) -> TxBuilder { - let _retval = try! - rustCall() { - - bdk_1c1_TxBuilder_enable_rbf_with_sequence(self.pointer, nsequence.lower() , $0 - ) -} - return try! TxBuilder.lift(_retval) - } - public func finish( wallet: Wallet ) throws -> PartiallySignedBitcoinTransaction { - let _retval = try - rustCallWithError(BdkError.self) { - - bdk_1c1_TxBuilder_finish(self.pointer, wallet.lower() , $0 - ) -} - return try PartiallySignedBitcoinTransaction.lift(_retval) - } - -} - - -fileprivate extension TxBuilder { - typealias FfiType = UnsafeMutableRawPointer - - static func read(from buf: Reader) throws -> Self { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try self.lift(ptr!) - } - - func write(into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) - } - - static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { - return Self(unsafeFromRawPointer: pointer) - } - - func lower() -> UnsafeMutableRawPointer { - return self.pointer - } -} - -// Ideally this would be `fileprivate`, but Swift says: -// """ -// 'private' modifier cannot be used with extensions that declare protocol conformances -// """ -extension TxBuilder : ViaFfi, Serializable {} - - -public protocol BumpFeeTxBuilderProtocol { - func allowShrinking( address: String ) -> BumpFeeTxBuilder - func enableRbf() -> BumpFeeTxBuilder - func enableRbfWithSequence( nsequence: UInt32 ) -> BumpFeeTxBuilder - func finish( wallet: Wallet ) throws -> PartiallySignedBitcoinTransaction - -} - -public class BumpFeeTxBuilder: BumpFeeTxBuilderProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `ViaFfi` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init( txid: String, newFeeRate: Float ) { - self.init(unsafeFromRawPointer: try! - - - rustCall() { - - bdk_1c1_BumpFeeTxBuilder_new(txid.lower(), newFeeRate.lower() , $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_1c1_BumpFeeTxBuilder_object_free(pointer, $0) } - } - - - - - public func allowShrinking( address: String ) -> BumpFeeTxBuilder { - let _retval = try! - rustCall() { - - bdk_1c1_BumpFeeTxBuilder_allow_shrinking(self.pointer, address.lower() , $0 - ) -} - return try! BumpFeeTxBuilder.lift(_retval) - } - public func enableRbf() -> BumpFeeTxBuilder { - let _retval = try! - rustCall() { - - bdk_1c1_BumpFeeTxBuilder_enable_rbf(self.pointer, $0 - ) -} - return try! BumpFeeTxBuilder.lift(_retval) - } - public func enableRbfWithSequence( nsequence: UInt32 ) -> BumpFeeTxBuilder { - let _retval = try! - rustCall() { - - bdk_1c1_BumpFeeTxBuilder_enable_rbf_with_sequence(self.pointer, nsequence.lower() , $0 - ) -} - return try! BumpFeeTxBuilder.lift(_retval) - } - public func finish( wallet: Wallet ) throws -> PartiallySignedBitcoinTransaction { - let _retval = try - rustCallWithError(BdkError.self) { - - bdk_1c1_BumpFeeTxBuilder_finish(self.pointer, wallet.lower() , $0 - ) -} - return try PartiallySignedBitcoinTransaction.lift(_retval) - } - -} - - -fileprivate extension BumpFeeTxBuilder { - typealias FfiType = UnsafeMutableRawPointer - - static func read(from buf: Reader) throws -> Self { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try self.lift(ptr!) - } - - func write(into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: self.lower())))) - } - - static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self { - return Self(unsafeFromRawPointer: pointer) - } - - func lower() -> UnsafeMutableRawPointer { - return self.pointer - } -} - -// Ideally this would be `fileprivate`, but Swift says: -// """ -// 'private' modifier cannot be used with extensions that declare protocol conformances -// """ -extension BumpFeeTxBuilder : ViaFfi, Serializable {} - -public struct AddressInfo { - public var index: UInt32 - public var address: String - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(index: UInt32, address: String ) { - self.index = index - self.address = address - } -} - - -extension AddressInfo: Equatable, Hashable { - public static func ==(lhs: AddressInfo, rhs: AddressInfo) -> Bool { - if lhs.index != rhs.index { - return false - } - if lhs.address != rhs.address { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(index) - hasher.combine(address) - } -} - - -fileprivate extension AddressInfo { - static func read(from buf: Reader) throws -> AddressInfo { - return try AddressInfo( - index: UInt32.read(from: buf), - address: String.read(from: buf) - ) - } - - func write(into buf: Writer) { - self.index.write(into: buf) - self.address.write(into: buf) - } -} - -extension AddressInfo: ViaFfiUsingByteBuffer, ViaFfi {} - -public struct SledDbConfiguration { - public var path: String - public var treeName: String - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(path: String, treeName: String ) { - self.path = path - self.treeName = treeName - } -} - - -extension SledDbConfiguration: Equatable, Hashable { - public static func ==(lhs: SledDbConfiguration, rhs: SledDbConfiguration) -> Bool { - if lhs.path != rhs.path { - return false - } - if lhs.treeName != rhs.treeName { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(path) - hasher.combine(treeName) - } -} - - -fileprivate extension SledDbConfiguration { - static func read(from buf: Reader) throws -> SledDbConfiguration { - return try SledDbConfiguration( - path: String.read(from: buf), - treeName: String.read(from: buf) - ) - } - - func write(into buf: Writer) { - self.path.write(into: buf) - self.treeName.write(into: buf) - } -} - -extension SledDbConfiguration: ViaFfiUsingByteBuffer, ViaFfi {} - -public struct SqliteDbConfiguration { - public var path: String - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(path: String ) { - self.path = path - } -} - - -extension SqliteDbConfiguration: Equatable, Hashable { - public static func ==(lhs: SqliteDbConfiguration, rhs: SqliteDbConfiguration) -> Bool { - if lhs.path != rhs.path { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(path) - } -} - - -fileprivate extension SqliteDbConfiguration { - static func read(from buf: Reader) throws -> SqliteDbConfiguration { - return try SqliteDbConfiguration( - path: String.read(from: buf) - ) - } - - func write(into buf: Writer) { - self.path.write(into: buf) - } -} - -extension SqliteDbConfiguration: ViaFfiUsingByteBuffer, ViaFfi {} - -public struct TransactionDetails { - public var fee: UInt64? - public var received: UInt64 - public var sent: UInt64 - public var txid: String - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(fee: UInt64?, received: UInt64, sent: UInt64, txid: String ) { - self.fee = fee - self.received = received - self.sent = sent - self.txid = txid - } -} - - -extension TransactionDetails: Equatable, Hashable { - public static func ==(lhs: TransactionDetails, rhs: TransactionDetails) -> Bool { - if lhs.fee != rhs.fee { - return false - } - if lhs.received != rhs.received { - return false - } - if lhs.sent != rhs.sent { - return false - } - if lhs.txid != rhs.txid { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(fee) - hasher.combine(received) - hasher.combine(sent) - hasher.combine(txid) - } -} - - -fileprivate extension TransactionDetails { - static func read(from buf: Reader) throws -> TransactionDetails { - return try TransactionDetails( - fee: FfiConverterOptionUInt64.read(from: buf), - received: UInt64.read(from: buf), - sent: UInt64.read(from: buf), - txid: String.read(from: buf) - ) - } - - func write(into buf: Writer) { - FfiConverterOptionUInt64.write(self.fee, into: buf) - self.received.write(into: buf) - self.sent.write(into: buf) - self.txid.write(into: buf) - } -} - -extension TransactionDetails: ViaFfiUsingByteBuffer, ViaFfi {} - -public struct BlockTime { - public var height: UInt32 - public var timestamp: UInt64 - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(height: UInt32, timestamp: UInt64 ) { - self.height = height - self.timestamp = timestamp - } -} - - -extension BlockTime: Equatable, Hashable { - public static func ==(lhs: BlockTime, rhs: BlockTime) -> Bool { - if lhs.height != rhs.height { - return false - } - if lhs.timestamp != rhs.timestamp { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(height) - hasher.combine(timestamp) - } -} - - -fileprivate extension BlockTime { - static func read(from buf: Reader) throws -> BlockTime { - return try BlockTime( - height: UInt32.read(from: buf), - timestamp: UInt64.read(from: buf) - ) - } - - func write(into buf: Writer) { - self.height.write(into: buf) - self.timestamp.write(into: buf) - } -} - -extension BlockTime: ViaFfiUsingByteBuffer, ViaFfi {} - -public struct ExtendedKeyInfo { - public var mnemonic: String - public var xprv: String - public var fingerprint: String - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(mnemonic: String, xprv: String, fingerprint: String ) { - self.mnemonic = mnemonic - self.xprv = xprv - self.fingerprint = fingerprint - } -} - - -extension ExtendedKeyInfo: Equatable, Hashable { - public static func ==(lhs: ExtendedKeyInfo, rhs: ExtendedKeyInfo) -> Bool { - if lhs.mnemonic != rhs.mnemonic { - return false - } - if lhs.xprv != rhs.xprv { - return false - } - if lhs.fingerprint != rhs.fingerprint { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(mnemonic) - hasher.combine(xprv) - hasher.combine(fingerprint) - } -} - - -fileprivate extension ExtendedKeyInfo { - static func read(from buf: Reader) throws -> ExtendedKeyInfo { - return try ExtendedKeyInfo( - mnemonic: String.read(from: buf), - xprv: String.read(from: buf), - fingerprint: String.read(from: buf) - ) - } - - func write(into buf: Writer) { - self.mnemonic.write(into: buf) - self.xprv.write(into: buf) - self.fingerprint.write(into: buf) - } -} - -extension ExtendedKeyInfo: ViaFfiUsingByteBuffer, ViaFfi {} - -public struct ElectrumConfig { - public var url: String - public var socks5: String? - public var retry: UInt8 - public var timeout: UInt8? - public var stopGap: UInt64 - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(url: String, socks5: String?, retry: UInt8, timeout: UInt8?, stopGap: UInt64 ) { - self.url = url - self.socks5 = socks5 - self.retry = retry - self.timeout = timeout - self.stopGap = stopGap - } -} - - -extension ElectrumConfig: Equatable, Hashable { - public static func ==(lhs: ElectrumConfig, rhs: ElectrumConfig) -> Bool { - if lhs.url != rhs.url { - return false - } - if lhs.socks5 != rhs.socks5 { - return false - } - if lhs.retry != rhs.retry { - return false - } - if lhs.timeout != rhs.timeout { - return false - } - if lhs.stopGap != rhs.stopGap { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(url) - hasher.combine(socks5) - hasher.combine(retry) - hasher.combine(timeout) - hasher.combine(stopGap) - } -} - - -fileprivate extension ElectrumConfig { - static func read(from buf: Reader) throws -> ElectrumConfig { - return try ElectrumConfig( - url: String.read(from: buf), - socks5: FfiConverterOptionString.read(from: buf), - retry: UInt8.read(from: buf), - timeout: FfiConverterOptionUInt8.read(from: buf), - stopGap: UInt64.read(from: buf) - ) - } - - func write(into buf: Writer) { - self.url.write(into: buf) - FfiConverterOptionString.write(self.socks5, into: buf) - self.retry.write(into: buf) - FfiConverterOptionUInt8.write(self.timeout, into: buf) - self.stopGap.write(into: buf) - } -} - -extension ElectrumConfig: ViaFfiUsingByteBuffer, ViaFfi {} - -public struct EsploraConfig { - public var baseUrl: String - public var proxy: String? - public var concurrency: UInt8? - public var stopGap: UInt64 - public var timeout: UInt64? - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(baseUrl: String, proxy: String?, concurrency: UInt8?, stopGap: UInt64, timeout: UInt64? ) { - self.baseUrl = baseUrl - self.proxy = proxy - self.concurrency = concurrency - self.stopGap = stopGap - self.timeout = timeout - } -} - - -extension EsploraConfig: Equatable, Hashable { - public static func ==(lhs: EsploraConfig, rhs: EsploraConfig) -> Bool { - if lhs.baseUrl != rhs.baseUrl { - return false - } - if lhs.proxy != rhs.proxy { - return false - } - if lhs.concurrency != rhs.concurrency { - return false - } - if lhs.stopGap != rhs.stopGap { - return false - } - if lhs.timeout != rhs.timeout { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(baseUrl) - hasher.combine(proxy) - hasher.combine(concurrency) - hasher.combine(stopGap) - hasher.combine(timeout) - } -} - - -fileprivate extension EsploraConfig { - static func read(from buf: Reader) throws -> EsploraConfig { - return try EsploraConfig( - baseUrl: String.read(from: buf), - proxy: FfiConverterOptionString.read(from: buf), - concurrency: FfiConverterOptionUInt8.read(from: buf), - stopGap: UInt64.read(from: buf), - timeout: FfiConverterOptionUInt64.read(from: buf) - ) - } - - func write(into buf: Writer) { - self.baseUrl.write(into: buf) - FfiConverterOptionString.write(self.proxy, into: buf) - FfiConverterOptionUInt8.write(self.concurrency, into: buf) - self.stopGap.write(into: buf) - FfiConverterOptionUInt64.write(self.timeout, into: buf) - } -} - -extension EsploraConfig: ViaFfiUsingByteBuffer, ViaFfi {} public enum BdkError { @@ -1792,6 +2524,9 @@ public enum BdkError { // Simple error enums only carry a message case Generic(message: String) + // Simple error enums only carry a message + case MissingCachedScripts(message: String) + // Simple error enums only carry a message case ScriptDoesntHaveAddressForm(message: String) @@ -1908,8 +2643,10 @@ public enum BdkError { } -extension BdkError: ViaFfiUsingByteBuffer, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> BdkError { +fileprivate struct FfiConverterTypeBdkError: FfiConverterRustBuffer { + typealias SwiftType = BdkError + + static func read(from buf: Reader) throws -> BdkError { let variant: Int32 = try buf.readInt() switch variant { @@ -1917,296 +2654,305 @@ extension BdkError: ViaFfiUsingByteBuffer, ViaFfi { case 1: return .InvalidU32Bytes( - message: try String.read(from: buf) + message: try FfiConverterString.read(from: buf) ) case 2: return .Generic( - message: try String.read(from: buf) + message: try FfiConverterString.read(from: buf) ) - case 3: return .ScriptDoesntHaveAddressForm( - message: try String.read(from: buf) + case 3: return .MissingCachedScripts( + message: try FfiConverterString.read(from: buf) ) - case 4: return .NoRecipients( - message: try String.read(from: buf) + case 4: return .ScriptDoesntHaveAddressForm( + message: try FfiConverterString.read(from: buf) ) - case 5: return .NoUtxosSelected( - message: try String.read(from: buf) + case 5: return .NoRecipients( + message: try FfiConverterString.read(from: buf) ) - case 6: return .OutputBelowDustLimit( - message: try String.read(from: buf) + case 6: return .NoUtxosSelected( + message: try FfiConverterString.read(from: buf) ) - case 7: return .InsufficientFunds( - message: try String.read(from: buf) + case 7: return .OutputBelowDustLimit( + message: try FfiConverterString.read(from: buf) ) - case 8: return .BnBTotalTriesExceeded( - message: try String.read(from: buf) + case 8: return .InsufficientFunds( + message: try FfiConverterString.read(from: buf) ) - case 9: return .BnBNoExactMatch( - message: try String.read(from: buf) + case 9: return .BnBTotalTriesExceeded( + message: try FfiConverterString.read(from: buf) ) - case 10: return .UnknownUtxo( - message: try String.read(from: buf) + case 10: return .BnBNoExactMatch( + message: try FfiConverterString.read(from: buf) ) - case 11: return .TransactionNotFound( - message: try String.read(from: buf) + case 11: return .UnknownUtxo( + message: try FfiConverterString.read(from: buf) ) - case 12: return .TransactionConfirmed( - message: try String.read(from: buf) + case 12: return .TransactionNotFound( + message: try FfiConverterString.read(from: buf) ) - case 13: return .IrreplaceableTransaction( - message: try String.read(from: buf) + case 13: return .TransactionConfirmed( + message: try FfiConverterString.read(from: buf) ) - case 14: return .FeeRateTooLow( - message: try String.read(from: buf) + case 14: return .IrreplaceableTransaction( + message: try FfiConverterString.read(from: buf) ) - case 15: return .FeeTooLow( - message: try String.read(from: buf) + case 15: return .FeeRateTooLow( + message: try FfiConverterString.read(from: buf) ) - case 16: return .FeeRateUnavailable( - message: try String.read(from: buf) + case 16: return .FeeTooLow( + message: try FfiConverterString.read(from: buf) ) - case 17: return .MissingKeyOrigin( - message: try String.read(from: buf) + case 17: return .FeeRateUnavailable( + message: try FfiConverterString.read(from: buf) ) - case 18: return .Key( - message: try String.read(from: buf) + case 18: return .MissingKeyOrigin( + message: try FfiConverterString.read(from: buf) ) - case 19: return .ChecksumMismatch( - message: try String.read(from: buf) + case 19: return .Key( + message: try FfiConverterString.read(from: buf) ) - case 20: return .SpendingPolicyRequired( - message: try String.read(from: buf) + case 20: return .ChecksumMismatch( + message: try FfiConverterString.read(from: buf) ) - case 21: return .InvalidPolicyPathError( - message: try String.read(from: buf) + case 21: return .SpendingPolicyRequired( + message: try FfiConverterString.read(from: buf) ) - case 22: return .Signer( - message: try String.read(from: buf) + case 22: return .InvalidPolicyPathError( + message: try FfiConverterString.read(from: buf) ) - case 23: return .InvalidNetwork( - message: try String.read(from: buf) + case 23: return .Signer( + message: try FfiConverterString.read(from: buf) ) - case 24: return .InvalidProgressValue( - message: try String.read(from: buf) + case 24: return .InvalidNetwork( + message: try FfiConverterString.read(from: buf) ) - case 25: return .ProgressUpdateError( - message: try String.read(from: buf) + case 25: return .InvalidProgressValue( + message: try FfiConverterString.read(from: buf) ) - case 26: return .InvalidOutpoint( - message: try String.read(from: buf) + case 26: return .ProgressUpdateError( + message: try FfiConverterString.read(from: buf) ) - case 27: return .Descriptor( - message: try String.read(from: buf) + case 27: return .InvalidOutpoint( + message: try FfiConverterString.read(from: buf) ) - case 28: return .AddressValidator( - message: try String.read(from: buf) + case 28: return .Descriptor( + message: try FfiConverterString.read(from: buf) ) - case 29: return .Encode( - message: try String.read(from: buf) + case 29: return .AddressValidator( + message: try FfiConverterString.read(from: buf) ) - case 30: return .Miniscript( - message: try String.read(from: buf) + case 30: return .Encode( + message: try FfiConverterString.read(from: buf) ) - case 31: return .Bip32( - message: try String.read(from: buf) + case 31: return .Miniscript( + message: try FfiConverterString.read(from: buf) ) - case 32: return .Secp256k1( - message: try String.read(from: buf) + case 32: return .Bip32( + message: try FfiConverterString.read(from: buf) ) - case 33: return .Json( - message: try String.read(from: buf) + case 33: return .Secp256k1( + message: try FfiConverterString.read(from: buf) ) - case 34: return .Hex( - message: try String.read(from: buf) + case 34: return .Json( + message: try FfiConverterString.read(from: buf) ) - case 35: return .Psbt( - message: try String.read(from: buf) + case 35: return .Hex( + message: try FfiConverterString.read(from: buf) ) - case 36: return .PsbtParse( - message: try String.read(from: buf) + case 36: return .Psbt( + message: try FfiConverterString.read(from: buf) ) - case 37: return .Electrum( - message: try String.read(from: buf) + case 37: return .PsbtParse( + message: try FfiConverterString.read(from: buf) ) - case 38: return .Esplora( - message: try String.read(from: buf) + case 38: return .Electrum( + message: try FfiConverterString.read(from: buf) ) - case 39: return .Sled( - message: try String.read(from: buf) + case 39: return .Esplora( + message: try FfiConverterString.read(from: buf) ) - case 40: return .Rusqlite( - message: try String.read(from: buf) + case 40: return .Sled( + message: try FfiConverterString.read(from: buf) + ) + + case 41: return .Rusqlite( + message: try FfiConverterString.read(from: buf) ) - default: throw UniffiInternalError.unexpectedEnumCase + default: throw UniffiInternalError.unexpectedEnumCase } } - fileprivate func write(into buf: Writer) { - switch self { + static func write(_ value: BdkError, into buf: Writer) { + switch value { case let .InvalidU32Bytes(message): buf.writeInt(Int32(1)) - message.write(into: buf) + FfiConverterString.write(message, into: buf) case let .Generic(message): buf.writeInt(Int32(2)) - message.write(into: buf) - case let .ScriptDoesntHaveAddressForm(message): + FfiConverterString.write(message, into: buf) + case let .MissingCachedScripts(message): buf.writeInt(Int32(3)) - message.write(into: buf) - case let .NoRecipients(message): + FfiConverterString.write(message, into: buf) + case let .ScriptDoesntHaveAddressForm(message): buf.writeInt(Int32(4)) - message.write(into: buf) - case let .NoUtxosSelected(message): + FfiConverterString.write(message, into: buf) + case let .NoRecipients(message): buf.writeInt(Int32(5)) - message.write(into: buf) - case let .OutputBelowDustLimit(message): + FfiConverterString.write(message, into: buf) + case let .NoUtxosSelected(message): buf.writeInt(Int32(6)) - message.write(into: buf) - case let .InsufficientFunds(message): + FfiConverterString.write(message, into: buf) + case let .OutputBelowDustLimit(message): buf.writeInt(Int32(7)) - message.write(into: buf) - case let .BnBTotalTriesExceeded(message): + FfiConverterString.write(message, into: buf) + case let .InsufficientFunds(message): buf.writeInt(Int32(8)) - message.write(into: buf) - case let .BnBNoExactMatch(message): + FfiConverterString.write(message, into: buf) + case let .BnBTotalTriesExceeded(message): buf.writeInt(Int32(9)) - message.write(into: buf) - case let .UnknownUtxo(message): + FfiConverterString.write(message, into: buf) + case let .BnBNoExactMatch(message): buf.writeInt(Int32(10)) - message.write(into: buf) - case let .TransactionNotFound(message): + FfiConverterString.write(message, into: buf) + case let .UnknownUtxo(message): buf.writeInt(Int32(11)) - message.write(into: buf) - case let .TransactionConfirmed(message): + FfiConverterString.write(message, into: buf) + case let .TransactionNotFound(message): buf.writeInt(Int32(12)) - message.write(into: buf) - case let .IrreplaceableTransaction(message): + FfiConverterString.write(message, into: buf) + case let .TransactionConfirmed(message): buf.writeInt(Int32(13)) - message.write(into: buf) - case let .FeeRateTooLow(message): + FfiConverterString.write(message, into: buf) + case let .IrreplaceableTransaction(message): buf.writeInt(Int32(14)) - message.write(into: buf) - case let .FeeTooLow(message): + FfiConverterString.write(message, into: buf) + case let .FeeRateTooLow(message): buf.writeInt(Int32(15)) - message.write(into: buf) - case let .FeeRateUnavailable(message): + FfiConverterString.write(message, into: buf) + case let .FeeTooLow(message): buf.writeInt(Int32(16)) - message.write(into: buf) - case let .MissingKeyOrigin(message): + FfiConverterString.write(message, into: buf) + case let .FeeRateUnavailable(message): buf.writeInt(Int32(17)) - message.write(into: buf) - case let .Key(message): + FfiConverterString.write(message, into: buf) + case let .MissingKeyOrigin(message): buf.writeInt(Int32(18)) - message.write(into: buf) - case let .ChecksumMismatch(message): + FfiConverterString.write(message, into: buf) + case let .Key(message): buf.writeInt(Int32(19)) - message.write(into: buf) - case let .SpendingPolicyRequired(message): + FfiConverterString.write(message, into: buf) + case let .ChecksumMismatch(message): buf.writeInt(Int32(20)) - message.write(into: buf) - case let .InvalidPolicyPathError(message): + FfiConverterString.write(message, into: buf) + case let .SpendingPolicyRequired(message): buf.writeInt(Int32(21)) - message.write(into: buf) - case let .Signer(message): + FfiConverterString.write(message, into: buf) + case let .InvalidPolicyPathError(message): buf.writeInt(Int32(22)) - message.write(into: buf) - case let .InvalidNetwork(message): + FfiConverterString.write(message, into: buf) + case let .Signer(message): buf.writeInt(Int32(23)) - message.write(into: buf) - case let .InvalidProgressValue(message): + FfiConverterString.write(message, into: buf) + case let .InvalidNetwork(message): buf.writeInt(Int32(24)) - message.write(into: buf) - case let .ProgressUpdateError(message): + FfiConverterString.write(message, into: buf) + case let .InvalidProgressValue(message): buf.writeInt(Int32(25)) - message.write(into: buf) - case let .InvalidOutpoint(message): + FfiConverterString.write(message, into: buf) + case let .ProgressUpdateError(message): buf.writeInt(Int32(26)) - message.write(into: buf) - case let .Descriptor(message): + FfiConverterString.write(message, into: buf) + case let .InvalidOutpoint(message): buf.writeInt(Int32(27)) - message.write(into: buf) - case let .AddressValidator(message): + FfiConverterString.write(message, into: buf) + case let .Descriptor(message): buf.writeInt(Int32(28)) - message.write(into: buf) - case let .Encode(message): + FfiConverterString.write(message, into: buf) + case let .AddressValidator(message): buf.writeInt(Int32(29)) - message.write(into: buf) - case let .Miniscript(message): + FfiConverterString.write(message, into: buf) + case let .Encode(message): buf.writeInt(Int32(30)) - message.write(into: buf) - case let .Bip32(message): + FfiConverterString.write(message, into: buf) + case let .Miniscript(message): buf.writeInt(Int32(31)) - message.write(into: buf) - case let .Secp256k1(message): + FfiConverterString.write(message, into: buf) + case let .Bip32(message): buf.writeInt(Int32(32)) - message.write(into: buf) - case let .Json(message): + FfiConverterString.write(message, into: buf) + case let .Secp256k1(message): buf.writeInt(Int32(33)) - message.write(into: buf) - case let .Hex(message): + FfiConverterString.write(message, into: buf) + case let .Json(message): buf.writeInt(Int32(34)) - message.write(into: buf) - case let .Psbt(message): + FfiConverterString.write(message, into: buf) + case let .Hex(message): buf.writeInt(Int32(35)) - message.write(into: buf) - case let .PsbtParse(message): + FfiConverterString.write(message, into: buf) + case let .Psbt(message): buf.writeInt(Int32(36)) - message.write(into: buf) - case let .Electrum(message): + FfiConverterString.write(message, into: buf) + case let .PsbtParse(message): buf.writeInt(Int32(37)) - message.write(into: buf) - case let .Esplora(message): + FfiConverterString.write(message, into: buf) + case let .Electrum(message): buf.writeInt(Int32(38)) - message.write(into: buf) - case let .Sled(message): + FfiConverterString.write(message, into: buf) + case let .Esplora(message): buf.writeInt(Int32(39)) - message.write(into: buf) - case let .Rusqlite(message): + FfiConverterString.write(message, into: buf) + case let .Sled(message): buf.writeInt(Int32(40)) - message.write(into: buf) + FfiConverterString.write(message, into: buf) + case let .Rusqlite(message): + buf.writeInt(Int32(41)) + FfiConverterString.write(message, into: buf) + + } } } @@ -2216,45 +2962,116 @@ extension BdkError: Equatable, Hashable {} extension BdkError: Error { } +fileprivate extension NSLock { + func withLock(f: () throws -> T) rethrows -> T { + self.lock() + defer { self.unlock() } + return try f() + } +} + +fileprivate typealias Handle = UInt64 +fileprivate class ConcurrentHandleMap { + private var leftMap: [Handle: T] = [:] + private var counter: [Handle: UInt64] = [:] + private var rightMap: [ObjectIdentifier: Handle] = [:] + + private let lock = NSLock() + private var currentHandle: Handle = 0 + private let stride: Handle = 1 + + func insert(obj: T) -> Handle { + lock.withLock { + let id = ObjectIdentifier(obj as AnyObject) + let handle = rightMap[id] ?? { + currentHandle += stride + let handle = currentHandle + leftMap[handle] = obj + rightMap[id] = handle + return handle + }() + counter[handle] = (counter[handle] ?? 0) + 1 + return handle + } + } + + func get(handle: Handle) -> T? { + lock.withLock { + leftMap[handle] + } + } + + func delete(handle: Handle) { + remove(handle: handle) + } + + @discardableResult + func remove(handle: Handle) -> T? { + lock.withLock { + defer { counter[handle] = (counter[handle] ?? 1) - 1 } + guard counter[handle] == 1 else { return leftMap[handle] } + let obj = leftMap.removeValue(forKey: handle) + if let obj = obj { + rightMap.removeValue(forKey: ObjectIdentifier(obj as AnyObject)) + } + return obj + } + } +} + +// 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 // Declaration and FfiConverters for Progress Callback Interface public protocol Progress : AnyObject { - func update( progress: Float, message: String? ) + func `update`(`progress`: Float, `message`: String?) } // The ForeignCallback that is passed to Rust. fileprivate let foreignCallbackCallbackInterfaceProgress : ForeignCallback = { (handle: Handle, method: Int32, args: RustBuffer, out_buf: UnsafeMutablePointer) -> Int32 in - func invokeUpdate(_ swiftCallbackInterface: Progress, _ args: RustBuffer) throws -> RustBuffer { + func `invokeUpdate`(_ swiftCallbackInterface: Progress, _ args: RustBuffer) throws -> RustBuffer { defer { args.deallocate() } let reader = Reader(data: Data(rustBuffer: args)) - swiftCallbackInterface.update( - progress: try Float.read(from: reader), - message: try FfiConverterOptionString.read(from: reader) + swiftCallbackInterface.`update`( + `progress`: try FfiConverterFloat.read(from: reader), + `message`: try FfiConverterOptionString.read(from: reader) ) return RustBuffer() // TODO catch errors and report them back to Rust. // https://github.com/mozilla/uniffi-rs/issues/351 - } - + } + + + let cb: Progress + do { + cb = try FfiConverterCallbackInterfaceProgress.lift(handle) + } catch { + out_buf.pointee = FfiConverterString.lower("Progress: Invalid handle") + return -1 + } - let cb = try! ffiConverterCallbackInterfaceProgress.lift(handle) switch method { case IDX_CALLBACK_FREE: - ffiConverterCallbackInterfaceProgress.drop(handle: handle) + FfiConverterCallbackInterfaceProgress.drop(handle: handle) // No return value. // See docs of ForeignCallback in `uniffi/src/ffi/foreigncallbacks.rs` return 0 case 1: - let buffer = try! invokeUpdate(cb, args) - out_buf.pointee = buffer - // Value written to out buffer. - // See docs of ForeignCallback in `uniffi/src/ffi/foreigncallbacks.rs` - return 1 + do { + out_buf.pointee = try `invokeUpdate`(cb, args) + // Value written to out buffer. + // See docs of ForeignCallback in `uniffi/src/ffi/foreigncallbacks.rs` + return 1 + } catch let error { + out_buf.pointee = FfiConverterString.lower(String(describing: error)) + return -1 + } // This should never happen, because an out of bounds method index won't // ever be used. Once we can catch errors, we should return an InternalError. @@ -2266,205 +3083,287 @@ fileprivate let foreignCallbackCallbackInterfaceProgress : ForeignCallback = } } -// The ffiConverter which transforms the Callbacks in to Handles to pass to Rust. -private let ffiConverterCallbackInterfaceProgress: FfiConverterCallbackInterface = { - try! rustCall { (err: UnsafeMutablePointer) in - ffi_bdk_1c1_Progress_init_callback(foreignCallbackCallbackInterfaceProgress, err) - } - return FfiConverterCallbackInterface() -}() -extension UInt8: Primitive, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> Self { - return try self.lift(buf.readInt()) - } - - fileprivate func write(into buf: Writer) { - buf.writeInt(self.lower()) - } -} -extension UInt32: Primitive, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> Self { - return try self.lift(buf.readInt()) - } - - fileprivate func write(into buf: Writer) { - buf.writeInt(self.lower()) - } -} -extension UInt64: Primitive, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> Self { - return try self.lift(buf.readInt()) - } - - fileprivate func write(into buf: Writer) { - buf.writeInt(self.lower()) - } -} -extension Float: Primitive, ViaFfi { - fileprivate static func read(from buf: Reader) throws -> Self { - return try self.lift(buf.readFloat()) - } - - fileprivate func write(into buf: Writer) { - buf.writeFloat(self.lower()) - } -} -extension Bool: ViaFfi { - fileprivate typealias FfiType = Int8 - - fileprivate static func read(from buf: Reader) throws -> Self { - return try self.lift(buf.readInt()) - } - - fileprivate func write(into buf: Writer) { - buf.writeInt(self.lower()) - } - - fileprivate static func lift(_ v: FfiType) throws -> Self { - return v != 0 - } - - fileprivate func lower() -> FfiType { - return self ? 1 : 0 - } -} -extension String: ViaFfi { - fileprivate typealias FfiType = RustBuffer - - fileprivate static func lift(_ v: FfiType) throws -> Self { - defer { - v.deallocate() +// FFIConverter protocol for callback interfaces +fileprivate struct FfiConverterCallbackInterfaceProgress { + // Initialize our callback method with the scaffolding code + private static var callbackInitialized = false + private static func initCallback() { + try! rustCall { (err: UnsafeMutablePointer) in + ffi_bdk_1724_Progress_init_callback(foreignCallbackCallbackInterfaceProgress, err) } - if v.data == nil { - return String() - } - let bytes = UnsafeBufferPointer(start: v.data!, count: Int(v.len)) - return String(bytes: bytes, encoding: String.Encoding.utf8)! } - - fileprivate func lower() -> FfiType { - return self.utf8CString.withUnsafeBufferPointer { ptr in - // The swift string gives us int8_t, we want uint8_t. - ptr.withMemoryRebound(to: UInt8.self) { ptr in - // The swift string gives us a trailing null byte, we don't want it. - let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) - return RustBuffer.from(buf) - } + private static func ensureCallbackinitialized() { + if !callbackInitialized { + initCallback() + callbackInitialized = true } } - fileprivate static func read(from buf: Reader) throws -> Self { - let len: Int32 = try buf.readInt() - return String(bytes: try buf.readBytes(count: Int(len)), encoding: String.Encoding.utf8)! + static func drop(handle: Handle) { + handleMap.remove(handle: handle) } - fileprivate func write(into buf: Writer) { - let len = Int32(self.utf8.count) - buf.writeInt(len) - buf.writeBytes(self.utf8) + private static var handleMap = ConcurrentHandleMap() +} + +extension FfiConverterCallbackInterfaceProgress : FfiConverter { + typealias SwiftType = Progress + // We can use Handle as the FFIType because it's a typealias to UInt64 + typealias FfiType = Handle + + static func lift(_ handle: Handle) throws -> SwiftType { + ensureCallbackinitialized(); + guard let callback = handleMap.get(handle: handle) else { + throw UniffiInternalError.unexpectedStaleHandle + } + return callback + } + + static func read(from buf: Reader) throws -> SwiftType { + ensureCallbackinitialized(); + let handle: Handle = try buf.readInt() + return try lift(handle) + } + + static func lower(_ v: SwiftType) -> Handle { + ensureCallbackinitialized(); + return handleMap.insert(obj: v) + } + + static func write(_ v: SwiftType, into buf: Writer) { + ensureCallbackinitialized(); + buf.writeInt(lower(v)) } } -// Helper code for Blockchain class is found in ObjectTemplate.swift -// Helper code for BumpFeeTxBuilder class is found in ObjectTemplate.swift -// Helper code for PartiallySignedBitcoinTransaction class is found in ObjectTemplate.swift -// Helper code for TxBuilder class is found in ObjectTemplate.swift -// Helper code for Wallet class is found in ObjectTemplate.swift -// Helper code for AddressInfo record is found in RecordTemplate.swift -// Helper code for BlockTime record is found in RecordTemplate.swift -// Helper code for ElectrumConfig record is found in RecordTemplate.swift -// Helper code for EsploraConfig record is found in RecordTemplate.swift -// Helper code for ExtendedKeyInfo record is found in RecordTemplate.swift -// Helper code for SledDbConfiguration record is found in RecordTemplate.swift -// Helper code for SqliteDbConfiguration record is found in RecordTemplate.swift -// Helper code for TransactionDetails record is found in RecordTemplate.swift -// Helper code for AddressIndex enum is found in EnumTemplate.swift -// Helper code for BlockchainConfig enum is found in EnumTemplate.swift -// Helper code for DatabaseConfig enum is found in EnumTemplate.swift -// Helper code for Network enum is found in EnumTemplate.swift -// Helper code for Transaction enum is found in EnumTemplate.swift -// Helper code for WordCount enum is found in EnumTemplate.swift -// Helper code for BdkError error is found in ErrorTemplate.swift -fileprivate enum FfiConverterOptionUInt8: FfiConverterUsingByteBuffer { +fileprivate struct FfiConverterOptionUInt8: FfiConverterRustBuffer { typealias SwiftType = UInt8? static func write(_ value: SwiftType, into buf: Writer) { - FfiConverterOptional.write(value, into: buf) { item, buf in - item.write(into: buf) + guard let value = value else { + buf.writeInt(Int8(0)) + return } + buf.writeInt(Int8(1)) + FfiConverterUInt8.write(value, into: buf) } static func read(from buf: Reader) throws -> SwiftType { - try FfiConverterOptional.read(from: buf) { buf in - try UInt8.read(from: buf) + switch try buf.readInt() as Int8 { + case 0: return nil + case 1: return try FfiConverterUInt8.read(from: buf) + default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate enum FfiConverterOptionUInt64: FfiConverterUsingByteBuffer { +fileprivate struct FfiConverterOptionUInt64: FfiConverterRustBuffer { typealias SwiftType = UInt64? static func write(_ value: SwiftType, into buf: Writer) { - FfiConverterOptional.write(value, into: buf) { item, buf in - item.write(into: buf) + guard let value = value else { + buf.writeInt(Int8(0)) + return } + buf.writeInt(Int8(1)) + FfiConverterUInt64.write(value, into: buf) } static func read(from buf: Reader) throws -> SwiftType { - try FfiConverterOptional.read(from: buf) { buf in - try UInt64.read(from: buf) + switch try buf.readInt() as Int8 { + case 0: return nil + case 1: return try FfiConverterUInt64.read(from: buf) + default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate enum FfiConverterOptionString: FfiConverterUsingByteBuffer { +fileprivate struct FfiConverterOptionString: FfiConverterRustBuffer { typealias SwiftType = String? static func write(_ value: SwiftType, into buf: Writer) { - FfiConverterOptional.write(value, into: buf) { item, buf in - item.write(into: buf) + guard let value = value else { + buf.writeInt(Int8(0)) + return } + buf.writeInt(Int8(1)) + FfiConverterString.write(value, into: buf) } static func read(from buf: Reader) throws -> SwiftType { - try FfiConverterOptional.read(from: buf) { buf in - try String.read(from: buf) + switch try buf.readInt() as Int8 { + case 0: return nil + case 1: return try FfiConverterString.read(from: buf) + default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate enum FfiConverterOptionCallbackInterfaceProgress: FfiConverterUsingByteBuffer { +fileprivate struct FfiConverterOptionTypeBlockTime: FfiConverterRustBuffer { + typealias SwiftType = BlockTime? + + static func write(_ value: SwiftType, into buf: Writer) { + guard let value = value else { + buf.writeInt(Int8(0)) + return + } + buf.writeInt(Int8(1)) + FfiConverterTypeBlockTime.write(value, into: buf) + } + + static func read(from buf: Reader) throws -> SwiftType { + switch try buf.readInt() as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeBlockTime.read(from: buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterOptionCallbackInterfaceProgress: FfiConverterRustBuffer { typealias SwiftType = Progress? static func write(_ value: SwiftType, into buf: Writer) { - FfiConverterOptional.write(value, into: buf) { item, buf in - ffiConverterCallbackInterfaceProgress.write(item, into: buf) + guard let value = value else { + buf.writeInt(Int8(0)) + return } + buf.writeInt(Int8(1)) + FfiConverterCallbackInterfaceProgress.write(value, into: buf) } static func read(from buf: Reader) throws -> SwiftType { - try FfiConverterOptional.read(from: buf) { buf in - try ffiConverterCallbackInterfaceProgress.read(from: buf) + switch try buf.readInt() as Int8 { + case 0: return nil + case 1: return try FfiConverterCallbackInterfaceProgress.read(from: buf) + default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate enum FfiConverterSequenceEnumTransaction: FfiConverterUsingByteBuffer { - typealias SwiftType = [Transaction] +fileprivate struct FfiConverterSequenceUInt8: FfiConverterRustBuffer { + typealias SwiftType = [UInt8] - static func write(_ value: SwiftType, into buf: Writer) { - FfiConverterSequence.write(value, into: buf) { (item, buf) in - item.write(into: buf) + static func write(_ value: [UInt8], into buf: Writer) { + let len = Int32(value.count) + buf.writeInt(len) + for item in value { + FfiConverterUInt8.write(item, into: buf) } } - static func read(from buf: Reader) throws -> SwiftType { - try FfiConverterSequence.read(from: buf) { buf in - try Transaction.read(from: buf) + static func read(from buf: Reader) throws -> [UInt8] { + let len: Int32 = try buf.readInt() + var seq = [UInt8]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterUInt8.read(from: buf)) } + return seq } } +fileprivate struct FfiConverterSequenceTypeLocalUtxo: FfiConverterRustBuffer { + typealias SwiftType = [LocalUtxo] + + static func write(_ value: [LocalUtxo], into buf: Writer) { + let len = Int32(value.count) + buf.writeInt(len) + for item in value { + FfiConverterTypeLocalUtxo.write(item, into: buf) + } + } + + static func read(from buf: Reader) throws -> [LocalUtxo] { + let len: Int32 = try buf.readInt() + var seq = [LocalUtxo]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeLocalUtxo.read(from: buf)) + } + return seq + } +} + +fileprivate struct FfiConverterSequenceTypeOutPoint: FfiConverterRustBuffer { + typealias SwiftType = [OutPoint] + + static func write(_ value: [OutPoint], into buf: Writer) { + let len = Int32(value.count) + buf.writeInt(len) + for item in value { + FfiConverterTypeOutPoint.write(item, into: buf) + } + } + + static func read(from buf: Reader) throws -> [OutPoint] { + let len: Int32 = try buf.readInt() + var seq = [OutPoint]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeOutPoint.read(from: buf)) + } + return seq + } +} + +fileprivate struct FfiConverterSequenceTypeScriptAmount: FfiConverterRustBuffer { + typealias SwiftType = [ScriptAmount] + + static func write(_ value: [ScriptAmount], into buf: Writer) { + let len = Int32(value.count) + buf.writeInt(len) + for item in value { + FfiConverterTypeScriptAmount.write(item, into: buf) + } + } + + static func read(from buf: Reader) throws -> [ScriptAmount] { + let len: Int32 = try buf.readInt() + var seq = [ScriptAmount]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeScriptAmount.read(from: buf)) + } + return seq + } +} + +fileprivate struct FfiConverterSequenceTypeTransactionDetails: FfiConverterRustBuffer { + typealias SwiftType = [TransactionDetails] + + static func write(_ value: [TransactionDetails], into buf: Writer) { + let len = Int32(value.count) + buf.writeInt(len) + for item in value { + FfiConverterTypeTransactionDetails.write(item, into: buf) + } + } + + static func read(from buf: Reader) throws -> [TransactionDetails] { + let len: Int32 = try buf.readInt() + var seq = [TransactionDetails]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeTransactionDetails.read(from: buf)) + } + return seq + } +} + +public func `generateMnemonic`(`wordCount`: WordCount) throws -> String { + return try FfiConverterString.lift( + try + + rustCallWithError(FfiConverterTypeBdkError.self) { + + bdk_1724_generate_mnemonic( + FfiConverterTypeWordCount.lower(`wordCount`), $0) +} + ) +} + + /** * Top level initializers and tear down methods. @@ -2476,8 +3375,5 @@ public enum BdkLifecycle { * Initialize the FFI and Rust library. This should be only called once per application. */ func initialize() { - - // No initialization code needed - } } \ No newline at end of file diff --git a/bdk-ffi b/bdk-ffi index 80ed21e..e6cf423 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit 80ed21e4c9e61d6224e074258229a4d6da6cc049 +Subproject commit e6cf4237218be9c6143936e7d0056e5270d4c227 From beca56ba3c399ec932332bbde9cca8491aa505cc Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Fri, 28 Oct 2022 21:32:08 -0500 Subject: [PATCH 23/33] Add publish-spm github actions workflow --- .github/workflows/publish-spm.yaml | 117 +++++++++++++++++++++++++++++ Package.swift.txt | 36 +++++++++ build.sh | 76 ------------------- 3 files changed, 153 insertions(+), 76 deletions(-) create mode 100644 .github/workflows/publish-spm.yaml create mode 100644 Package.swift.txt delete mode 100755 build.sh diff --git a/.github/workflows/publish-spm.yaml b/.github/workflows/publish-spm.yaml new file mode 100644 index 0000000..f135871 --- /dev/null +++ b/.github/workflows/publish-spm.yaml @@ -0,0 +1,117 @@ +name: Build, tag and create release +on: + workflow_dispatch: + inputs: + branch: + description: 'Release branch, eg. release/0.MINOR' + required: true + type: string + version: + description: 'New release version, eg. 0.MINOR.PATCH' + required: true + type: string + +jobs: + build-publish: + name: Build, tag and create release + runs-on: macos-12 + steps: + - name: Checkout release branch + uses: actions/checkout@v2 + with: + ref: ${{ inputs.branch }} + submodules: true + + - name: Cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + ./bdk-ffi/target + key: ${{ runner.os }}-${{ hashFiles('**/Cargo.toml','**/Cargo.lock') }} + + - name: Install Rust targets + run: | + rustup install nightly-x86_64-apple-darwin + rustup component add rust-src --toolchain nightly-x86_64-apple-darwin + rustup target add aarch64-apple-ios x86_64-apple-ios + rustup target add aarch64-apple-ios-sim --toolchain nightly + rustup target add aarch64-apple-darwin x86_64-apple-darwin + + - name: Run bdk-ffi-bindgen + working-directory: bdk-ffi + run: | + cargo run --package bdk-ffi-bindgen -- --language swift --out-dir ../Sources/BitcoinDevKit + + - name: Build bdk-ffi for x86_64-apple-darwin + working-directory: bdk-ffi + run: | + cargo build --release --target x86_64-apple-darwin + + - name: Build bdk-ffi for aarch64-apple-darwin + working-directory: bdk-ffi + run: | + cargo build --release --target aarch64-apple-darwin + + - name: Build bdk-ffi for x86_64-apple-ios + working-directory: bdk-ffi + run: | + cargo build --release --target x86_64-apple-ios + + - name: Build bdk-ffi for aarch64-apple-ios + working-directory: bdk-ffi + run: | + cargo build --release --target aarch64-apple-ios + + - name: Build bdk-ffi for aarch64-apple-ios-sim + working-directory: bdk-ffi + run: | + cargo +nightly build --release -Z build-std --target aarch64-apple-ios-sim + + - name: Create lipo-ios-sim and lipo-macos + working-directory: bdk-ffi + run: | + mkdir -p target/lipo-ios-sim/release + lipo target/aarch64-apple-ios-sim/release/libbdkffi.a target/x86_64-apple-ios/release/libbdkffi.a -create -output target/lipo-ios-sim/release/libbdkffi.a + mkdir -p target/lipo-macos/release + lipo target/aarch64-apple-darwin/release/libbdkffi.a target/x86_64-apple-darwin/release/libbdkffi.a -create -output target/lipo-macos/release/libbdkffi.a + + - name: Create bdkFFI.xcframework + run: | + mv Sources/BitcoinDevKit/bdk.swift Sources/BitcoinDevKit/BitcoinDevKit.swift + cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Headers + cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Headers + cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Headers + cp bdk-ffi/target/aarch64-apple-ios/release/libbdkffi.a bdkFFI.xcframework/ios-arm64/bdkFFI.framework/bdkFFI + cp bdk-ffi/target/lipo-ios-sim/release/libbdkffi.a bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/bdkFFI + cp bdk-ffi/target/lipo-macos/release/libbdkffi.a bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/bdkFFI + rm Sources/BitcoinDevKit/bdkFFI.h + rm Sources/BitcoinDevkit/bdkFFI.modulemap + rm bdkFFI.xcframework.zip || true + zip -9 -r bdkFFI.xcframework.zip bdkFFI.xcframework + echo "BDKFFICHECKSUM=`swift package compute-checksum bdkFFI.xcframework.zip`" >> $GITHUB_ENV + echo "BDKFFIURL=https\:\/\/github\.com\/${{ github.repository_owner }}\/bdk\-swift\/releases\/download\/${{ inputs.version }}\/bdkFFI\.xcframework\.zip" >> $GITHUB_ENV + + - name: Update, commit, and push new Package.swift + run: | + echo checksum = ${{ env.BDKFFICHECKSUM }} + echo url = ${{ env.BDKFFIURL }} + sed "s/BDKFFICHECKSUM/${BDKFFICHECKSUM}/;s/BDKFFIURL/${BDKFFIURL}/" Package.swift.txt > Package.swift + git add Package.swift + git commit -m "Update Package.swift for release ${{ inputs.version }}" + git push + + - name: Tag new release + run: | + git tag ${{ inputs.version }} -m "Release ${{ inputs.version }}" + git push --tags + + - name: Publish release + uses: ncipollo/release-action@v1 + with: + artifacts: "bdkFFI.xcframework.zip" + tag: ${{ inputs.version }} + token: ${{ secrets.GITHUB_TOKEN }} + name: Release ${{ inputs.version }} + prerelease: true diff --git a/Package.swift.txt b/Package.swift.txt new file mode 100644 index 0000000..ec401f2 --- /dev/null +++ b/Package.swift.txt @@ -0,0 +1,36 @@ +// swift-tools-version:5.5 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "bdk-swift", + platforms: [ + .macOS(.v12), + .iOS(.v15) + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "BitcoinDevKit", + targets: ["bdkFFI", "BitcoinDevKit"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + // .package(url: /* package url */, from: "1.0.0"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .binaryTarget( + name: "bdkFFI", + url: "BDKFFIURL", + checksum: "BDKFFICHECKSUM"), + .target( + name: "BitcoinDevKit", + dependencies: ["bdkFFI"]), + .testTarget( + name: "BitcoinDevKitTests", + dependencies: ["BitcoinDevKit"]), + ] +) diff --git a/build.sh b/build.sh deleted file mode 100755 index f18881d..0000000 --- a/build.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -## confirm bdk-ffi rust lib builds -pushd bdk-ffi -echo "Confirm bdk-ffi rust lib builds" -cargo build --release - -echo "Generate bdk-ffi swift bindings" -cargo run --package bdk-ffi-bindgen -- --language swift --out-dir ../Sources/BitcoinDevKit - -## build bdk-ffi rust libs for apple targets and add to xcframework -echo "Build bdk-ffi libs for apple targets and add to xcframework" - -TARGET_TRIPLES=("x86_64-apple-darwin" "aarch64-apple-darwin" "x86_64-apple-ios" "aarch64-apple-ios") -#XCFRAMEWORK_LIBS="" -for TARGET in ${TARGET_TRIPLES[@]}; do - echo "Build bdk-ffi lib for target $TARGET" - cargo build --release --target $TARGET - #XCFRAMEWORK_LIBS="$XCFRAMEWORK_LIBS -library target/$TARGET/release/libbdkffi.a" -done -# special build for M1 ios simulator -cargo +nightly build --release -Z build-std --target aarch64-apple-ios-sim - -echo "Create lipo static libs for ios-sim to support M1" -mkdir -p target/lipo-ios-sim/release -lipo target/aarch64-apple-ios-sim/release/libbdkffi.a target/x86_64-apple-ios/release/libbdkffi.a -create -output target/lipo-ios-sim/release/libbdkffi.a - -echo "Create lipo static libs for macos to support M1" -mkdir -p target/lipo-macos/release -lipo target/aarch64-apple-darwin/release/libbdkffi.a target/x86_64-apple-darwin/release/libbdkffi.a -create -output target/lipo-macos/release/libbdkffi.a - -#echo "Create xcframework with xcodebuild" -#xcodebuild -create-xcframework \ -# -library target/lipo-ios-sim/release/libbdkffi.a \ -# -library target/lipo-macos/release/libbdkffi.a \ -# -library target/aarch64-apple-ios/release/libbdkffi.a \ -# -output ../bdkFFI.xcframework - -popd - -# rename bdk.swift bindings to BitcoinDevKit.swift -mv Sources/BitcoinDevKit/bdk.swift Sources/BitcoinDevKit/BitcoinDevKit.swift - -XCFRAMEWORK_LIBS=("ios-arm64" "ios-arm64_x86_64-simulator" "macos-arm64_x86_64") -for LIB in ${XCFRAMEWORK_LIBS[@]}; do - # copy possibly updated header file - cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/$LIB/bdkFFI.framework/Headers -done - -echo "Copy libbdkffi.a files to bdkFFI.xcframework/bdkFFI" -cp bdk-ffi/target/aarch64-apple-ios/release/libbdkffi.a bdkFFI.xcframework/ios-arm64/bdkFFI.framework/bdkFFI -cp bdk-ffi/target/lipo-ios-sim/release/libbdkffi.a bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/bdkFFI -cp bdk-ffi/target/lipo-macos/release/libbdkffi.a bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/bdkFFI - -# remove unneed .h and .modulemap files -rm Sources/BitcoinDevKit/bdkFFI.h -rm Sources/BitcoinDevkit/bdkFFI.modulemap - -# TODO add license info - -if test -f "bdkFFI.xcframework.zip"; then - echo "Remove old bdkFFI.xcframework.zip" - rm bdkFFI.xcframework.zip -fi - - -# zip bdkFFI.xcframework directory into a bundle for distribution -zip -9 -r bdkFFI.xcframework.zip bdkFFI.xcframework - -# compute bdkFFI.xcframework.zip checksum -echo checksum: -swift package compute-checksum bdkFFI.xcframework.zip - -# TODO update Package.swift with checksum -# TODO upload zip to github release From c8436f519c9ed1900f6d96a7ac33a3baa6daa0fd Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Sat, 29 Oct 2022 16:33:26 -0500 Subject: [PATCH 24/33] Update README publishing steps --- README.md | 50 +++----------------------------------------------- 1 file changed, 3 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index bfd258e..48a9905 100644 --- a/README.md +++ b/README.md @@ -30,53 +30,9 @@ let addressInfo = try wallet.getAddress(addressIndex: AddressIndex.new) If you are a maintainer of this project or want to build and publish this project to your own Github repository use the following steps: -1. Clone this repository and init and update it's [`bdk-ffi`] submodule. - ```shell - git clone https://github.com/bitcoindevkit/bdk-swift - git submodule update --init - ``` - -1. Follow the "General" `bdk-ffi` ["Getting Started (Developer)"] instructions. - -1. Install the latest version of [Xcode], download and install the advanced tools. - -1. Ensure Swift is installed. - -1. Install required targets. - ```shell - rustup target add aarch64-apple-ios x86_64-apple-ios - rustup target add aarch64-apple-ios-sim --toolchain nightly - rustup target add aarch64-apple-darwin x86_64-apple-darwin - ``` - -1. Build [`bdk-ffi`] Swift bindings and `bdkFFI.xcframework.zip`. - ```shell - ./build.sh - ``` - -1. Update the `Package.swift` file with the new expected URL for the - `bdkFFI.xcframework.zip` file and new hash as shown at the end of the build.sh script. - For example: - ```swift - .binaryTarget( - name: "bdkFFI", - url: "https://github.com/bitcoindevkit/bdk-swift/releases/download/0.1.3/bdkFFI.xcframework.zip", - checksum: "c0b1e3ea09376b3f316d7d83575e1cd513fc4ad39ef8cf01120a3a1d7757fb97"), - ``` -1. Commit the changed `Package.swift` and tag it with the new version number. - ```shell - git add Package.swift - git commit -m "Bump version to 0.1.3" - git tag 0.1.3 -m "Release 0.1.3" - git push --tags - ``` - -1. Create a github release for your new tag. - -1. Upload the newly created zip to the new github release and publish the release. - -1. Test the new package in Xcode. If you get an error you might need to reset the Xcode - package caches: File -> Packages -> Reset Package Caches. +1. If it doesn't already exist, create a new `release/0.MINOR` branch from the `master` branch +2. Run the `publish-spm` workflow on Github for branch `release/0.MINOR` and version `0.MINOR.0` +3. Copy the changelog from corresponding `bdk-ffi` release description to this release [Swift]: https://developer.apple.com/swift/ [Xcode]: https://developer.apple.com/documentation/Xcode From 4abda332de4a4537bea13b354aed724145deb804 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Sat, 29 Oct 2022 22:08:09 -0500 Subject: [PATCH 25/33] Use the release-smaller profile in publish-spm workflow --- .github/workflows/publish-spm.yaml | 8 ++++---- bdk-ffi | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish-spm.yaml b/.github/workflows/publish-spm.yaml index f135871..4b7f3e3 100644 --- a/.github/workflows/publish-spm.yaml +++ b/.github/workflows/publish-spm.yaml @@ -47,22 +47,22 @@ jobs: - name: Build bdk-ffi for x86_64-apple-darwin working-directory: bdk-ffi run: | - cargo build --release --target x86_64-apple-darwin + cargo build --profile release-smaller --target x86_64-apple-darwin - name: Build bdk-ffi for aarch64-apple-darwin working-directory: bdk-ffi run: | - cargo build --release --target aarch64-apple-darwin + cargo build --profile release-smaller --target aarch64-apple-darwin - name: Build bdk-ffi for x86_64-apple-ios working-directory: bdk-ffi run: | - cargo build --release --target x86_64-apple-ios + cargo build --profile release-smaller --target x86_64-apple-ios - name: Build bdk-ffi for aarch64-apple-ios working-directory: bdk-ffi run: | - cargo build --release --target aarch64-apple-ios + cargo build --profile release-smaller --target aarch64-apple-ios - name: Build bdk-ffi for aarch64-apple-ios-sim working-directory: bdk-ffi diff --git a/bdk-ffi b/bdk-ffi index e6cf423..c2aecb0 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit e6cf4237218be9c6143936e7d0056e5270d4c227 +Subproject commit c2aecb05972af36b35a2c0b0380c503b4d8eb6c2 From eb9241d31531f4d5fefd5398776c390cf4c0dd51 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Tue, 8 Nov 2022 09:55:25 -0600 Subject: [PATCH 26/33] Update bdk-ffi to 0.11.0 --- bdk-ffi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bdk-ffi b/bdk-ffi index c2aecb0..0648075 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit c2aecb05972af36b35a2c0b0380c503b4d8eb6c2 +Subproject commit 0648075555b86365e2408fab484782a2b793b545 From 073c89db4b6d5ca51a5096d27265918e90c153df Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Tue, 8 Nov 2022 11:07:27 -0600 Subject: [PATCH 27/33] Fix publish-spm workflow with release-smaller profile --- .github/workflows/publish-spm.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/publish-spm.yaml b/.github/workflows/publish-spm.yaml index 4b7f3e3..524d213 100644 --- a/.github/workflows/publish-spm.yaml +++ b/.github/workflows/publish-spm.yaml @@ -72,10 +72,10 @@ jobs: - name: Create lipo-ios-sim and lipo-macos working-directory: bdk-ffi run: | - mkdir -p target/lipo-ios-sim/release - lipo target/aarch64-apple-ios-sim/release/libbdkffi.a target/x86_64-apple-ios/release/libbdkffi.a -create -output target/lipo-ios-sim/release/libbdkffi.a - mkdir -p target/lipo-macos/release - lipo target/aarch64-apple-darwin/release/libbdkffi.a target/x86_64-apple-darwin/release/libbdkffi.a -create -output target/lipo-macos/release/libbdkffi.a + mkdir -p target/lipo-ios-sim/release-smaller + lipo target/aarch64-apple-ios-sim/release/libbdkffi.a target/x86_64-apple-ios/release-smaller/libbdkffi.a -create -output target/lipo-ios-sim/release-smaller/libbdkffi.a + mkdir -p target/lipo-macos/release-smaller + lipo target/aarch64-apple-darwin/release-smaller/libbdkffi.a target/x86_64-apple-darwin/release-smaller/libbdkffi.a -create -output target/lipo-macos/release-smaller/libbdkffi.a - name: Create bdkFFI.xcframework run: | @@ -83,9 +83,9 @@ jobs: cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Headers cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Headers cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Headers - cp bdk-ffi/target/aarch64-apple-ios/release/libbdkffi.a bdkFFI.xcframework/ios-arm64/bdkFFI.framework/bdkFFI - cp bdk-ffi/target/lipo-ios-sim/release/libbdkffi.a bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/bdkFFI - cp bdk-ffi/target/lipo-macos/release/libbdkffi.a bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/bdkFFI + cp bdk-ffi/target/aarch64-apple-ios/release-smaller/libbdkffi.a bdkFFI.xcframework/ios-arm64/bdkFFI.framework/bdkFFI + cp bdk-ffi/target/lipo-ios-sim/release-smaller/libbdkffi.a bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/bdkFFI + cp bdk-ffi/target/lipo-macos/release-smaller/libbdkffi.a bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/bdkFFI rm Sources/BitcoinDevKit/bdkFFI.h rm Sources/BitcoinDevkit/bdkFFI.modulemap rm bdkFFI.xcframework.zip || true From 95a36bc9e259d3a96b88313010bd33131142cc3f Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Mon, 14 Nov 2022 18:57:17 -0600 Subject: [PATCH 28/33] Add MIT and Apache 2.0 licenses --- LICENSE | 14 ++++ LICENSE-APACHE | 201 +++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE-MIT | 16 ++++ 3 files changed, 231 insertions(+) create mode 100644 LICENSE create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9c61848 --- /dev/null +++ b/LICENSE @@ -0,0 +1,14 @@ +This software is licensed under [Apache 2.0](LICENSE-APACHE) or +[MIT](LICENSE-MIT), at your option. + +Some files retain their own copyright notice, however, for full authorship +information, see version control history. + +Except as otherwise noted in individual files, all files in this repository are +licensed under the Apache License, Version 2.0 or the MIT license , at your option. + +You may not use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of this software or any files in this repository except in +accordance with one or both of these licenses. \ No newline at end of file diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..9d982a4 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,16 @@ +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From e017d763513df5d7850427c2923b8accb2e2fdd0 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Tue, 15 Nov 2022 18:27:16 -0600 Subject: [PATCH 29/33] Fix publish-spm to commit updated BitcoinDevKit.swift --- .github/workflows/publish-spm.yaml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/publish-spm.yaml b/.github/workflows/publish-spm.yaml index 524d213..ffddeb9 100644 --- a/.github/workflows/publish-spm.yaml +++ b/.github/workflows/publish-spm.yaml @@ -2,10 +2,6 @@ name: Build, tag and create release on: workflow_dispatch: inputs: - branch: - description: 'Release branch, eg. release/0.MINOR' - required: true - type: string version: description: 'New release version, eg. 0.MINOR.PATCH' required: true @@ -19,7 +15,6 @@ jobs: - name: Checkout release branch uses: actions/checkout@v2 with: - ref: ${{ inputs.branch }} submodules: true - name: Cache @@ -98,8 +93,9 @@ jobs: echo checksum = ${{ env.BDKFFICHECKSUM }} echo url = ${{ env.BDKFFIURL }} sed "s/BDKFFICHECKSUM/${BDKFFICHECKSUM}/;s/BDKFFIURL/${BDKFFIURL}/" Package.swift.txt > Package.swift + git add Sources/BitcoinDevKit/BitcoinDevKit.swift git add Package.swift - git commit -m "Update Package.swift for release ${{ inputs.version }}" + git commit -m "Update BitcoinDevKit.swift and Package.swift for release ${{ inputs.version }}" git push - name: Tag new release From b7efb376325d91e6e51daa5b4bf581e870cc5243 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Mon, 21 Nov 2022 12:10:23 -0600 Subject: [PATCH 30/33] Move all files to bdk-swift and deinit bdk-ffi --- bdk-ffi | 1 - {.github => bdk-swift/.github}/workflows/publish-spm.yaml | 0 .gitignore => bdk-swift/.gitignore | 0 .gitmodules => bdk-swift/.gitmodules | 0 LICENSE => bdk-swift/LICENSE | 0 LICENSE-APACHE => bdk-swift/LICENSE-APACHE | 0 LICENSE-MIT => bdk-swift/LICENSE-MIT | 0 Package.swift => bdk-swift/Package.swift | 0 Package.swift.txt => bdk-swift/Package.swift.txt | 0 README.md => bdk-swift/README.md | 0 {Sources => bdk-swift/Sources}/BitcoinDevKit/BitcoinDevKit.swift | 0 .../Tests}/BitcoinDevKitTests/BitcoinDevKitTests.swift | 0 {bdkFFI.xcframework => bdk-swift/bdkFFI.xcframework}/Info.plist | 0 .../ios-arm64/bdkFFI.framework/Headers/bdkFFI-umbrella.h | 0 .../ios-arm64/bdkFFI.framework/Modules/module.modulemap | 0 .../bdkFFI.framework/Headers/bdkFFI-umbrella.h | 0 .../bdkFFI.framework/Modules/module.modulemap | 0 .../bdkFFI.framework/Headers/bdkFFI-umbrella.h | 0 .../macos-arm64_x86_64/bdkFFI.framework/Modules/module.modulemap | 0 19 files changed, 1 deletion(-) delete mode 160000 bdk-ffi rename {.github => bdk-swift/.github}/workflows/publish-spm.yaml (100%) rename .gitignore => bdk-swift/.gitignore (100%) rename .gitmodules => bdk-swift/.gitmodules (100%) rename LICENSE => bdk-swift/LICENSE (100%) rename LICENSE-APACHE => bdk-swift/LICENSE-APACHE (100%) rename LICENSE-MIT => bdk-swift/LICENSE-MIT (100%) rename Package.swift => bdk-swift/Package.swift (100%) rename Package.swift.txt => bdk-swift/Package.swift.txt (100%) rename README.md => bdk-swift/README.md (100%) rename {Sources => bdk-swift/Sources}/BitcoinDevKit/BitcoinDevKit.swift (100%) rename {Tests => bdk-swift/Tests}/BitcoinDevKitTests/BitcoinDevKitTests.swift (100%) rename {bdkFFI.xcframework => bdk-swift/bdkFFI.xcframework}/Info.plist (100%) rename {bdkFFI.xcframework => bdk-swift/bdkFFI.xcframework}/ios-arm64/bdkFFI.framework/Headers/bdkFFI-umbrella.h (100%) rename {bdkFFI.xcframework => bdk-swift/bdkFFI.xcframework}/ios-arm64/bdkFFI.framework/Modules/module.modulemap (100%) rename {bdkFFI.xcframework => bdk-swift/bdkFFI.xcframework}/ios-arm64_x86_64-simulator/bdkFFI.framework/Headers/bdkFFI-umbrella.h (100%) rename {bdkFFI.xcframework => bdk-swift/bdkFFI.xcframework}/ios-arm64_x86_64-simulator/bdkFFI.framework/Modules/module.modulemap (100%) rename {bdkFFI.xcframework => bdk-swift/bdkFFI.xcframework}/macos-arm64_x86_64/bdkFFI.framework/Headers/bdkFFI-umbrella.h (100%) rename {bdkFFI.xcframework => bdk-swift/bdkFFI.xcframework}/macos-arm64_x86_64/bdkFFI.framework/Modules/module.modulemap (100%) diff --git a/bdk-ffi b/bdk-ffi deleted file mode 160000 index 0648075..0000000 --- a/bdk-ffi +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0648075555b86365e2408fab484782a2b793b545 diff --git a/.github/workflows/publish-spm.yaml b/bdk-swift/.github/workflows/publish-spm.yaml similarity index 100% rename from .github/workflows/publish-spm.yaml rename to bdk-swift/.github/workflows/publish-spm.yaml diff --git a/.gitignore b/bdk-swift/.gitignore similarity index 100% rename from .gitignore rename to bdk-swift/.gitignore diff --git a/.gitmodules b/bdk-swift/.gitmodules similarity index 100% rename from .gitmodules rename to bdk-swift/.gitmodules diff --git a/LICENSE b/bdk-swift/LICENSE similarity index 100% rename from LICENSE rename to bdk-swift/LICENSE diff --git a/LICENSE-APACHE b/bdk-swift/LICENSE-APACHE similarity index 100% rename from LICENSE-APACHE rename to bdk-swift/LICENSE-APACHE diff --git a/LICENSE-MIT b/bdk-swift/LICENSE-MIT similarity index 100% rename from LICENSE-MIT rename to bdk-swift/LICENSE-MIT diff --git a/Package.swift b/bdk-swift/Package.swift similarity index 100% rename from Package.swift rename to bdk-swift/Package.swift diff --git a/Package.swift.txt b/bdk-swift/Package.swift.txt similarity index 100% rename from Package.swift.txt rename to bdk-swift/Package.swift.txt diff --git a/README.md b/bdk-swift/README.md similarity index 100% rename from README.md rename to bdk-swift/README.md diff --git a/Sources/BitcoinDevKit/BitcoinDevKit.swift b/bdk-swift/Sources/BitcoinDevKit/BitcoinDevKit.swift similarity index 100% rename from Sources/BitcoinDevKit/BitcoinDevKit.swift rename to bdk-swift/Sources/BitcoinDevKit/BitcoinDevKit.swift diff --git a/Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift b/bdk-swift/Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift similarity index 100% rename from Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift rename to bdk-swift/Tests/BitcoinDevKitTests/BitcoinDevKitTests.swift diff --git a/bdkFFI.xcframework/Info.plist b/bdk-swift/bdkFFI.xcframework/Info.plist similarity index 100% rename from bdkFFI.xcframework/Info.plist rename to bdk-swift/bdkFFI.xcframework/Info.plist diff --git a/bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Headers/bdkFFI-umbrella.h b/bdk-swift/bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Headers/bdkFFI-umbrella.h similarity index 100% rename from bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Headers/bdkFFI-umbrella.h rename to bdk-swift/bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Headers/bdkFFI-umbrella.h diff --git a/bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Modules/module.modulemap b/bdk-swift/bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Modules/module.modulemap similarity index 100% rename from bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Modules/module.modulemap rename to bdk-swift/bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Modules/module.modulemap diff --git a/bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Headers/bdkFFI-umbrella.h b/bdk-swift/bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Headers/bdkFFI-umbrella.h similarity index 100% rename from bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Headers/bdkFFI-umbrella.h rename to bdk-swift/bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Headers/bdkFFI-umbrella.h diff --git a/bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Modules/module.modulemap b/bdk-swift/bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Modules/module.modulemap similarity index 100% rename from bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Modules/module.modulemap rename to bdk-swift/bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Modules/module.modulemap diff --git a/bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Headers/bdkFFI-umbrella.h b/bdk-swift/bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Headers/bdkFFI-umbrella.h similarity index 100% rename from bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Headers/bdkFFI-umbrella.h rename to bdk-swift/bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Headers/bdkFFI-umbrella.h diff --git a/bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Modules/module.modulemap b/bdk-swift/bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Modules/module.modulemap similarity index 100% rename from bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Modules/module.modulemap rename to bdk-swift/bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Modules/module.modulemap From 97d011acc0cf14fd9348d9c04d8d7f15860d0031 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Mon, 21 Nov 2022 12:59:09 -0600 Subject: [PATCH 31/33] Update README and remove redundant license files --- bdk-swift/LICENSE | 14 --- bdk-swift/LICENSE-APACHE | 201 --------------------------------------- bdk-swift/LICENSE-MIT | 16 ---- bdk-swift/README.md | 40 ++++---- 4 files changed, 22 insertions(+), 249 deletions(-) delete mode 100644 bdk-swift/LICENSE delete mode 100644 bdk-swift/LICENSE-APACHE delete mode 100644 bdk-swift/LICENSE-MIT diff --git a/bdk-swift/LICENSE b/bdk-swift/LICENSE deleted file mode 100644 index 9c61848..0000000 --- a/bdk-swift/LICENSE +++ /dev/null @@ -1,14 +0,0 @@ -This software is licensed under [Apache 2.0](LICENSE-APACHE) or -[MIT](LICENSE-MIT), at your option. - -Some files retain their own copyright notice, however, for full authorship -information, see version control history. - -Except as otherwise noted in individual files, all files in this repository are -licensed under the Apache License, Version 2.0 or the MIT license , at your option. - -You may not use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of this software or any files in this repository except in -accordance with one or both of these licenses. \ No newline at end of file diff --git a/bdk-swift/LICENSE-APACHE b/bdk-swift/LICENSE-APACHE deleted file mode 100644 index 261eeb9..0000000 --- a/bdk-swift/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/bdk-swift/LICENSE-MIT b/bdk-swift/LICENSE-MIT deleted file mode 100644 index 9d982a4..0000000 --- a/bdk-swift/LICENSE-MIT +++ /dev/null @@ -1,16 +0,0 @@ -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/bdk-swift/README.md b/bdk-swift/README.md index 48a9905..e10c8b0 100644 --- a/bdk-swift/README.md +++ b/bdk-swift/README.md @@ -1,41 +1,45 @@ # bdk-swift -This project builds a Swift package that provides [Swift] language bindings for the -[`bdk`] library. The Swift language bindings are created by the [`bdk-ffi`] project which -is included as a git submodule of this repository. +This project builds a Swift package that provides [Swift] language bindings for the +[`bdk`] library. The Swift language bindings are created by the [`bdk-ffi`] project which is included as a module of this repository. ## How to Use -To use the Swift language bindings for [`bdk`] in your [Xcode] iOS or MacOS project add -the github repository (https://github.com/bitcoindevkit/bdk-swift) and select one of the -release versions. You may then import and use the `BitcoinDevKit` library in your Swift +To use the Swift language bindings for [`bdk`] in your [Xcode] iOS or MacOS project add +the github repository https://github.com/bitcoindevkit/bdk-swift and select one of the +release versions. You may then import and use the `BitcoinDevKit` library in your Swift code. For example: ```swift import BitcoinDevKit ... -let desc = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)" -let databaseConfig = DatabaseConfig.memory -let wallet = try Wallet.init(descriptor: desc, changeDescriptor: nil, network: Network.regtest, databaseConfig: databaseConfig) -let addressInfo = try wallet.getAddress(addressIndex: AddressIndex.new) + +``` + +Note: the Swift Package Manager package for `bdk-swift` is located in it's own repository (https://github.com/bitcoindevkit/bdk-swift), and that is where releases are created for it. But the code that generates the bindings is located in the https://github.com/bitcoindevkit/bdk-ffi repo in the `bdk-swift/` directory. + +### How to test + +```shell +swift test ``` ### Example Projects -* [BdkSwiftSample](https://github.com/futurepaul/BdkSwiftSample) +* TBD ## How to Build and Publish -If you are a maintainer of this project or want to build and publish this project to your +If you are a maintainer of this project or want to build and publish this project to your own Github repository use the following steps: -1. If it doesn't already exist, create a new `release/0.MINOR` branch from the `master` branch -2. Run the `publish-spm` workflow on Github for branch `release/0.MINOR` and version `0.MINOR.0` -3. Copy the changelog from corresponding `bdk-ffi` release description to this release +If you are a maintainer of this project or want to build and publish this project to your +own Github repository use the following steps: + +1. If it doesn't already exist, create a new `release/0.MINOR` branch from the `master` branch. +2. Add a tag `v0.MINOR.0`. +3. Run the `publish-spm` workflow on Github from the `bdk-swift` repo for version `0.MINOR.0`. [Swift]: https://developer.apple.com/swift/ [Xcode]: https://developer.apple.com/documentation/Xcode -[`bdk`]: https://github.com/bitcoindevkit/bdk -[`bdk-ffi`]: https://github.com/bitcoindevkit/bdk-ffi -["Getting Started (Developer)"]: https://github.com/bitcoindevkit/bdk-ffi#getting-started-developer From a12b1f8d7a26cde05b8bb299a273d0747ec8498b Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Mon, 21 Nov 2022 13:06:35 -0600 Subject: [PATCH 32/33] Remove unneeded .github and .gitmodules directories --- bdk-swift/.github/workflows/publish-spm.yaml | 113 ------------------- bdk-swift/.gitmodules | 3 - 2 files changed, 116 deletions(-) delete mode 100644 bdk-swift/.github/workflows/publish-spm.yaml delete mode 100644 bdk-swift/.gitmodules diff --git a/bdk-swift/.github/workflows/publish-spm.yaml b/bdk-swift/.github/workflows/publish-spm.yaml deleted file mode 100644 index ffddeb9..0000000 --- a/bdk-swift/.github/workflows/publish-spm.yaml +++ /dev/null @@ -1,113 +0,0 @@ -name: Build, tag and create release -on: - workflow_dispatch: - inputs: - version: - description: 'New release version, eg. 0.MINOR.PATCH' - required: true - type: string - -jobs: - build-publish: - name: Build, tag and create release - runs-on: macos-12 - steps: - - name: Checkout release branch - uses: actions/checkout@v2 - with: - submodules: true - - - name: Cache - uses: actions/cache@v3 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - ./bdk-ffi/target - key: ${{ runner.os }}-${{ hashFiles('**/Cargo.toml','**/Cargo.lock') }} - - - name: Install Rust targets - run: | - rustup install nightly-x86_64-apple-darwin - rustup component add rust-src --toolchain nightly-x86_64-apple-darwin - rustup target add aarch64-apple-ios x86_64-apple-ios - rustup target add aarch64-apple-ios-sim --toolchain nightly - rustup target add aarch64-apple-darwin x86_64-apple-darwin - - - name: Run bdk-ffi-bindgen - working-directory: bdk-ffi - run: | - cargo run --package bdk-ffi-bindgen -- --language swift --out-dir ../Sources/BitcoinDevKit - - - name: Build bdk-ffi for x86_64-apple-darwin - working-directory: bdk-ffi - run: | - cargo build --profile release-smaller --target x86_64-apple-darwin - - - name: Build bdk-ffi for aarch64-apple-darwin - working-directory: bdk-ffi - run: | - cargo build --profile release-smaller --target aarch64-apple-darwin - - - name: Build bdk-ffi for x86_64-apple-ios - working-directory: bdk-ffi - run: | - cargo build --profile release-smaller --target x86_64-apple-ios - - - name: Build bdk-ffi for aarch64-apple-ios - working-directory: bdk-ffi - run: | - cargo build --profile release-smaller --target aarch64-apple-ios - - - name: Build bdk-ffi for aarch64-apple-ios-sim - working-directory: bdk-ffi - run: | - cargo +nightly build --release -Z build-std --target aarch64-apple-ios-sim - - - name: Create lipo-ios-sim and lipo-macos - working-directory: bdk-ffi - run: | - mkdir -p target/lipo-ios-sim/release-smaller - lipo target/aarch64-apple-ios-sim/release/libbdkffi.a target/x86_64-apple-ios/release-smaller/libbdkffi.a -create -output target/lipo-ios-sim/release-smaller/libbdkffi.a - mkdir -p target/lipo-macos/release-smaller - lipo target/aarch64-apple-darwin/release-smaller/libbdkffi.a target/x86_64-apple-darwin/release-smaller/libbdkffi.a -create -output target/lipo-macos/release-smaller/libbdkffi.a - - - name: Create bdkFFI.xcframework - run: | - mv Sources/BitcoinDevKit/bdk.swift Sources/BitcoinDevKit/BitcoinDevKit.swift - cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Headers - cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Headers - cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Headers - cp bdk-ffi/target/aarch64-apple-ios/release-smaller/libbdkffi.a bdkFFI.xcframework/ios-arm64/bdkFFI.framework/bdkFFI - cp bdk-ffi/target/lipo-ios-sim/release-smaller/libbdkffi.a bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/bdkFFI - cp bdk-ffi/target/lipo-macos/release-smaller/libbdkffi.a bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/bdkFFI - rm Sources/BitcoinDevKit/bdkFFI.h - rm Sources/BitcoinDevkit/bdkFFI.modulemap - rm bdkFFI.xcframework.zip || true - zip -9 -r bdkFFI.xcframework.zip bdkFFI.xcframework - echo "BDKFFICHECKSUM=`swift package compute-checksum bdkFFI.xcframework.zip`" >> $GITHUB_ENV - echo "BDKFFIURL=https\:\/\/github\.com\/${{ github.repository_owner }}\/bdk\-swift\/releases\/download\/${{ inputs.version }}\/bdkFFI\.xcframework\.zip" >> $GITHUB_ENV - - - name: Update, commit, and push new Package.swift - run: | - echo checksum = ${{ env.BDKFFICHECKSUM }} - echo url = ${{ env.BDKFFIURL }} - sed "s/BDKFFICHECKSUM/${BDKFFICHECKSUM}/;s/BDKFFIURL/${BDKFFIURL}/" Package.swift.txt > Package.swift - git add Sources/BitcoinDevKit/BitcoinDevKit.swift - git add Package.swift - git commit -m "Update BitcoinDevKit.swift and Package.swift for release ${{ inputs.version }}" - git push - - - name: Tag new release - run: | - git tag ${{ inputs.version }} -m "Release ${{ inputs.version }}" - git push --tags - - - name: Publish release - uses: ncipollo/release-action@v1 - with: - artifacts: "bdkFFI.xcframework.zip" - tag: ${{ inputs.version }} - token: ${{ secrets.GITHUB_TOKEN }} - name: Release ${{ inputs.version }} - prerelease: true diff --git a/bdk-swift/.gitmodules b/bdk-swift/.gitmodules deleted file mode 100644 index 96bdc69..0000000 --- a/bdk-swift/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "bdk-ffi"] - path = bdk-ffi - url = https://github.com/bitcoindevkit/bdk-ffi.git From 07f5b5f8ba64d38798166cf8a341964522303da1 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Mon, 21 Nov 2022 13:08:31 -0600 Subject: [PATCH 33/33] Remove autogenerated BitcoinDevKit.swift --- .../Sources/BitcoinDevKit/BitcoinDevKit.swift | 3379 ----------------- 1 file changed, 3379 deletions(-) delete mode 100644 bdk-swift/Sources/BitcoinDevKit/BitcoinDevKit.swift diff --git a/bdk-swift/Sources/BitcoinDevKit/BitcoinDevKit.swift b/bdk-swift/Sources/BitcoinDevKit/BitcoinDevKit.swift deleted file mode 100644 index 9ab21b7..0000000 --- a/bdk-swift/Sources/BitcoinDevKit/BitcoinDevKit.swift +++ /dev/null @@ -1,3379 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! -import Foundation - -// Depending on the consumer's build setup, the low-level FFI code -// might be in a separate module, or it might be compiled inline into -// this module. This is a bit of light hackery to work with both. -#if canImport(bdkFFI) -import bdkFFI -#endif - -fileprivate extension RustBuffer { - // Allocate a new buffer, copying the contents of a `UInt8` array. - init(bytes: [UInt8]) { - let rbuf = bytes.withUnsafeBufferPointer { ptr in - RustBuffer.from(ptr) - } - self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) - } - - static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { - try! rustCall { ffi_bdk_1724_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } - } - - // Frees the buffer in place. - // The buffer must not be used after this is called. - func deallocate() { - try! rustCall { ffi_bdk_1724_rustbuffer_free(self, $0) } - } -} - -fileprivate extension ForeignBytes { - init(bufferPointer: UnsafeBufferPointer) { - self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) - } -} - -// For every type used in the interface, we provide helper methods for conveniently -// lifting and lowering that type from C-compatible data, and for reading and writing -// values of that type in a buffer. - -// Helper classes/extensions that don't change. -// Someday, this will be in a libray of its own. - -fileprivate extension Data { - init(rustBuffer: RustBuffer) { - // TODO: This copies the buffer. Can we read directly from a - // Rust buffer? - self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len)) - } -} - -// A helper class to read values out of a byte buffer. -fileprivate class Reader { - let data: Data - var offset: Data.Index - - init(data: Data) { - self.data = data - self.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. - func readInt() throws -> T { - let range = offset...size - guard data.count >= range.upperBound else { - throw UniffiInternalError.bufferOverflow - } - if T.self == UInt8.self { - let value = data[offset] - offset += 1 - return value as! T - } - var value: T = 0 - let _ = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0, from: range)}) - offset = range.upperBound - return value.bigEndian - } - - // Reads an arbitrary number of bytes, to be used to read - // raw bytes, this is useful when lifting strings - func readBytes(count: Int) throws -> Array { - let range = offset..<(offset+count) - guard data.count >= range.upperBound else { - throw UniffiInternalError.bufferOverflow - } - var value = [UInt8](repeating: 0, count: count) - value.withUnsafeMutableBufferPointer({ buffer in - data.copyBytes(to: buffer, from: range) - }) - offset = range.upperBound - return value - } - - // Reads a float at the current offset. - @inlinable - func readFloat() throws -> Float { - return Float(bitPattern: try readInt()) - } - - // Reads a float at the current offset. - @inlinable - func readDouble() throws -> Double { - return Double(bitPattern: try readInt()) - } - - // Indicates if the offset has reached the end of the buffer. - @inlinable - func hasRemaining() -> Bool { - return offset < data.count - } -} - -// A helper class to write values into a byte buffer. -fileprivate class Writer { - var bytes: [UInt8] - var offset: Array.Index - - init() { - self.bytes = [] - self.offset = 0 - } - - func writeBytes(_ byteArr: S) where S: Sequence, S.Element == UInt8 { - bytes.append(contentsOf: byteArr) - } - - // Writes an integer in big-endian order. - // - // Warning: make sure what you are trying to write - // is in the correct type! - func writeInt(_ value: T) { - var value = value.bigEndian - withUnsafeBytes(of: &value) { bytes.append(contentsOf: $0) } - } - - @inlinable - func writeFloat(_ value: Float) { - writeInt(value.bitPattern) - } - - @inlinable - func writeDouble(_ value: Double) { - writeInt(value.bitPattern) - } -} - -// Protocol for types that transfer other types across the FFI. This is -// analogous go the Rust trait of the same name. -fileprivate protocol FfiConverter { - associatedtype FfiType - associatedtype SwiftType - - static func lift(_ value: FfiType) throws -> SwiftType - static func lower(_ value: SwiftType) -> FfiType - static func read(from buf: Reader) throws -> SwiftType - static func write(_ value: SwiftType, into buf: Writer) -} - -// Types conforming to `Primitive` pass themselves directly over the FFI. -fileprivate protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType { } - -extension FfiConverterPrimitive { - static func lift(_ value: FfiType) throws -> SwiftType { - return value - } - - static func lower(_ value: SwiftType) -> FfiType { - return value - } -} - -// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. -// Used for complex types where it's hard to write a custom lift/lower. -fileprivate protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} - -extension FfiConverterRustBuffer { - static func lift(_ buf: RustBuffer) throws -> SwiftType { - let reader = Reader(data: Data(rustBuffer: buf)) - let value = try read(from: reader) - if reader.hasRemaining() { - throw UniffiInternalError.incompleteData - } - buf.deallocate() - return value - } - - static func lower(_ value: SwiftType) -> RustBuffer { - let writer = Writer() - write(value, into: writer) - return RustBuffer(bytes: writer.bytes) - } -} -// An error type for FFI errors. These errors occur at the UniFFI level, not -// the library level. -fileprivate enum UniffiInternalError: LocalizedError { - case bufferOverflow - case incompleteData - case unexpectedOptionalTag - case unexpectedEnumCase - case unexpectedNullPointer - case unexpectedRustCallStatusCode - case unexpectedRustCallError - case unexpectedStaleHandle - case rustPanic(_ message: String) - - public var errorDescription: String? { - switch self { - case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" - case .incompleteData: return "The buffer still has data after lifting its containing value" - case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1" - case .unexpectedEnumCase: return "Raw enum value doesn't match any cases" - case .unexpectedNullPointer: return "Raw pointer value was null" - case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code" - case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified" - case .unexpectedStaleHandle: return "The object in the handle map has been dropped already" - case let .rustPanic(message): return message - } - } -} - -fileprivate let CALL_SUCCESS: Int8 = 0 -fileprivate let CALL_ERROR: Int8 = 1 -fileprivate let CALL_PANIC: Int8 = 2 - -fileprivate extension RustCallStatus { - init() { - self.init( - code: CALL_SUCCESS, - errorBuf: RustBuffer.init( - capacity: 0, - len: 0, - data: nil - ) - ) - } -} - -private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T { - try makeRustCall(callback, errorHandler: { - $0.deallocate() - return UniffiInternalError.unexpectedRustCallError - }) -} - -private func rustCallWithError - (_ errorFfiConverter: F.Type, _ callback: (UnsafeMutablePointer) -> T) throws -> T - where F.SwiftType: Error, F.FfiType == RustBuffer - { - try makeRustCall(callback, errorHandler: { return try errorFfiConverter.lift($0) }) -} - -private func makeRustCall(_ callback: (UnsafeMutablePointer) -> T, errorHandler: (RustBuffer) throws -> Error) throws -> T { - var callStatus = RustCallStatus.init() - let returnedVal = callback(&callStatus) - switch callStatus.code { - case CALL_SUCCESS: - return returnedVal - - case CALL_ERROR: - throw try errorHandler(callStatus.errorBuf) - - case CALL_PANIC: - // When the rust code sees a panic, it tries to construct a RustBuffer - // with the message. But if that code panics, then it just sends back - // an empty buffer. - if callStatus.errorBuf.len > 0 { - throw UniffiInternalError.rustPanic(try FfiConverterString.lift(callStatus.errorBuf)) - } else { - callStatus.errorBuf.deallocate() - throw UniffiInternalError.rustPanic("Rust panic") - } - - default: - throw UniffiInternalError.unexpectedRustCallStatusCode - } -} - -// Public interface members begin here. - - -fileprivate struct FfiConverterUInt8: FfiConverterPrimitive { - typealias FfiType = UInt8 - typealias SwiftType = UInt8 - - static func read(from buf: Reader) throws -> UInt8 { - return try lift(buf.readInt()) - } - - static func write(_ value: UInt8, into buf: Writer) { - buf.writeInt(lower(value)) - } -} - -fileprivate struct FfiConverterUInt32: FfiConverterPrimitive { - typealias FfiType = UInt32 - typealias SwiftType = UInt32 - - static func read(from buf: Reader) throws -> UInt32 { - return try lift(buf.readInt()) - } - - static func write(_ value: SwiftType, into buf: Writer) { - buf.writeInt(lower(value)) - } -} - -fileprivate struct FfiConverterUInt64: FfiConverterPrimitive { - typealias FfiType = UInt64 - typealias SwiftType = UInt64 - - static func read(from buf: Reader) throws -> UInt64 { - return try lift(buf.readInt()) - } - - static func write(_ value: SwiftType, into buf: Writer) { - buf.writeInt(lower(value)) - } -} - -fileprivate struct FfiConverterFloat: FfiConverterPrimitive { - typealias FfiType = Float - typealias SwiftType = Float - - static func read(from buf: Reader) throws -> Float { - return try lift(buf.readFloat()) - } - - static func write(_ value: Float, into buf: Writer) { - buf.writeFloat(lower(value)) - } -} - -fileprivate struct FfiConverterBool : FfiConverter { - typealias FfiType = Int8 - typealias SwiftType = Bool - - static func lift(_ value: Int8) throws -> Bool { - return value != 0 - } - - static func lower(_ value: Bool) -> Int8 { - return value ? 1 : 0 - } - - static func read(from buf: Reader) throws -> Bool { - return try lift(buf.readInt()) - } - - static func write(_ value: Bool, into buf: Writer) { - buf.writeInt(lower(value)) - } -} - -fileprivate struct FfiConverterString: FfiConverter { - typealias SwiftType = String - typealias FfiType = RustBuffer - - static func lift(_ value: RustBuffer) throws -> String { - defer { - value.deallocate() - } - if value.data == nil { - return String() - } - let bytes = UnsafeBufferPointer(start: value.data!, count: Int(value.len)) - return String(bytes: bytes, encoding: String.Encoding.utf8)! - } - - static func lower(_ value: String) -> RustBuffer { - return value.utf8CString.withUnsafeBufferPointer { ptr in - // The swift string gives us int8_t, we want uint8_t. - ptr.withMemoryRebound(to: UInt8.self) { ptr in - // The swift string gives us a trailing null byte, we don't want it. - let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) - return RustBuffer.from(buf) - } - } - } - - static func read(from buf: Reader) throws -> String { - let len: Int32 = try buf.readInt() - return String(bytes: try buf.readBytes(count: Int(len)), encoding: String.Encoding.utf8)! - } - - static func write(_ value: String, into buf: Writer) { - let len = Int32(value.utf8.count) - buf.writeInt(len) - buf.writeBytes(value.utf8) - } -} - - -public protocol AddressProtocol { - func `scriptPubkey`() -> Script - -} - -public class Address: AddressProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `FfiConverter` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init(`address`: String) throws { - self.init(unsafeFromRawPointer: try - - rustCallWithError(FfiConverterTypeBdkError.self) { - - bdk_1724_Address_new( - FfiConverterString.lower(`address`), $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_1724_Address_object_free(pointer, $0) } - } - - - - - public func `scriptPubkey`() -> Script { - return try! FfiConverterTypeScript.lift( - try! - rustCall() { - - bdk_1724_Address_script_pubkey(self.pointer, $0 - ) -} - ) - } - -} - - -fileprivate struct FfiConverterTypeAddress: FfiConverter { - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = Address - - static func read(from buf: Reader) throws -> Address { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try lift(ptr!) - } - - static func write(_ value: Address, into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) - } - - static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Address { - return Address(unsafeFromRawPointer: pointer) - } - - static func lower(_ value: Address) -> UnsafeMutableRawPointer { - return value.pointer - } -} - - -public protocol BlockchainProtocol { - func `broadcast`(`psbt`: PartiallySignedBitcoinTransaction) throws - func `getHeight`() throws -> UInt32 - func `getBlockHash`(`height`: UInt32) throws -> String - -} - -public class Blockchain: BlockchainProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `FfiConverter` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init(`config`: BlockchainConfig) throws { - self.init(unsafeFromRawPointer: try - - rustCallWithError(FfiConverterTypeBdkError.self) { - - bdk_1724_Blockchain_new( - FfiConverterTypeBlockchainConfig.lower(`config`), $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_1724_Blockchain_object_free(pointer, $0) } - } - - - - - public func `broadcast`(`psbt`: PartiallySignedBitcoinTransaction) throws { - try - rustCallWithError(FfiConverterTypeBdkError.self) { - bdk_1724_Blockchain_broadcast(self.pointer, - FfiConverterTypePartiallySignedBitcoinTransaction.lower(`psbt`), $0 - ) -} - } - public func `getHeight`() throws -> UInt32 { - return try FfiConverterUInt32.lift( - try - rustCallWithError(FfiConverterTypeBdkError.self) { - bdk_1724_Blockchain_get_height(self.pointer, $0 - ) -} - ) - } - public func `getBlockHash`(`height`: UInt32) throws -> String { - return try FfiConverterString.lift( - try - rustCallWithError(FfiConverterTypeBdkError.self) { - bdk_1724_Blockchain_get_block_hash(self.pointer, - FfiConverterUInt32.lower(`height`), $0 - ) -} - ) - } - -} - - -fileprivate struct FfiConverterTypeBlockchain: FfiConverter { - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = Blockchain - - static func read(from buf: Reader) throws -> Blockchain { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try lift(ptr!) - } - - static func write(_ value: Blockchain, into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) - } - - static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Blockchain { - return Blockchain(unsafeFromRawPointer: pointer) - } - - static func lower(_ value: Blockchain) -> UnsafeMutableRawPointer { - return value.pointer - } -} - - -public protocol BumpFeeTxBuilderProtocol { - func `allowShrinking`(`address`: String) -> BumpFeeTxBuilder - func `enableRbf`() -> BumpFeeTxBuilder - func `enableRbfWithSequence`(`nsequence`: UInt32) -> BumpFeeTxBuilder - func `finish`(`wallet`: Wallet) throws -> PartiallySignedBitcoinTransaction - -} - -public class BumpFeeTxBuilder: BumpFeeTxBuilderProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `FfiConverter` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init(`txid`: String, `newFeeRate`: Float) { - self.init(unsafeFromRawPointer: try! - - rustCall() { - - bdk_1724_BumpFeeTxBuilder_new( - FfiConverterString.lower(`txid`), - FfiConverterFloat.lower(`newFeeRate`), $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_1724_BumpFeeTxBuilder_object_free(pointer, $0) } - } - - - - - public func `allowShrinking`(`address`: String) -> BumpFeeTxBuilder { - return try! FfiConverterTypeBumpFeeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_BumpFeeTxBuilder_allow_shrinking(self.pointer, - FfiConverterString.lower(`address`), $0 - ) -} - ) - } - public func `enableRbf`() -> BumpFeeTxBuilder { - return try! FfiConverterTypeBumpFeeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_BumpFeeTxBuilder_enable_rbf(self.pointer, $0 - ) -} - ) - } - public func `enableRbfWithSequence`(`nsequence`: UInt32) -> BumpFeeTxBuilder { - return try! FfiConverterTypeBumpFeeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_BumpFeeTxBuilder_enable_rbf_with_sequence(self.pointer, - FfiConverterUInt32.lower(`nsequence`), $0 - ) -} - ) - } - public func `finish`(`wallet`: Wallet) throws -> PartiallySignedBitcoinTransaction { - return try FfiConverterTypePartiallySignedBitcoinTransaction.lift( - try - rustCallWithError(FfiConverterTypeBdkError.self) { - bdk_1724_BumpFeeTxBuilder_finish(self.pointer, - FfiConverterTypeWallet.lower(`wallet`), $0 - ) -} - ) - } - -} - - -fileprivate struct FfiConverterTypeBumpFeeTxBuilder: FfiConverter { - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = BumpFeeTxBuilder - - static func read(from buf: Reader) throws -> BumpFeeTxBuilder { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try lift(ptr!) - } - - static func write(_ value: BumpFeeTxBuilder, into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) - } - - static func lift(_ pointer: UnsafeMutableRawPointer) throws -> BumpFeeTxBuilder { - return BumpFeeTxBuilder(unsafeFromRawPointer: pointer) - } - - static func lower(_ value: BumpFeeTxBuilder) -> UnsafeMutableRawPointer { - return value.pointer - } -} - - -public protocol DerivationPathProtocol { - -} - -public class DerivationPath: DerivationPathProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `FfiConverter` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init(`path`: String) throws { - self.init(unsafeFromRawPointer: try - - rustCallWithError(FfiConverterTypeBdkError.self) { - - bdk_1724_DerivationPath_new( - FfiConverterString.lower(`path`), $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_1724_DerivationPath_object_free(pointer, $0) } - } - - - - - -} - - -fileprivate struct FfiConverterTypeDerivationPath: FfiConverter { - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = DerivationPath - - static func read(from buf: Reader) throws -> DerivationPath { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try lift(ptr!) - } - - static func write(_ value: DerivationPath, into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) - } - - static func lift(_ pointer: UnsafeMutableRawPointer) throws -> DerivationPath { - return DerivationPath(unsafeFromRawPointer: pointer) - } - - static func lower(_ value: DerivationPath) -> UnsafeMutableRawPointer { - return value.pointer - } -} - - -public protocol DescriptorPublicKeyProtocol { - func `derive`(`path`: DerivationPath) throws -> DescriptorPublicKey - func `extend`(`path`: DerivationPath) -> DescriptorPublicKey - func `asString`() -> String - -} - -public class DescriptorPublicKey: DescriptorPublicKeyProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `FfiConverter` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - - deinit { - try! rustCall { ffi_bdk_1724_DescriptorPublicKey_object_free(pointer, $0) } - } - - - - - public func `derive`(`path`: DerivationPath) throws -> DescriptorPublicKey { - return try FfiConverterTypeDescriptorPublicKey.lift( - try - rustCallWithError(FfiConverterTypeBdkError.self) { - bdk_1724_DescriptorPublicKey_derive(self.pointer, - FfiConverterTypeDerivationPath.lower(`path`), $0 - ) -} - ) - } - public func `extend`(`path`: DerivationPath) -> DescriptorPublicKey { - return try! FfiConverterTypeDescriptorPublicKey.lift( - try! - rustCall() { - - bdk_1724_DescriptorPublicKey_extend(self.pointer, - FfiConverterTypeDerivationPath.lower(`path`), $0 - ) -} - ) - } - public func `asString`() -> String { - return try! FfiConverterString.lift( - try! - rustCall() { - - bdk_1724_DescriptorPublicKey_as_string(self.pointer, $0 - ) -} - ) - } - -} - - -fileprivate struct FfiConverterTypeDescriptorPublicKey: FfiConverter { - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = DescriptorPublicKey - - static func read(from buf: Reader) throws -> DescriptorPublicKey { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try lift(ptr!) - } - - static func write(_ value: DescriptorPublicKey, into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) - } - - static func lift(_ pointer: UnsafeMutableRawPointer) throws -> DescriptorPublicKey { - return DescriptorPublicKey(unsafeFromRawPointer: pointer) - } - - static func lower(_ value: DescriptorPublicKey) -> UnsafeMutableRawPointer { - return value.pointer - } -} - - -public protocol DescriptorSecretKeyProtocol { - func `derive`(`path`: DerivationPath) throws -> DescriptorSecretKey - func `extend`(`path`: DerivationPath) -> DescriptorSecretKey - func `asPublic`() -> DescriptorPublicKey - func `secretBytes`() -> [UInt8] - func `asString`() -> String - -} - -public class DescriptorSecretKey: DescriptorSecretKeyProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `FfiConverter` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init(`network`: Network, `mnemonic`: String, `password`: String?) throws { - self.init(unsafeFromRawPointer: try - - rustCallWithError(FfiConverterTypeBdkError.self) { - - bdk_1724_DescriptorSecretKey_new( - FfiConverterTypeNetwork.lower(`network`), - FfiConverterString.lower(`mnemonic`), - FfiConverterOptionString.lower(`password`), $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_1724_DescriptorSecretKey_object_free(pointer, $0) } - } - - - - - public func `derive`(`path`: DerivationPath) throws -> DescriptorSecretKey { - return try FfiConverterTypeDescriptorSecretKey.lift( - try - rustCallWithError(FfiConverterTypeBdkError.self) { - bdk_1724_DescriptorSecretKey_derive(self.pointer, - FfiConverterTypeDerivationPath.lower(`path`), $0 - ) -} - ) - } - public func `extend`(`path`: DerivationPath) -> DescriptorSecretKey { - return try! FfiConverterTypeDescriptorSecretKey.lift( - try! - rustCall() { - - bdk_1724_DescriptorSecretKey_extend(self.pointer, - FfiConverterTypeDerivationPath.lower(`path`), $0 - ) -} - ) - } - public func `asPublic`() -> DescriptorPublicKey { - return try! FfiConverterTypeDescriptorPublicKey.lift( - try! - rustCall() { - - bdk_1724_DescriptorSecretKey_as_public(self.pointer, $0 - ) -} - ) - } - public func `secretBytes`() -> [UInt8] { - return try! FfiConverterSequenceUInt8.lift( - try! - rustCall() { - - bdk_1724_DescriptorSecretKey_secret_bytes(self.pointer, $0 - ) -} - ) - } - public func `asString`() -> String { - return try! FfiConverterString.lift( - try! - rustCall() { - - bdk_1724_DescriptorSecretKey_as_string(self.pointer, $0 - ) -} - ) - } - -} - - -fileprivate struct FfiConverterTypeDescriptorSecretKey: FfiConverter { - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = DescriptorSecretKey - - static func read(from buf: Reader) throws -> DescriptorSecretKey { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try lift(ptr!) - } - - static func write(_ value: DescriptorSecretKey, into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) - } - - static func lift(_ pointer: UnsafeMutableRawPointer) throws -> DescriptorSecretKey { - return DescriptorSecretKey(unsafeFromRawPointer: pointer) - } - - static func lower(_ value: DescriptorSecretKey) -> UnsafeMutableRawPointer { - return value.pointer - } -} - - -public protocol PartiallySignedBitcoinTransactionProtocol { - func `serialize`() -> String - func `txid`() -> String - func `extractTx`() -> [UInt8] - func `combine`(`other`: PartiallySignedBitcoinTransaction) throws -> PartiallySignedBitcoinTransaction - -} - -public class PartiallySignedBitcoinTransaction: PartiallySignedBitcoinTransactionProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `FfiConverter` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init(`psbtBase64`: String) throws { - self.init(unsafeFromRawPointer: try - - rustCallWithError(FfiConverterTypeBdkError.self) { - - bdk_1724_PartiallySignedBitcoinTransaction_new( - FfiConverterString.lower(`psbtBase64`), $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_1724_PartiallySignedBitcoinTransaction_object_free(pointer, $0) } - } - - - - - public func `serialize`() -> String { - return try! FfiConverterString.lift( - try! - rustCall() { - - bdk_1724_PartiallySignedBitcoinTransaction_serialize(self.pointer, $0 - ) -} - ) - } - public func `txid`() -> String { - return try! FfiConverterString.lift( - try! - rustCall() { - - bdk_1724_PartiallySignedBitcoinTransaction_txid(self.pointer, $0 - ) -} - ) - } - public func `extractTx`() -> [UInt8] { - return try! FfiConverterSequenceUInt8.lift( - try! - rustCall() { - - bdk_1724_PartiallySignedBitcoinTransaction_extract_tx(self.pointer, $0 - ) -} - ) - } - public func `combine`(`other`: PartiallySignedBitcoinTransaction) throws -> PartiallySignedBitcoinTransaction { - return try FfiConverterTypePartiallySignedBitcoinTransaction.lift( - try - rustCallWithError(FfiConverterTypeBdkError.self) { - bdk_1724_PartiallySignedBitcoinTransaction_combine(self.pointer, - FfiConverterTypePartiallySignedBitcoinTransaction.lower(`other`), $0 - ) -} - ) - } - -} - - -fileprivate struct FfiConverterTypePartiallySignedBitcoinTransaction: FfiConverter { - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = PartiallySignedBitcoinTransaction - - static func read(from buf: Reader) throws -> PartiallySignedBitcoinTransaction { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try lift(ptr!) - } - - static func write(_ value: PartiallySignedBitcoinTransaction, into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) - } - - static func lift(_ pointer: UnsafeMutableRawPointer) throws -> PartiallySignedBitcoinTransaction { - return PartiallySignedBitcoinTransaction(unsafeFromRawPointer: pointer) - } - - static func lower(_ value: PartiallySignedBitcoinTransaction) -> UnsafeMutableRawPointer { - return value.pointer - } -} - - -public protocol ScriptProtocol { - -} - -public class Script: ScriptProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `FfiConverter` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init(`rawOutputScript`: [UInt8]) { - self.init(unsafeFromRawPointer: try! - - rustCall() { - - bdk_1724_Script_new( - FfiConverterSequenceUInt8.lower(`rawOutputScript`), $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_1724_Script_object_free(pointer, $0) } - } - - - - - -} - - -fileprivate struct FfiConverterTypeScript: FfiConverter { - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = Script - - static func read(from buf: Reader) throws -> Script { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try lift(ptr!) - } - - static func write(_ value: Script, into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) - } - - static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Script { - return Script(unsafeFromRawPointer: pointer) - } - - static func lower(_ value: Script) -> UnsafeMutableRawPointer { - return value.pointer - } -} - - -public protocol TxBuilderProtocol { - func `addRecipient`(`script`: Script, `amount`: UInt64) -> TxBuilder - func `addUnspendable`(`unspendable`: OutPoint) -> TxBuilder - func `addUtxo`(`outpoint`: OutPoint) -> TxBuilder - func `addUtxos`(`outpoints`: [OutPoint]) -> TxBuilder - func `doNotSpendChange`() -> TxBuilder - func `manuallySelectedOnly`() -> TxBuilder - func `onlySpendChange`() -> TxBuilder - func `unspendable`(`unspendable`: [OutPoint]) -> TxBuilder - func `feeRate`(`satPerVbyte`: Float) -> TxBuilder - func `feeAbsolute`(`feeAmount`: UInt64) -> TxBuilder - func `drainWallet`() -> TxBuilder - func `drainTo`(`address`: String) -> TxBuilder - func `enableRbf`() -> TxBuilder - func `enableRbfWithSequence`(`nsequence`: UInt32) -> TxBuilder - func `addData`(`data`: [UInt8]) -> TxBuilder - func `setRecipients`(`recipients`: [ScriptAmount]) -> TxBuilder - func `finish`(`wallet`: Wallet) throws -> TxBuilderResult - -} - -public class TxBuilder: TxBuilderProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `FfiConverter` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init() { - self.init(unsafeFromRawPointer: try! - - rustCall() { - - bdk_1724_TxBuilder_new($0) -}) - } - - deinit { - try! rustCall { ffi_bdk_1724_TxBuilder_object_free(pointer, $0) } - } - - - - - public func `addRecipient`(`script`: Script, `amount`: UInt64) -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_add_recipient(self.pointer, - FfiConverterTypeScript.lower(`script`), - FfiConverterUInt64.lower(`amount`), $0 - ) -} - ) - } - public func `addUnspendable`(`unspendable`: OutPoint) -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_add_unspendable(self.pointer, - FfiConverterTypeOutPoint.lower(`unspendable`), $0 - ) -} - ) - } - public func `addUtxo`(`outpoint`: OutPoint) -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_add_utxo(self.pointer, - FfiConverterTypeOutPoint.lower(`outpoint`), $0 - ) -} - ) - } - public func `addUtxos`(`outpoints`: [OutPoint]) -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_add_utxos(self.pointer, - FfiConverterSequenceTypeOutPoint.lower(`outpoints`), $0 - ) -} - ) - } - public func `doNotSpendChange`() -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_do_not_spend_change(self.pointer, $0 - ) -} - ) - } - public func `manuallySelectedOnly`() -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_manually_selected_only(self.pointer, $0 - ) -} - ) - } - public func `onlySpendChange`() -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_only_spend_change(self.pointer, $0 - ) -} - ) - } - public func `unspendable`(`unspendable`: [OutPoint]) -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_unspendable(self.pointer, - FfiConverterSequenceTypeOutPoint.lower(`unspendable`), $0 - ) -} - ) - } - public func `feeRate`(`satPerVbyte`: Float) -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_fee_rate(self.pointer, - FfiConverterFloat.lower(`satPerVbyte`), $0 - ) -} - ) - } - public func `feeAbsolute`(`feeAmount`: UInt64) -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_fee_absolute(self.pointer, - FfiConverterUInt64.lower(`feeAmount`), $0 - ) -} - ) - } - public func `drainWallet`() -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_drain_wallet(self.pointer, $0 - ) -} - ) - } - public func `drainTo`(`address`: String) -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_drain_to(self.pointer, - FfiConverterString.lower(`address`), $0 - ) -} - ) - } - public func `enableRbf`() -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_enable_rbf(self.pointer, $0 - ) -} - ) - } - public func `enableRbfWithSequence`(`nsequence`: UInt32) -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_enable_rbf_with_sequence(self.pointer, - FfiConverterUInt32.lower(`nsequence`), $0 - ) -} - ) - } - public func `addData`(`data`: [UInt8]) -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_add_data(self.pointer, - FfiConverterSequenceUInt8.lower(`data`), $0 - ) -} - ) - } - public func `setRecipients`(`recipients`: [ScriptAmount]) -> TxBuilder { - return try! FfiConverterTypeTxBuilder.lift( - try! - rustCall() { - - bdk_1724_TxBuilder_set_recipients(self.pointer, - FfiConverterSequenceTypeScriptAmount.lower(`recipients`), $0 - ) -} - ) - } - public func `finish`(`wallet`: Wallet) throws -> TxBuilderResult { - return try FfiConverterTypeTxBuilderResult.lift( - try - rustCallWithError(FfiConverterTypeBdkError.self) { - bdk_1724_TxBuilder_finish(self.pointer, - FfiConverterTypeWallet.lower(`wallet`), $0 - ) -} - ) - } - -} - - -fileprivate struct FfiConverterTypeTxBuilder: FfiConverter { - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = TxBuilder - - static func read(from buf: Reader) throws -> TxBuilder { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try lift(ptr!) - } - - static func write(_ value: TxBuilder, into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) - } - - static func lift(_ pointer: UnsafeMutableRawPointer) throws -> TxBuilder { - return TxBuilder(unsafeFromRawPointer: pointer) - } - - static func lower(_ value: TxBuilder) -> UnsafeMutableRawPointer { - return value.pointer - } -} - - -public protocol WalletProtocol { - func `getAddress`(`addressIndex`: AddressIndex) throws -> AddressInfo - func `getBalance`() throws -> Balance - func `sign`(`psbt`: PartiallySignedBitcoinTransaction) throws -> Bool - func `listTransactions`() throws -> [TransactionDetails] - func `network`() -> Network - func `sync`(`blockchain`: Blockchain, `progress`: Progress?) throws - func `listUnspent`() throws -> [LocalUtxo] - -} - -public class Wallet: WalletProtocol { - fileprivate let pointer: UnsafeMutableRawPointer - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `FfiConverter` without making this `required` and we can't - // make it `required` without making it `public`. - required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - public convenience init(`descriptor`: String, `changeDescriptor`: String?, `network`: Network, `databaseConfig`: DatabaseConfig) throws { - self.init(unsafeFromRawPointer: try - - rustCallWithError(FfiConverterTypeBdkError.self) { - - bdk_1724_Wallet_new( - FfiConverterString.lower(`descriptor`), - FfiConverterOptionString.lower(`changeDescriptor`), - FfiConverterTypeNetwork.lower(`network`), - FfiConverterTypeDatabaseConfig.lower(`databaseConfig`), $0) -}) - } - - deinit { - try! rustCall { ffi_bdk_1724_Wallet_object_free(pointer, $0) } - } - - - - - public func `getAddress`(`addressIndex`: AddressIndex) throws -> AddressInfo { - return try FfiConverterTypeAddressInfo.lift( - try - rustCallWithError(FfiConverterTypeBdkError.self) { - bdk_1724_Wallet_get_address(self.pointer, - FfiConverterTypeAddressIndex.lower(`addressIndex`), $0 - ) -} - ) - } - public func `getBalance`() throws -> Balance { - return try FfiConverterTypeBalance.lift( - try - rustCallWithError(FfiConverterTypeBdkError.self) { - bdk_1724_Wallet_get_balance(self.pointer, $0 - ) -} - ) - } - public func `sign`(`psbt`: PartiallySignedBitcoinTransaction) throws -> Bool { - return try FfiConverterBool.lift( - try - rustCallWithError(FfiConverterTypeBdkError.self) { - bdk_1724_Wallet_sign(self.pointer, - FfiConverterTypePartiallySignedBitcoinTransaction.lower(`psbt`), $0 - ) -} - ) - } - public func `listTransactions`() throws -> [TransactionDetails] { - return try FfiConverterSequenceTypeTransactionDetails.lift( - try - rustCallWithError(FfiConverterTypeBdkError.self) { - bdk_1724_Wallet_list_transactions(self.pointer, $0 - ) -} - ) - } - public func `network`() -> Network { - return try! FfiConverterTypeNetwork.lift( - try! - rustCall() { - - bdk_1724_Wallet_network(self.pointer, $0 - ) -} - ) - } - public func `sync`(`blockchain`: Blockchain, `progress`: Progress?) throws { - try - rustCallWithError(FfiConverterTypeBdkError.self) { - bdk_1724_Wallet_sync(self.pointer, - FfiConverterTypeBlockchain.lower(`blockchain`), - FfiConverterOptionCallbackInterfaceProgress.lower(`progress`), $0 - ) -} - } - public func `listUnspent`() throws -> [LocalUtxo] { - return try FfiConverterSequenceTypeLocalUtxo.lift( - try - rustCallWithError(FfiConverterTypeBdkError.self) { - bdk_1724_Wallet_list_unspent(self.pointer, $0 - ) -} - ) - } - -} - - -fileprivate struct FfiConverterTypeWallet: FfiConverter { - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = Wallet - - static func read(from buf: Reader) throws -> Wallet { - let v: UInt64 = try buf.readInt() - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try lift(ptr!) - } - - static func write(_ value: Wallet, into buf: Writer) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) - } - - static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Wallet { - return Wallet(unsafeFromRawPointer: pointer) - } - - static func lower(_ value: Wallet) -> UnsafeMutableRawPointer { - return value.pointer - } -} - - -public struct AddressInfo { - public var `index`: UInt32 - public var `address`: String - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(`index`: UInt32, `address`: String) { - self.`index` = `index` - self.`address` = `address` - } -} - - -extension AddressInfo: Equatable, Hashable { - public static func ==(lhs: AddressInfo, rhs: AddressInfo) -> Bool { - if lhs.`index` != rhs.`index` { - return false - } - if lhs.`address` != rhs.`address` { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(`index`) - hasher.combine(`address`) - } -} - - -fileprivate struct FfiConverterTypeAddressInfo: FfiConverterRustBuffer { - fileprivate static func read(from buf: Reader) throws -> AddressInfo { - return try AddressInfo( - `index`: FfiConverterUInt32.read(from: buf), - `address`: FfiConverterString.read(from: buf) - ) - } - - fileprivate static func write(_ value: AddressInfo, into buf: Writer) { - FfiConverterUInt32.write(value.`index`, into: buf) - FfiConverterString.write(value.`address`, into: buf) - } -} - - -public struct Balance { - public var `immature`: UInt64 - public var `trustedPending`: UInt64 - public var `untrustedPending`: UInt64 - public var `confirmed`: UInt64 - public var `spendable`: UInt64 - public var `total`: UInt64 - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(`immature`: UInt64, `trustedPending`: UInt64, `untrustedPending`: UInt64, `confirmed`: UInt64, `spendable`: UInt64, `total`: UInt64) { - self.`immature` = `immature` - self.`trustedPending` = `trustedPending` - self.`untrustedPending` = `untrustedPending` - self.`confirmed` = `confirmed` - self.`spendable` = `spendable` - self.`total` = `total` - } -} - - -extension Balance: Equatable, Hashable { - public static func ==(lhs: Balance, rhs: Balance) -> Bool { - if lhs.`immature` != rhs.`immature` { - return false - } - if lhs.`trustedPending` != rhs.`trustedPending` { - return false - } - if lhs.`untrustedPending` != rhs.`untrustedPending` { - return false - } - if lhs.`confirmed` != rhs.`confirmed` { - return false - } - if lhs.`spendable` != rhs.`spendable` { - return false - } - if lhs.`total` != rhs.`total` { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(`immature`) - hasher.combine(`trustedPending`) - hasher.combine(`untrustedPending`) - hasher.combine(`confirmed`) - hasher.combine(`spendable`) - hasher.combine(`total`) - } -} - - -fileprivate struct FfiConverterTypeBalance: FfiConverterRustBuffer { - fileprivate static func read(from buf: Reader) throws -> Balance { - return try Balance( - `immature`: FfiConverterUInt64.read(from: buf), - `trustedPending`: FfiConverterUInt64.read(from: buf), - `untrustedPending`: FfiConverterUInt64.read(from: buf), - `confirmed`: FfiConverterUInt64.read(from: buf), - `spendable`: FfiConverterUInt64.read(from: buf), - `total`: FfiConverterUInt64.read(from: buf) - ) - } - - fileprivate static func write(_ value: Balance, into buf: Writer) { - FfiConverterUInt64.write(value.`immature`, into: buf) - FfiConverterUInt64.write(value.`trustedPending`, into: buf) - FfiConverterUInt64.write(value.`untrustedPending`, into: buf) - FfiConverterUInt64.write(value.`confirmed`, into: buf) - FfiConverterUInt64.write(value.`spendable`, into: buf) - FfiConverterUInt64.write(value.`total`, into: buf) - } -} - - -public struct BlockTime { - public var `height`: UInt32 - public var `timestamp`: UInt64 - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(`height`: UInt32, `timestamp`: UInt64) { - self.`height` = `height` - self.`timestamp` = `timestamp` - } -} - - -extension BlockTime: Equatable, Hashable { - public static func ==(lhs: BlockTime, rhs: BlockTime) -> Bool { - if lhs.`height` != rhs.`height` { - return false - } - if lhs.`timestamp` != rhs.`timestamp` { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(`height`) - hasher.combine(`timestamp`) - } -} - - -fileprivate struct FfiConverterTypeBlockTime: FfiConverterRustBuffer { - fileprivate static func read(from buf: Reader) throws -> BlockTime { - return try BlockTime( - `height`: FfiConverterUInt32.read(from: buf), - `timestamp`: FfiConverterUInt64.read(from: buf) - ) - } - - fileprivate static func write(_ value: BlockTime, into buf: Writer) { - FfiConverterUInt32.write(value.`height`, into: buf) - FfiConverterUInt64.write(value.`timestamp`, into: buf) - } -} - - -public struct ElectrumConfig { - public var `url`: String - public var `socks5`: String? - public var `retry`: UInt8 - public var `timeout`: UInt8? - public var `stopGap`: UInt64 - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(`url`: String, `socks5`: String?, `retry`: UInt8, `timeout`: UInt8?, `stopGap`: UInt64) { - self.`url` = `url` - self.`socks5` = `socks5` - self.`retry` = `retry` - self.`timeout` = `timeout` - self.`stopGap` = `stopGap` - } -} - - -extension ElectrumConfig: Equatable, Hashable { - public static func ==(lhs: ElectrumConfig, rhs: ElectrumConfig) -> Bool { - if lhs.`url` != rhs.`url` { - return false - } - if lhs.`socks5` != rhs.`socks5` { - return false - } - if lhs.`retry` != rhs.`retry` { - return false - } - if lhs.`timeout` != rhs.`timeout` { - return false - } - if lhs.`stopGap` != rhs.`stopGap` { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(`url`) - hasher.combine(`socks5`) - hasher.combine(`retry`) - hasher.combine(`timeout`) - hasher.combine(`stopGap`) - } -} - - -fileprivate struct FfiConverterTypeElectrumConfig: FfiConverterRustBuffer { - fileprivate static func read(from buf: Reader) throws -> ElectrumConfig { - return try ElectrumConfig( - `url`: FfiConverterString.read(from: buf), - `socks5`: FfiConverterOptionString.read(from: buf), - `retry`: FfiConverterUInt8.read(from: buf), - `timeout`: FfiConverterOptionUInt8.read(from: buf), - `stopGap`: FfiConverterUInt64.read(from: buf) - ) - } - - fileprivate static func write(_ value: ElectrumConfig, into buf: Writer) { - FfiConverterString.write(value.`url`, into: buf) - FfiConverterOptionString.write(value.`socks5`, into: buf) - FfiConverterUInt8.write(value.`retry`, into: buf) - FfiConverterOptionUInt8.write(value.`timeout`, into: buf) - FfiConverterUInt64.write(value.`stopGap`, into: buf) - } -} - - -public struct EsploraConfig { - public var `baseUrl`: String - public var `proxy`: String? - public var `concurrency`: UInt8? - public var `stopGap`: UInt64 - public var `timeout`: UInt64? - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(`baseUrl`: String, `proxy`: String?, `concurrency`: UInt8?, `stopGap`: UInt64, `timeout`: UInt64?) { - self.`baseUrl` = `baseUrl` - self.`proxy` = `proxy` - self.`concurrency` = `concurrency` - self.`stopGap` = `stopGap` - self.`timeout` = `timeout` - } -} - - -extension EsploraConfig: Equatable, Hashable { - public static func ==(lhs: EsploraConfig, rhs: EsploraConfig) -> Bool { - if lhs.`baseUrl` != rhs.`baseUrl` { - return false - } - if lhs.`proxy` != rhs.`proxy` { - return false - } - if lhs.`concurrency` != rhs.`concurrency` { - return false - } - if lhs.`stopGap` != rhs.`stopGap` { - return false - } - if lhs.`timeout` != rhs.`timeout` { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(`baseUrl`) - hasher.combine(`proxy`) - hasher.combine(`concurrency`) - hasher.combine(`stopGap`) - hasher.combine(`timeout`) - } -} - - -fileprivate struct FfiConverterTypeEsploraConfig: FfiConverterRustBuffer { - fileprivate static func read(from buf: Reader) throws -> EsploraConfig { - return try EsploraConfig( - `baseUrl`: FfiConverterString.read(from: buf), - `proxy`: FfiConverterOptionString.read(from: buf), - `concurrency`: FfiConverterOptionUInt8.read(from: buf), - `stopGap`: FfiConverterUInt64.read(from: buf), - `timeout`: FfiConverterOptionUInt64.read(from: buf) - ) - } - - fileprivate static func write(_ value: EsploraConfig, into buf: Writer) { - FfiConverterString.write(value.`baseUrl`, into: buf) - FfiConverterOptionString.write(value.`proxy`, into: buf) - FfiConverterOptionUInt8.write(value.`concurrency`, into: buf) - FfiConverterUInt64.write(value.`stopGap`, into: buf) - FfiConverterOptionUInt64.write(value.`timeout`, into: buf) - } -} - - -public struct LocalUtxo { - public var `outpoint`: OutPoint - public var `txout`: TxOut - public var `keychain`: KeychainKind - public var `isSpent`: Bool - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(`outpoint`: OutPoint, `txout`: TxOut, `keychain`: KeychainKind, `isSpent`: Bool) { - self.`outpoint` = `outpoint` - self.`txout` = `txout` - self.`keychain` = `keychain` - self.`isSpent` = `isSpent` - } -} - - -extension LocalUtxo: Equatable, Hashable { - public static func ==(lhs: LocalUtxo, rhs: LocalUtxo) -> Bool { - if lhs.`outpoint` != rhs.`outpoint` { - return false - } - if lhs.`txout` != rhs.`txout` { - return false - } - if lhs.`keychain` != rhs.`keychain` { - return false - } - if lhs.`isSpent` != rhs.`isSpent` { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(`outpoint`) - hasher.combine(`txout`) - hasher.combine(`keychain`) - hasher.combine(`isSpent`) - } -} - - -fileprivate struct FfiConverterTypeLocalUtxo: FfiConverterRustBuffer { - fileprivate static func read(from buf: Reader) throws -> LocalUtxo { - return try LocalUtxo( - `outpoint`: FfiConverterTypeOutPoint.read(from: buf), - `txout`: FfiConverterTypeTxOut.read(from: buf), - `keychain`: FfiConverterTypeKeychainKind.read(from: buf), - `isSpent`: FfiConverterBool.read(from: buf) - ) - } - - fileprivate static func write(_ value: LocalUtxo, into buf: Writer) { - FfiConverterTypeOutPoint.write(value.`outpoint`, into: buf) - FfiConverterTypeTxOut.write(value.`txout`, into: buf) - FfiConverterTypeKeychainKind.write(value.`keychain`, into: buf) - FfiConverterBool.write(value.`isSpent`, into: buf) - } -} - - -public struct OutPoint { - public var `txid`: String - public var `vout`: UInt32 - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(`txid`: String, `vout`: UInt32) { - self.`txid` = `txid` - self.`vout` = `vout` - } -} - - -extension OutPoint: Equatable, Hashable { - public static func ==(lhs: OutPoint, rhs: OutPoint) -> Bool { - if lhs.`txid` != rhs.`txid` { - return false - } - if lhs.`vout` != rhs.`vout` { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(`txid`) - hasher.combine(`vout`) - } -} - - -fileprivate struct FfiConverterTypeOutPoint: FfiConverterRustBuffer { - fileprivate static func read(from buf: Reader) throws -> OutPoint { - return try OutPoint( - `txid`: FfiConverterString.read(from: buf), - `vout`: FfiConverterUInt32.read(from: buf) - ) - } - - fileprivate static func write(_ value: OutPoint, into buf: Writer) { - FfiConverterString.write(value.`txid`, into: buf) - FfiConverterUInt32.write(value.`vout`, into: buf) - } -} - - -public struct ScriptAmount { - public var `script`: Script - public var `amount`: UInt64 - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(`script`: Script, `amount`: UInt64) { - self.`script` = `script` - self.`amount` = `amount` - } -} - - - -fileprivate struct FfiConverterTypeScriptAmount: FfiConverterRustBuffer { - fileprivate static func read(from buf: Reader) throws -> ScriptAmount { - return try ScriptAmount( - `script`: FfiConverterTypeScript.read(from: buf), - `amount`: FfiConverterUInt64.read(from: buf) - ) - } - - fileprivate static func write(_ value: ScriptAmount, into buf: Writer) { - FfiConverterTypeScript.write(value.`script`, into: buf) - FfiConverterUInt64.write(value.`amount`, into: buf) - } -} - - -public struct SledDbConfiguration { - public var `path`: String - public var `treeName`: String - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(`path`: String, `treeName`: String) { - self.`path` = `path` - self.`treeName` = `treeName` - } -} - - -extension SledDbConfiguration: Equatable, Hashable { - public static func ==(lhs: SledDbConfiguration, rhs: SledDbConfiguration) -> Bool { - if lhs.`path` != rhs.`path` { - return false - } - if lhs.`treeName` != rhs.`treeName` { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(`path`) - hasher.combine(`treeName`) - } -} - - -fileprivate struct FfiConverterTypeSledDbConfiguration: FfiConverterRustBuffer { - fileprivate static func read(from buf: Reader) throws -> SledDbConfiguration { - return try SledDbConfiguration( - `path`: FfiConverterString.read(from: buf), - `treeName`: FfiConverterString.read(from: buf) - ) - } - - fileprivate static func write(_ value: SledDbConfiguration, into buf: Writer) { - FfiConverterString.write(value.`path`, into: buf) - FfiConverterString.write(value.`treeName`, into: buf) - } -} - - -public struct SqliteDbConfiguration { - public var `path`: String - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(`path`: String) { - self.`path` = `path` - } -} - - -extension SqliteDbConfiguration: Equatable, Hashable { - public static func ==(lhs: SqliteDbConfiguration, rhs: SqliteDbConfiguration) -> Bool { - if lhs.`path` != rhs.`path` { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(`path`) - } -} - - -fileprivate struct FfiConverterTypeSqliteDbConfiguration: FfiConverterRustBuffer { - fileprivate static func read(from buf: Reader) throws -> SqliteDbConfiguration { - return try SqliteDbConfiguration( - `path`: FfiConverterString.read(from: buf) - ) - } - - fileprivate static func write(_ value: SqliteDbConfiguration, into buf: Writer) { - FfiConverterString.write(value.`path`, into: buf) - } -} - - -public struct TransactionDetails { - public var `fee`: UInt64? - public var `received`: UInt64 - public var `sent`: UInt64 - public var `txid`: String - public var `confirmationTime`: BlockTime? - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(`fee`: UInt64?, `received`: UInt64, `sent`: UInt64, `txid`: String, `confirmationTime`: BlockTime?) { - self.`fee` = `fee` - self.`received` = `received` - self.`sent` = `sent` - self.`txid` = `txid` - self.`confirmationTime` = `confirmationTime` - } -} - - -extension TransactionDetails: Equatable, Hashable { - public static func ==(lhs: TransactionDetails, rhs: TransactionDetails) -> Bool { - if lhs.`fee` != rhs.`fee` { - return false - } - if lhs.`received` != rhs.`received` { - return false - } - if lhs.`sent` != rhs.`sent` { - return false - } - if lhs.`txid` != rhs.`txid` { - return false - } - if lhs.`confirmationTime` != rhs.`confirmationTime` { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(`fee`) - hasher.combine(`received`) - hasher.combine(`sent`) - hasher.combine(`txid`) - hasher.combine(`confirmationTime`) - } -} - - -fileprivate struct FfiConverterTypeTransactionDetails: FfiConverterRustBuffer { - fileprivate static func read(from buf: Reader) throws -> TransactionDetails { - return try TransactionDetails( - `fee`: FfiConverterOptionUInt64.read(from: buf), - `received`: FfiConverterUInt64.read(from: buf), - `sent`: FfiConverterUInt64.read(from: buf), - `txid`: FfiConverterString.read(from: buf), - `confirmationTime`: FfiConverterOptionTypeBlockTime.read(from: buf) - ) - } - - fileprivate static func write(_ value: TransactionDetails, into buf: Writer) { - FfiConverterOptionUInt64.write(value.`fee`, into: buf) - FfiConverterUInt64.write(value.`received`, into: buf) - FfiConverterUInt64.write(value.`sent`, into: buf) - FfiConverterString.write(value.`txid`, into: buf) - FfiConverterOptionTypeBlockTime.write(value.`confirmationTime`, into: buf) - } -} - - -public struct TxBuilderResult { - public var `psbt`: PartiallySignedBitcoinTransaction - public var `transactionDetails`: TransactionDetails - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(`psbt`: PartiallySignedBitcoinTransaction, `transactionDetails`: TransactionDetails) { - self.`psbt` = `psbt` - self.`transactionDetails` = `transactionDetails` - } -} - - - -fileprivate struct FfiConverterTypeTxBuilderResult: FfiConverterRustBuffer { - fileprivate static func read(from buf: Reader) throws -> TxBuilderResult { - return try TxBuilderResult( - `psbt`: FfiConverterTypePartiallySignedBitcoinTransaction.read(from: buf), - `transactionDetails`: FfiConverterTypeTransactionDetails.read(from: buf) - ) - } - - fileprivate static func write(_ value: TxBuilderResult, into buf: Writer) { - FfiConverterTypePartiallySignedBitcoinTransaction.write(value.`psbt`, into: buf) - FfiConverterTypeTransactionDetails.write(value.`transactionDetails`, into: buf) - } -} - - -public struct TxOut { - public var `value`: UInt64 - public var `address`: String - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(`value`: UInt64, `address`: String) { - self.`value` = `value` - self.`address` = `address` - } -} - - -extension TxOut: Equatable, Hashable { - public static func ==(lhs: TxOut, rhs: TxOut) -> Bool { - if lhs.`value` != rhs.`value` { - return false - } - if lhs.`address` != rhs.`address` { - return false - } - return true - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(`value`) - hasher.combine(`address`) - } -} - - -fileprivate struct FfiConverterTypeTxOut: FfiConverterRustBuffer { - fileprivate static func read(from buf: Reader) throws -> TxOut { - return try TxOut( - `value`: FfiConverterUInt64.read(from: buf), - `address`: FfiConverterString.read(from: buf) - ) - } - - fileprivate static func write(_ value: TxOut, into buf: Writer) { - FfiConverterUInt64.write(value.`value`, into: buf) - FfiConverterString.write(value.`address`, into: buf) - } -} - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. -public enum AddressIndex { - - case `new` - case `lastUnused` -} - -fileprivate struct FfiConverterTypeAddressIndex: FfiConverterRustBuffer { - typealias SwiftType = AddressIndex - - static func read(from buf: Reader) throws -> AddressIndex { - let variant: Int32 = try buf.readInt() - switch variant { - - case 1: return .`new` - - case 2: return .`lastUnused` - - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - static func write(_ value: AddressIndex, into buf: Writer) { - switch value { - - - case .`new`: - buf.writeInt(Int32(1)) - - - case .`lastUnused`: - buf.writeInt(Int32(2)) - - } - } -} - - -extension AddressIndex: Equatable, Hashable {} - - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. -public enum BlockchainConfig { - - case `electrum`(`config`: ElectrumConfig) - case `esplora`(`config`: EsploraConfig) -} - -fileprivate struct FfiConverterTypeBlockchainConfig: FfiConverterRustBuffer { - typealias SwiftType = BlockchainConfig - - static func read(from buf: Reader) throws -> BlockchainConfig { - let variant: Int32 = try buf.readInt() - switch variant { - - case 1: return .`electrum`( - `config`: try FfiConverterTypeElectrumConfig.read(from: buf) - ) - - case 2: return .`esplora`( - `config`: try FfiConverterTypeEsploraConfig.read(from: buf) - ) - - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - static func write(_ value: BlockchainConfig, into buf: Writer) { - switch value { - - - case let .`electrum`(`config`): - buf.writeInt(Int32(1)) - FfiConverterTypeElectrumConfig.write(`config`, into: buf) - - - case let .`esplora`(`config`): - buf.writeInt(Int32(2)) - FfiConverterTypeEsploraConfig.write(`config`, into: buf) - - } - } -} - - -extension BlockchainConfig: Equatable, Hashable {} - - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. -public enum DatabaseConfig { - - case `memory` - case `sled`(`config`: SledDbConfiguration) - case `sqlite`(`config`: SqliteDbConfiguration) -} - -fileprivate struct FfiConverterTypeDatabaseConfig: FfiConverterRustBuffer { - typealias SwiftType = DatabaseConfig - - static func read(from buf: Reader) throws -> DatabaseConfig { - let variant: Int32 = try buf.readInt() - switch variant { - - case 1: return .`memory` - - case 2: return .`sled`( - `config`: try FfiConverterTypeSledDbConfiguration.read(from: buf) - ) - - case 3: return .`sqlite`( - `config`: try FfiConverterTypeSqliteDbConfiguration.read(from: buf) - ) - - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - static func write(_ value: DatabaseConfig, into buf: Writer) { - switch value { - - - case .`memory`: - buf.writeInt(Int32(1)) - - - case let .`sled`(`config`): - buf.writeInt(Int32(2)) - FfiConverterTypeSledDbConfiguration.write(`config`, into: buf) - - - case let .`sqlite`(`config`): - buf.writeInt(Int32(3)) - FfiConverterTypeSqliteDbConfiguration.write(`config`, into: buf) - - } - } -} - - -extension DatabaseConfig: Equatable, Hashable {} - - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. -public enum KeychainKind { - - case `external` - case `internal` -} - -fileprivate struct FfiConverterTypeKeychainKind: FfiConverterRustBuffer { - typealias SwiftType = KeychainKind - - static func read(from buf: Reader) throws -> KeychainKind { - let variant: Int32 = try buf.readInt() - switch variant { - - case 1: return .`external` - - case 2: return .`internal` - - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - static func write(_ value: KeychainKind, into buf: Writer) { - switch value { - - - case .`external`: - buf.writeInt(Int32(1)) - - - case .`internal`: - buf.writeInt(Int32(2)) - - } - } -} - - -extension KeychainKind: Equatable, Hashable {} - - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. -public enum Network { - - case `bitcoin` - case `testnet` - case `signet` - case `regtest` -} - -fileprivate struct FfiConverterTypeNetwork: FfiConverterRustBuffer { - typealias SwiftType = Network - - static func read(from buf: Reader) throws -> Network { - let variant: Int32 = try buf.readInt() - switch variant { - - case 1: return .`bitcoin` - - case 2: return .`testnet` - - case 3: return .`signet` - - case 4: return .`regtest` - - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - static func write(_ value: Network, into buf: Writer) { - switch value { - - - case .`bitcoin`: - buf.writeInt(Int32(1)) - - - case .`testnet`: - buf.writeInt(Int32(2)) - - - case .`signet`: - buf.writeInt(Int32(3)) - - - case .`regtest`: - buf.writeInt(Int32(4)) - - } - } -} - - -extension Network: Equatable, Hashable {} - - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. -public enum WordCount { - - case `words12` - case `words15` - case `words18` - case `words21` - case `words24` -} - -fileprivate struct FfiConverterTypeWordCount: FfiConverterRustBuffer { - typealias SwiftType = WordCount - - static func read(from buf: Reader) throws -> WordCount { - let variant: Int32 = try buf.readInt() - switch variant { - - case 1: return .`words12` - - case 2: return .`words15` - - case 3: return .`words18` - - case 4: return .`words21` - - case 5: return .`words24` - - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - static func write(_ value: WordCount, into buf: Writer) { - switch value { - - - case .`words12`: - buf.writeInt(Int32(1)) - - - case .`words15`: - buf.writeInt(Int32(2)) - - - case .`words18`: - buf.writeInt(Int32(3)) - - - case .`words21`: - buf.writeInt(Int32(4)) - - - case .`words24`: - buf.writeInt(Int32(5)) - - } - } -} - - -extension WordCount: Equatable, Hashable {} - - - -public enum BdkError { - - - - // Simple error enums only carry a message - case InvalidU32Bytes(message: String) - - // Simple error enums only carry a message - case Generic(message: String) - - // Simple error enums only carry a message - case MissingCachedScripts(message: String) - - // Simple error enums only carry a message - case ScriptDoesntHaveAddressForm(message: String) - - // Simple error enums only carry a message - case NoRecipients(message: String) - - // Simple error enums only carry a message - case NoUtxosSelected(message: String) - - // Simple error enums only carry a message - case OutputBelowDustLimit(message: String) - - // Simple error enums only carry a message - case InsufficientFunds(message: String) - - // Simple error enums only carry a message - case BnBTotalTriesExceeded(message: String) - - // Simple error enums only carry a message - case BnBNoExactMatch(message: String) - - // Simple error enums only carry a message - case UnknownUtxo(message: String) - - // Simple error enums only carry a message - case TransactionNotFound(message: String) - - // Simple error enums only carry a message - case TransactionConfirmed(message: String) - - // Simple error enums only carry a message - case IrreplaceableTransaction(message: String) - - // Simple error enums only carry a message - case FeeRateTooLow(message: String) - - // Simple error enums only carry a message - case FeeTooLow(message: String) - - // Simple error enums only carry a message - case FeeRateUnavailable(message: String) - - // Simple error enums only carry a message - case MissingKeyOrigin(message: String) - - // Simple error enums only carry a message - case Key(message: String) - - // Simple error enums only carry a message - case ChecksumMismatch(message: String) - - // Simple error enums only carry a message - case SpendingPolicyRequired(message: String) - - // Simple error enums only carry a message - case InvalidPolicyPathError(message: String) - - // Simple error enums only carry a message - case Signer(message: String) - - // Simple error enums only carry a message - case InvalidNetwork(message: String) - - // Simple error enums only carry a message - case InvalidProgressValue(message: String) - - // Simple error enums only carry a message - case ProgressUpdateError(message: String) - - // Simple error enums only carry a message - case InvalidOutpoint(message: String) - - // Simple error enums only carry a message - case Descriptor(message: String) - - // Simple error enums only carry a message - case AddressValidator(message: String) - - // Simple error enums only carry a message - case Encode(message: String) - - // Simple error enums only carry a message - case Miniscript(message: String) - - // Simple error enums only carry a message - case Bip32(message: String) - - // Simple error enums only carry a message - case Secp256k1(message: String) - - // Simple error enums only carry a message - case Json(message: String) - - // Simple error enums only carry a message - case Hex(message: String) - - // Simple error enums only carry a message - case Psbt(message: String) - - // Simple error enums only carry a message - case PsbtParse(message: String) - - // Simple error enums only carry a message - case Electrum(message: String) - - // Simple error enums only carry a message - case Esplora(message: String) - - // Simple error enums only carry a message - case Sled(message: String) - - // Simple error enums only carry a message - case Rusqlite(message: String) - -} - -fileprivate struct FfiConverterTypeBdkError: FfiConverterRustBuffer { - typealias SwiftType = BdkError - - static func read(from buf: Reader) throws -> BdkError { - let variant: Int32 = try buf.readInt() - switch variant { - - - - - case 1: return .InvalidU32Bytes( - message: try FfiConverterString.read(from: buf) - ) - - case 2: return .Generic( - message: try FfiConverterString.read(from: buf) - ) - - case 3: return .MissingCachedScripts( - message: try FfiConverterString.read(from: buf) - ) - - case 4: return .ScriptDoesntHaveAddressForm( - message: try FfiConverterString.read(from: buf) - ) - - case 5: return .NoRecipients( - message: try FfiConverterString.read(from: buf) - ) - - case 6: return .NoUtxosSelected( - message: try FfiConverterString.read(from: buf) - ) - - case 7: return .OutputBelowDustLimit( - message: try FfiConverterString.read(from: buf) - ) - - case 8: return .InsufficientFunds( - message: try FfiConverterString.read(from: buf) - ) - - case 9: return .BnBTotalTriesExceeded( - message: try FfiConverterString.read(from: buf) - ) - - case 10: return .BnBNoExactMatch( - message: try FfiConverterString.read(from: buf) - ) - - case 11: return .UnknownUtxo( - message: try FfiConverterString.read(from: buf) - ) - - case 12: return .TransactionNotFound( - message: try FfiConverterString.read(from: buf) - ) - - case 13: return .TransactionConfirmed( - message: try FfiConverterString.read(from: buf) - ) - - case 14: return .IrreplaceableTransaction( - message: try FfiConverterString.read(from: buf) - ) - - case 15: return .FeeRateTooLow( - message: try FfiConverterString.read(from: buf) - ) - - case 16: return .FeeTooLow( - message: try FfiConverterString.read(from: buf) - ) - - case 17: return .FeeRateUnavailable( - message: try FfiConverterString.read(from: buf) - ) - - case 18: return .MissingKeyOrigin( - message: try FfiConverterString.read(from: buf) - ) - - case 19: return .Key( - message: try FfiConverterString.read(from: buf) - ) - - case 20: return .ChecksumMismatch( - message: try FfiConverterString.read(from: buf) - ) - - case 21: return .SpendingPolicyRequired( - message: try FfiConverterString.read(from: buf) - ) - - case 22: return .InvalidPolicyPathError( - message: try FfiConverterString.read(from: buf) - ) - - case 23: return .Signer( - message: try FfiConverterString.read(from: buf) - ) - - case 24: return .InvalidNetwork( - message: try FfiConverterString.read(from: buf) - ) - - case 25: return .InvalidProgressValue( - message: try FfiConverterString.read(from: buf) - ) - - case 26: return .ProgressUpdateError( - message: try FfiConverterString.read(from: buf) - ) - - case 27: return .InvalidOutpoint( - message: try FfiConverterString.read(from: buf) - ) - - case 28: return .Descriptor( - message: try FfiConverterString.read(from: buf) - ) - - case 29: return .AddressValidator( - message: try FfiConverterString.read(from: buf) - ) - - case 30: return .Encode( - message: try FfiConverterString.read(from: buf) - ) - - case 31: return .Miniscript( - message: try FfiConverterString.read(from: buf) - ) - - case 32: return .Bip32( - message: try FfiConverterString.read(from: buf) - ) - - case 33: return .Secp256k1( - message: try FfiConverterString.read(from: buf) - ) - - case 34: return .Json( - message: try FfiConverterString.read(from: buf) - ) - - case 35: return .Hex( - message: try FfiConverterString.read(from: buf) - ) - - case 36: return .Psbt( - message: try FfiConverterString.read(from: buf) - ) - - case 37: return .PsbtParse( - message: try FfiConverterString.read(from: buf) - ) - - case 38: return .Electrum( - message: try FfiConverterString.read(from: buf) - ) - - case 39: return .Esplora( - message: try FfiConverterString.read(from: buf) - ) - - case 40: return .Sled( - message: try FfiConverterString.read(from: buf) - ) - - case 41: return .Rusqlite( - message: try FfiConverterString.read(from: buf) - ) - - - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - static func write(_ value: BdkError, into buf: Writer) { - switch value { - - - - - case let .InvalidU32Bytes(message): - buf.writeInt(Int32(1)) - FfiConverterString.write(message, into: buf) - case let .Generic(message): - buf.writeInt(Int32(2)) - FfiConverterString.write(message, into: buf) - case let .MissingCachedScripts(message): - buf.writeInt(Int32(3)) - FfiConverterString.write(message, into: buf) - case let .ScriptDoesntHaveAddressForm(message): - buf.writeInt(Int32(4)) - FfiConverterString.write(message, into: buf) - case let .NoRecipients(message): - buf.writeInt(Int32(5)) - FfiConverterString.write(message, into: buf) - case let .NoUtxosSelected(message): - buf.writeInt(Int32(6)) - FfiConverterString.write(message, into: buf) - case let .OutputBelowDustLimit(message): - buf.writeInt(Int32(7)) - FfiConverterString.write(message, into: buf) - case let .InsufficientFunds(message): - buf.writeInt(Int32(8)) - FfiConverterString.write(message, into: buf) - case let .BnBTotalTriesExceeded(message): - buf.writeInt(Int32(9)) - FfiConverterString.write(message, into: buf) - case let .BnBNoExactMatch(message): - buf.writeInt(Int32(10)) - FfiConverterString.write(message, into: buf) - case let .UnknownUtxo(message): - buf.writeInt(Int32(11)) - FfiConverterString.write(message, into: buf) - case let .TransactionNotFound(message): - buf.writeInt(Int32(12)) - FfiConverterString.write(message, into: buf) - case let .TransactionConfirmed(message): - buf.writeInt(Int32(13)) - FfiConverterString.write(message, into: buf) - case let .IrreplaceableTransaction(message): - buf.writeInt(Int32(14)) - FfiConverterString.write(message, into: buf) - case let .FeeRateTooLow(message): - buf.writeInt(Int32(15)) - FfiConverterString.write(message, into: buf) - case let .FeeTooLow(message): - buf.writeInt(Int32(16)) - FfiConverterString.write(message, into: buf) - case let .FeeRateUnavailable(message): - buf.writeInt(Int32(17)) - FfiConverterString.write(message, into: buf) - case let .MissingKeyOrigin(message): - buf.writeInt(Int32(18)) - FfiConverterString.write(message, into: buf) - case let .Key(message): - buf.writeInt(Int32(19)) - FfiConverterString.write(message, into: buf) - case let .ChecksumMismatch(message): - buf.writeInt(Int32(20)) - FfiConverterString.write(message, into: buf) - case let .SpendingPolicyRequired(message): - buf.writeInt(Int32(21)) - FfiConverterString.write(message, into: buf) - case let .InvalidPolicyPathError(message): - buf.writeInt(Int32(22)) - FfiConverterString.write(message, into: buf) - case let .Signer(message): - buf.writeInt(Int32(23)) - FfiConverterString.write(message, into: buf) - case let .InvalidNetwork(message): - buf.writeInt(Int32(24)) - FfiConverterString.write(message, into: buf) - case let .InvalidProgressValue(message): - buf.writeInt(Int32(25)) - FfiConverterString.write(message, into: buf) - case let .ProgressUpdateError(message): - buf.writeInt(Int32(26)) - FfiConverterString.write(message, into: buf) - case let .InvalidOutpoint(message): - buf.writeInt(Int32(27)) - FfiConverterString.write(message, into: buf) - case let .Descriptor(message): - buf.writeInt(Int32(28)) - FfiConverterString.write(message, into: buf) - case let .AddressValidator(message): - buf.writeInt(Int32(29)) - FfiConverterString.write(message, into: buf) - case let .Encode(message): - buf.writeInt(Int32(30)) - FfiConverterString.write(message, into: buf) - case let .Miniscript(message): - buf.writeInt(Int32(31)) - FfiConverterString.write(message, into: buf) - case let .Bip32(message): - buf.writeInt(Int32(32)) - FfiConverterString.write(message, into: buf) - case let .Secp256k1(message): - buf.writeInt(Int32(33)) - FfiConverterString.write(message, into: buf) - case let .Json(message): - buf.writeInt(Int32(34)) - FfiConverterString.write(message, into: buf) - case let .Hex(message): - buf.writeInt(Int32(35)) - FfiConverterString.write(message, into: buf) - case let .Psbt(message): - buf.writeInt(Int32(36)) - FfiConverterString.write(message, into: buf) - case let .PsbtParse(message): - buf.writeInt(Int32(37)) - FfiConverterString.write(message, into: buf) - case let .Electrum(message): - buf.writeInt(Int32(38)) - FfiConverterString.write(message, into: buf) - case let .Esplora(message): - buf.writeInt(Int32(39)) - FfiConverterString.write(message, into: buf) - case let .Sled(message): - buf.writeInt(Int32(40)) - FfiConverterString.write(message, into: buf) - case let .Rusqlite(message): - buf.writeInt(Int32(41)) - FfiConverterString.write(message, into: buf) - - - } - } -} - - -extension BdkError: Equatable, Hashable {} - -extension BdkError: Error { } - -fileprivate extension NSLock { - func withLock(f: () throws -> T) rethrows -> T { - self.lock() - defer { self.unlock() } - return try f() - } -} - -fileprivate typealias Handle = UInt64 -fileprivate class ConcurrentHandleMap { - private var leftMap: [Handle: T] = [:] - private var counter: [Handle: UInt64] = [:] - private var rightMap: [ObjectIdentifier: Handle] = [:] - - private let lock = NSLock() - private var currentHandle: Handle = 0 - private let stride: Handle = 1 - - func insert(obj: T) -> Handle { - lock.withLock { - let id = ObjectIdentifier(obj as AnyObject) - let handle = rightMap[id] ?? { - currentHandle += stride - let handle = currentHandle - leftMap[handle] = obj - rightMap[id] = handle - return handle - }() - counter[handle] = (counter[handle] ?? 0) + 1 - return handle - } - } - - func get(handle: Handle) -> T? { - lock.withLock { - leftMap[handle] - } - } - - func delete(handle: Handle) { - remove(handle: handle) - } - - @discardableResult - func remove(handle: Handle) -> T? { - lock.withLock { - defer { counter[handle] = (counter[handle] ?? 1) - 1 } - guard counter[handle] == 1 else { return leftMap[handle] } - let obj = leftMap.removeValue(forKey: handle) - if let obj = obj { - rightMap.removeValue(forKey: ObjectIdentifier(obj as AnyObject)) - } - return obj - } - } -} - -// 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 - -// Declaration and FfiConverters for Progress Callback Interface - -public protocol Progress : AnyObject { - func `update`(`progress`: Float, `message`: String?) - -} - -// The ForeignCallback that is passed to Rust. -fileprivate let foreignCallbackCallbackInterfaceProgress : ForeignCallback = - { (handle: Handle, method: Int32, args: RustBuffer, out_buf: UnsafeMutablePointer) -> Int32 in - func `invokeUpdate`(_ swiftCallbackInterface: Progress, _ args: RustBuffer) throws -> RustBuffer { - defer { args.deallocate() } - - let reader = Reader(data: Data(rustBuffer: args)) - swiftCallbackInterface.`update`( - `progress`: try FfiConverterFloat.read(from: reader), - `message`: try FfiConverterOptionString.read(from: reader) - ) - return RustBuffer() - // TODO catch errors and report them back to Rust. - // https://github.com/mozilla/uniffi-rs/issues/351 - - } - - - let cb: Progress - do { - cb = try FfiConverterCallbackInterfaceProgress.lift(handle) - } catch { - out_buf.pointee = FfiConverterString.lower("Progress: Invalid handle") - return -1 - } - - switch method { - case IDX_CALLBACK_FREE: - FfiConverterCallbackInterfaceProgress.drop(handle: handle) - // No return value. - // See docs of ForeignCallback in `uniffi/src/ffi/foreigncallbacks.rs` - return 0 - case 1: - do { - out_buf.pointee = try `invokeUpdate`(cb, args) - // Value written to out buffer. - // See docs of ForeignCallback in `uniffi/src/ffi/foreigncallbacks.rs` - return 1 - } catch let error { - out_buf.pointee = FfiConverterString.lower(String(describing: error)) - return -1 - } - - // This should never happen, because an out of bounds method index won't - // ever be used. Once we can catch errors, we should return an InternalError. - // https://github.com/mozilla/uniffi-rs/issues/351 - default: - // An unexpected error happened. - // See docs of ForeignCallback in `uniffi/src/ffi/foreigncallbacks.rs` - return -1 - } - } - -// FFIConverter protocol for callback interfaces -fileprivate struct FfiConverterCallbackInterfaceProgress { - // Initialize our callback method with the scaffolding code - private static var callbackInitialized = false - private static func initCallback() { - try! rustCall { (err: UnsafeMutablePointer) in - ffi_bdk_1724_Progress_init_callback(foreignCallbackCallbackInterfaceProgress, err) - } - } - private static func ensureCallbackinitialized() { - if !callbackInitialized { - initCallback() - callbackInitialized = true - } - } - - static func drop(handle: Handle) { - handleMap.remove(handle: handle) - } - - private static var handleMap = ConcurrentHandleMap() -} - -extension FfiConverterCallbackInterfaceProgress : FfiConverter { - typealias SwiftType = Progress - // We can use Handle as the FFIType because it's a typealias to UInt64 - typealias FfiType = Handle - - static func lift(_ handle: Handle) throws -> SwiftType { - ensureCallbackinitialized(); - guard let callback = handleMap.get(handle: handle) else { - throw UniffiInternalError.unexpectedStaleHandle - } - return callback - } - - static func read(from buf: Reader) throws -> SwiftType { - ensureCallbackinitialized(); - let handle: Handle = try buf.readInt() - return try lift(handle) - } - - static func lower(_ v: SwiftType) -> Handle { - ensureCallbackinitialized(); - return handleMap.insert(obj: v) - } - - static func write(_ v: SwiftType, into buf: Writer) { - ensureCallbackinitialized(); - buf.writeInt(lower(v)) - } -} - -fileprivate struct FfiConverterOptionUInt8: FfiConverterRustBuffer { - typealias SwiftType = UInt8? - - static func write(_ value: SwiftType, into buf: Writer) { - guard let value = value else { - buf.writeInt(Int8(0)) - return - } - buf.writeInt(Int8(1)) - FfiConverterUInt8.write(value, into: buf) - } - - static func read(from buf: Reader) throws -> SwiftType { - switch try buf.readInt() as Int8 { - case 0: return nil - case 1: return try FfiConverterUInt8.read(from: buf) - default: throw UniffiInternalError.unexpectedOptionalTag - } - } -} - -fileprivate struct FfiConverterOptionUInt64: FfiConverterRustBuffer { - typealias SwiftType = UInt64? - - static func write(_ value: SwiftType, into buf: Writer) { - guard let value = value else { - buf.writeInt(Int8(0)) - return - } - buf.writeInt(Int8(1)) - FfiConverterUInt64.write(value, into: buf) - } - - static func read(from buf: Reader) throws -> SwiftType { - switch try buf.readInt() as Int8 { - case 0: return nil - case 1: return try FfiConverterUInt64.read(from: buf) - default: throw UniffiInternalError.unexpectedOptionalTag - } - } -} - -fileprivate struct FfiConverterOptionString: FfiConverterRustBuffer { - typealias SwiftType = String? - - static func write(_ value: SwiftType, into buf: Writer) { - guard let value = value else { - buf.writeInt(Int8(0)) - return - } - buf.writeInt(Int8(1)) - FfiConverterString.write(value, into: buf) - } - - static func read(from buf: Reader) throws -> SwiftType { - switch try buf.readInt() as Int8 { - case 0: return nil - case 1: return try FfiConverterString.read(from: buf) - default: throw UniffiInternalError.unexpectedOptionalTag - } - } -} - -fileprivate struct FfiConverterOptionTypeBlockTime: FfiConverterRustBuffer { - typealias SwiftType = BlockTime? - - static func write(_ value: SwiftType, into buf: Writer) { - guard let value = value else { - buf.writeInt(Int8(0)) - return - } - buf.writeInt(Int8(1)) - FfiConverterTypeBlockTime.write(value, into: buf) - } - - static func read(from buf: Reader) throws -> SwiftType { - switch try buf.readInt() as Int8 { - case 0: return nil - case 1: return try FfiConverterTypeBlockTime.read(from: buf) - default: throw UniffiInternalError.unexpectedOptionalTag - } - } -} - -fileprivate struct FfiConverterOptionCallbackInterfaceProgress: FfiConverterRustBuffer { - typealias SwiftType = Progress? - - static func write(_ value: SwiftType, into buf: Writer) { - guard let value = value else { - buf.writeInt(Int8(0)) - return - } - buf.writeInt(Int8(1)) - FfiConverterCallbackInterfaceProgress.write(value, into: buf) - } - - static func read(from buf: Reader) throws -> SwiftType { - switch try buf.readInt() as Int8 { - case 0: return nil - case 1: return try FfiConverterCallbackInterfaceProgress.read(from: buf) - default: throw UniffiInternalError.unexpectedOptionalTag - } - } -} - -fileprivate struct FfiConverterSequenceUInt8: FfiConverterRustBuffer { - typealias SwiftType = [UInt8] - - static func write(_ value: [UInt8], into buf: Writer) { - let len = Int32(value.count) - buf.writeInt(len) - for item in value { - FfiConverterUInt8.write(item, into: buf) - } - } - - static func read(from buf: Reader) throws -> [UInt8] { - let len: Int32 = try buf.readInt() - var seq = [UInt8]() - seq.reserveCapacity(Int(len)) - for _ in 0 ..< len { - seq.append(try FfiConverterUInt8.read(from: buf)) - } - return seq - } -} - -fileprivate struct FfiConverterSequenceTypeLocalUtxo: FfiConverterRustBuffer { - typealias SwiftType = [LocalUtxo] - - static func write(_ value: [LocalUtxo], into buf: Writer) { - let len = Int32(value.count) - buf.writeInt(len) - for item in value { - FfiConverterTypeLocalUtxo.write(item, into: buf) - } - } - - static func read(from buf: Reader) throws -> [LocalUtxo] { - let len: Int32 = try buf.readInt() - var seq = [LocalUtxo]() - seq.reserveCapacity(Int(len)) - for _ in 0 ..< len { - seq.append(try FfiConverterTypeLocalUtxo.read(from: buf)) - } - return seq - } -} - -fileprivate struct FfiConverterSequenceTypeOutPoint: FfiConverterRustBuffer { - typealias SwiftType = [OutPoint] - - static func write(_ value: [OutPoint], into buf: Writer) { - let len = Int32(value.count) - buf.writeInt(len) - for item in value { - FfiConverterTypeOutPoint.write(item, into: buf) - } - } - - static func read(from buf: Reader) throws -> [OutPoint] { - let len: Int32 = try buf.readInt() - var seq = [OutPoint]() - seq.reserveCapacity(Int(len)) - for _ in 0 ..< len { - seq.append(try FfiConverterTypeOutPoint.read(from: buf)) - } - return seq - } -} - -fileprivate struct FfiConverterSequenceTypeScriptAmount: FfiConverterRustBuffer { - typealias SwiftType = [ScriptAmount] - - static func write(_ value: [ScriptAmount], into buf: Writer) { - let len = Int32(value.count) - buf.writeInt(len) - for item in value { - FfiConverterTypeScriptAmount.write(item, into: buf) - } - } - - static func read(from buf: Reader) throws -> [ScriptAmount] { - let len: Int32 = try buf.readInt() - var seq = [ScriptAmount]() - seq.reserveCapacity(Int(len)) - for _ in 0 ..< len { - seq.append(try FfiConverterTypeScriptAmount.read(from: buf)) - } - return seq - } -} - -fileprivate struct FfiConverterSequenceTypeTransactionDetails: FfiConverterRustBuffer { - typealias SwiftType = [TransactionDetails] - - static func write(_ value: [TransactionDetails], into buf: Writer) { - let len = Int32(value.count) - buf.writeInt(len) - for item in value { - FfiConverterTypeTransactionDetails.write(item, into: buf) - } - } - - static func read(from buf: Reader) throws -> [TransactionDetails] { - let len: Int32 = try buf.readInt() - var seq = [TransactionDetails]() - seq.reserveCapacity(Int(len)) - for _ in 0 ..< len { - seq.append(try FfiConverterTypeTransactionDetails.read(from: buf)) - } - return seq - } -} - -public func `generateMnemonic`(`wordCount`: WordCount) throws -> String { - return try FfiConverterString.lift( - try - - rustCallWithError(FfiConverterTypeBdkError.self) { - - bdk_1724_generate_mnemonic( - FfiConverterTypeWordCount.lower(`wordCount`), $0) -} - ) -} - - - -/** - * Top level initializers and tear down methods. - * - * This is generated by uniffi. - */ -public enum BdkLifecycle { - /** - * Initialize the FFI and Rust library. This should be only called once per application. - */ - func initialize() { - } -} \ No newline at end of file