From 832c6148e18b1f8c6b7d8fc675398b8f1dbceb6d Mon Sep 17 00:00:00 2001 From: dorianvp Date: Tue, 10 Feb 2026 00:45:15 -0300 Subject: [PATCH 01/15] chore(ffi): stashed changes --- Cargo.lock | 312 +++++ Cargo.toml | 1 + ffi/ios/WalletModule/Generated/ffi.swift | 1118 +++++++++++++++++ ffi/ios/WalletModule/Generated/ffiFFI.h | 627 +++++++++ .../WalletModule/Generated/ffiFFI.modulemap | 7 + ffi/ios/WalletModule/WalletModule.podspec | 17 + ffi/ios/WalletSDK/.gitignore | 3 + .../Binaries/WalletFFI.xcframework/Info.plist | 43 + ffi/ios/WalletSDK/Package.swift | 37 + .../Sources/WalletSDK/Generated/ffi.swift | 1118 +++++++++++++++++ .../Sources/WalletSDK/Generated/ffiFFI.h | 627 +++++++++ .../WalletSDK/Generated/ffiFFI.modulemap | 7 + .../Sources/WalletSDK/WalletSDK.swift | 80 ++ .../Sources/WalletSDKSmoke/main.swift | 22 + .../WalletSDK/Sources/ffiFFI/include/ffiFFI.h | 627 +++++++++ .../WalletSDK/Sources/ffiFFI/module.modulemap | 7 + .../Tests/WalletSDKTests/WalletSDKTests.swift | 19 + ffi/rust/Cargo.toml | 21 + ffi/rust/generate-bindings.rs | 3 + ffi/rust/src/lib.rs | 190 +++ 20 files changed, 4886 insertions(+) create mode 100644 ffi/ios/WalletModule/Generated/ffi.swift create mode 100644 ffi/ios/WalletModule/Generated/ffiFFI.h create mode 100644 ffi/ios/WalletModule/Generated/ffiFFI.modulemap create mode 100644 ffi/ios/WalletModule/WalletModule.podspec create mode 100644 ffi/ios/WalletSDK/.gitignore create mode 100644 ffi/ios/WalletSDK/Binaries/WalletFFI.xcframework/Info.plist create mode 100644 ffi/ios/WalletSDK/Package.swift create mode 100644 ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffi.swift create mode 100644 ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.h create mode 100644 ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.modulemap create mode 100644 ffi/ios/WalletSDK/Sources/WalletSDK/WalletSDK.swift create mode 100644 ffi/ios/WalletSDK/Sources/WalletSDKSmoke/main.swift create mode 100644 ffi/ios/WalletSDK/Sources/ffiFFI/include/ffiFFI.h create mode 100644 ffi/ios/WalletSDK/Sources/ffiFFI/module.modulemap create mode 100644 ffi/ios/WalletSDK/Tests/WalletSDKTests/WalletSDKTests.swift create mode 100644 ffi/rust/Cargo.toml create mode 100644 ffi/rust/generate-bindings.rs create mode 100644 ffi/rust/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 91af012d6..359f08c12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -273,6 +273,48 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" +[[package]] +name = "askama" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" +dependencies = [ + "askama_derive", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" +dependencies = [ + "askama_parser", + "basic-toml", + "memchr", + "proc-macro2", + "quote", + "rustc-hash 2.1.1", + "serde", + "serde_derive", + "syn 2.0.111", +] + +[[package]] +name = "askama_parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" +dependencies = [ + "memchr", + "serde", + "serde_derive", + "winnow", +] + [[package]] name = "asn1-rs" version = "0.7.1" @@ -494,6 +536,15 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +[[package]] +name = "basic-toml" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" +dependencies = [ + "serde", +] + [[package]] name = "bech32" version = "0.11.0" @@ -842,12 +893,44 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +dependencies = [ + "serde_core", +] + [[package]] name = "caret" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4d27042e727de6261ee6391b834c6e1adec7031a03228cc1a67f95a3d8f2202" +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.17", +] + [[package]] name = "cast" version = "0.3.0" @@ -990,6 +1073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" dependencies = [ "clap_builder", + "clap_derive", ] [[package]] @@ -1004,6 +1088,18 @@ dependencies = [ "strsim 0.11.1", ] +[[package]] +name = "clap_derive" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "clap_lex" version = "0.7.6" @@ -2037,6 +2133,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "ffi" +version = "0.0.0" +dependencies = [ + "thiserror 2.0.17", + "tokio", + "uniffi", +] + [[package]] name = "fiat-crypto" version = "0.2.9" @@ -2143,6 +2248,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "fs-err" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] + [[package]] name = "fs-mistrust" version = "0.12.0" @@ -2359,6 +2473,17 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985c9503b412198aa4197559e9a318524ebc4519c229bfa05a535828c950b9d" +[[package]] +name = "goblin" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" +dependencies = [ + "log", + "plain", + "scroll", +] + [[package]] name = "group" version = "0.13.0" @@ -4184,6 +4309,12 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "plotters" version = "0.3.7" @@ -5402,6 +5533,26 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scroll" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "sct" version = "0.7.1" @@ -5488,6 +5639,10 @@ name = "semver" version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] [[package]] name = "serde" @@ -5815,6 +5970,12 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + [[package]] name = "socket2" version = "0.6.1" @@ -6053,6 +6214,15 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "smawk", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -7648,6 +7818,139 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "uniffi" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c6dec3fc6645f71a16a3fa9ff57991028153bd194ca97f4b55e610c73ce66a" +dependencies = [ + "anyhow", + "camino", + "cargo_metadata", + "clap", + "uniffi_bindgen", + "uniffi_build", + "uniffi_core", + "uniffi_macros", + "uniffi_pipeline", +] + +[[package]] +name = "uniffi_bindgen" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ed0150801958d4825da56a41c71f000a457ac3a4613fa9647df78ac4b6b6881" +dependencies = [ + "anyhow", + "askama", + "camino", + "cargo_metadata", + "fs-err", + "glob", + "goblin", + "heck", + "indexmap 2.12.1", + "once_cell", + "serde", + "tempfile", + "textwrap", + "toml 0.9.10+spec-1.1.0", + "uniffi_internal_macros", + "uniffi_meta", + "uniffi_pipeline", + "uniffi_udl", +] + +[[package]] +name = "uniffi_build" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b78fd9271a4c2e85bd2c266c5a9ede1fac676eb39fd77f636c27eaf67426fd5f" +dependencies = [ + "anyhow", + "camino", + "uniffi_bindgen", +] + +[[package]] +name = "uniffi_core" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0ef62e69762fbb9386dcb6c87cd3dd05d525fa8a3a579a290892e60ddbda47e" +dependencies = [ + "anyhow", + "bytes", + "once_cell", + "static_assertions", +] + +[[package]] +name = "uniffi_internal_macros" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98f51ebca0d9a4b2aa6c644d5ede45c56f73906b96403c08a1985e75ccb64a01" +dependencies = [ + "anyhow", + "indexmap 2.12.1", + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "uniffi_macros" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db9d12529f1223d014fd501e5f29ca0884d15d6ed5ddddd9f506e55350327dc3" +dependencies = [ + "camino", + "fs-err", + "once_cell", + "proc-macro2", + "quote", + "serde", + "syn 2.0.111", + "toml 0.9.10+spec-1.1.0", + "uniffi_meta", +] + +[[package]] +name = "uniffi_meta" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df6d413db2827c68588f8149d30d49b71d540d46539e435b23a7f7dbd4d4f86" +dependencies = [ + "anyhow", + "siphasher", + "uniffi_internal_macros", + "uniffi_pipeline", +] + +[[package]] +name = "uniffi_pipeline" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a806dddc8208f22efd7e95a5cdf88ed43d0f3271e8f63b47e757a8bbdb43b63a" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.12.1", + "tempfile", + "uniffi_internal_macros", +] + +[[package]] +name = "uniffi_udl" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d1a7339539bf6f6fa3e9b534dece13f778bda2d54b1a6d4e40b4d6090ac26e7" +dependencies = [ + "anyhow", + "textwrap", + "uniffi_meta", + "weedle2", +] + [[package]] name = "universal-hash" version = "0.5.1" @@ -7961,6 +8264,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "weedle2" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" +dependencies = [ + "nom", +] + [[package]] name = "which" version = "8.0.0" diff --git a/Cargo.toml b/Cargo.toml index 67ab243c1..fc3de3e29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "pepper-sync", "zingo-price", "zingolib_testutils", + "ffi/rust", ] resolver = "2" diff --git a/ffi/ios/WalletModule/Generated/ffi.swift b/ffi/ios/WalletModule/Generated/ffi.swift new file mode 100644 index 000000000..eb1827cfa --- /dev/null +++ b/ffi/ios/WalletModule/Generated/ffi.swift @@ -0,0 +1,1118 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! + +// swiftlint:disable all +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(ffiFFI) +import ffiFFI +#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 empty() -> RustBuffer { + RustBuffer(capacity: 0, len:0, data: nil) + } + + static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { + try! rustCall { ffi_ffi_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_ffi_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 library of its own. + +fileprivate extension Data { + init(rustBuffer: RustBuffer) { + self.init( + bytesNoCopy: rustBuffer.data!, + count: Int(rustBuffer.len), + deallocator: .none + ) + } +} + +// Define reader functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. +// +// With external types, one swift source file needs to be able to call the read +// method on another source file's FfiConverter, but then what visibility +// should Reader have? +// - If Reader is fileprivate, then this means the read() must also +// be fileprivate, which doesn't work with external types. +// - If Reader is internal/public, we'll get compile errors since both source +// files will try define the same type. +// +// Instead, the read() method and these helper functions input a tuple of data + +fileprivate func createReader(data: Data) -> (data: Data, offset: Data.Index) { + (data: data, offset: 0) +} + +// Reads an integer at the current offset, in big-endian order, and advances +// the offset on success. Throws if reading the integer would move the +// offset past the end of the buffer. +fileprivate func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { + let range = reader.offset...size + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + if T.self == UInt8.self { + let value = reader.data[reader.offset] + reader.offset += 1 + return value as! T + } + var value: T = 0 + let _ = withUnsafeMutableBytes(of: &value, { reader.data.copyBytes(to: $0, from: range)}) + reader.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 +fileprivate func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> Array { + let range = reader.offset..<(reader.offset+count) + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + var value = [UInt8](repeating: 0, count: count) + value.withUnsafeMutableBufferPointer({ buffer in + reader.data.copyBytes(to: buffer, from: range) + }) + reader.offset = range.upperBound + return value +} + +// Reads a float at the current offset. +fileprivate func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { + return Float(bitPattern: try readInt(&reader)) +} + +// Reads a float at the current offset. +fileprivate func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { + return Double(bitPattern: try readInt(&reader)) +} + +// Indicates if the offset has reached the end of the buffer. +fileprivate func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { + return reader.offset < reader.data.count +} + +// Define writer functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. See the above discussion on Readers for details. + +fileprivate func createWriter() -> [UInt8] { + return [] +} + +fileprivate func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { + writer.append(contentsOf: byteArr) +} + +// Writes an integer in big-endian order. +// +// Warning: make sure what you are trying to write +// is in the correct type! +fileprivate func writeInt(_ writer: inout [UInt8], _ value: T) { + var value = value.bigEndian + withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } +} + +fileprivate func writeFloat(_ writer: inout [UInt8], _ value: Float) { + writeInt(&writer, value.bitPattern) +} + +fileprivate func writeDouble(_ writer: inout [UInt8], _ value: Double) { + writeInt(&writer, value.bitPattern) +} + +// Protocol for types that transfer other types across the FFI. This is +// analogous to the Rust trait of the same name. +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: inout (data: Data, offset: Data.Index)) throws -> SwiftType + static func write(_ value: SwiftType, into buf: inout [UInt8]) +} + +// Types conforming to `Primitive` pass themselves directly over the FFI. +fileprivate protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType { } + +extension FfiConverterPrimitive { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func lift(_ value: FfiType) throws -> SwiftType { + return value + } + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public 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 { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func lift(_ buf: RustBuffer) throws -> SwiftType { + var reader = createReader(data: Data(rustBuffer: buf)) + let value = try read(from: &reader) + if hasRemaining(reader) { + throw UniffiInternalError.incompleteData + } + buf.deallocate() + return value + } + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func lower(_ value: SwiftType) -> RustBuffer { + var writer = createWriter() + write(value, into: &writer) + return RustBuffer(bytes: writer) + } +} +// 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 extension NSLock { + func withLock(f: () throws -> T) rethrows -> T { + self.lock() + defer { self.unlock() } + return try f() + } +} + +fileprivate let CALL_SUCCESS: Int8 = 0 +fileprivate let CALL_ERROR: Int8 = 1 +fileprivate let CALL_UNEXPECTED_ERROR: Int8 = 2 +fileprivate let CALL_CANCELLED: Int8 = 3 + +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 { + let neverThrow: ((RustBuffer) throws -> Never)? = nil + return try makeRustCall(callback, errorHandler: neverThrow) +} + +private func rustCallWithError( + _ errorHandler: @escaping (RustBuffer) throws -> E, + _ callback: (UnsafeMutablePointer) -> T) throws -> T { + try makeRustCall(callback, errorHandler: errorHandler) +} + +private func makeRustCall( + _ callback: (UnsafeMutablePointer) -> T, + errorHandler: ((RustBuffer) throws -> E)? +) throws -> T { + uniffiEnsureFfiInitialized() + var callStatus = RustCallStatus.init() + let returnedVal = callback(&callStatus) + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) + return returnedVal +} + +private func uniffiCheckCallStatus( + callStatus: RustCallStatus, + errorHandler: ((RustBuffer) throws -> E)? +) throws { + switch callStatus.code { + case CALL_SUCCESS: + return + + case CALL_ERROR: + if let errorHandler = errorHandler { + throw try errorHandler(callStatus.errorBuf) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.unexpectedRustCallError + } + + case CALL_UNEXPECTED_ERROR: + // 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") + } + + case CALL_CANCELLED: + fatalError("Cancellation not supported yet") + + default: + throw UniffiInternalError.unexpectedRustCallStatusCode + } +} + +private func uniffiTraitInterfaceCall( + callStatus: UnsafeMutablePointer, + makeCall: () throws -> T, + writeReturn: (T) -> () +) { + do { + try writeReturn(makeCall()) + } catch let error { + callStatus.pointee.code = CALL_UNEXPECTED_ERROR + callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error)) + } +} + +private func uniffiTraitInterfaceCallWithError( + callStatus: UnsafeMutablePointer, + makeCall: () throws -> T, + writeReturn: (T) -> (), + lowerError: (E) -> RustBuffer +) { + do { + try writeReturn(makeCall()) + } catch let error as E { + callStatus.pointee.code = CALL_ERROR + callStatus.pointee.errorBuf = lowerError(error) + } catch { + callStatus.pointee.code = CALL_UNEXPECTED_ERROR + callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error)) + } +} +// Initial value and increment amount for handles. +// These ensure that SWIFT handles always have the lowest bit set +fileprivate let UNIFFI_HANDLEMAP_INITIAL: UInt64 = 1 +fileprivate let UNIFFI_HANDLEMAP_DELTA: UInt64 = 2 + +fileprivate final class UniffiHandleMap: @unchecked Sendable { + // All mutation happens with this lock held, which is why we implement @unchecked Sendable. + private let lock = NSLock() + private var map: [UInt64: T] = [:] + private var currentHandle: UInt64 = UNIFFI_HANDLEMAP_INITIAL + + func insert(obj: T) -> UInt64 { + lock.withLock { + return doInsert(obj) + } + } + + // Low-level insert function, this assumes `lock` is held. + private func doInsert(_ obj: T) -> UInt64 { + let handle = currentHandle + currentHandle += UNIFFI_HANDLEMAP_DELTA + map[handle] = obj + return handle + } + + func get(handle: UInt64) throws -> T { + try lock.withLock { + guard let obj = map[handle] else { + throw UniffiInternalError.unexpectedStaleHandle + } + return obj + } + } + + func clone(handle: UInt64) throws -> UInt64 { + try lock.withLock { + guard let obj = map[handle] else { + throw UniffiInternalError.unexpectedStaleHandle + } + return doInsert(obj) + } + } + + @discardableResult + func remove(handle: UInt64) throws -> T { + try lock.withLock { + guard let obj = map.removeValue(forKey: handle) else { + throw UniffiInternalError.unexpectedStaleHandle + } + return obj + } + } + + var count: Int { + get { + map.count + } + } +} + + +// Public interface members begin here. +// Magic number for the Rust proxy to call using the same mechanism as every other method, +// to free the callback once it's dropped by Rust. +private let IDX_CALLBACK_FREE: Int32 = 0 +// Callback return codes +private let UNIFFI_CALLBACK_SUCCESS: Int32 = 0 +private let UNIFFI_CALLBACK_ERROR: Int32 = 1 +private let UNIFFI_CALLBACK_UNEXPECTED_ERROR: Int32 = 2 + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterUInt32: FfiConverterPrimitive { + typealias FfiType = UInt32 + typealias SwiftType = UInt32 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterFloat: FfiConverterPrimitive { + typealias FfiType = Float + typealias SwiftType = Float + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Float { + return try lift(readFloat(&buf)) + } + + public static func write(_ value: Float, into buf: inout [UInt8]) { + writeFloat(&buf, lower(value)) + } +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterString: FfiConverter { + typealias SwiftType = String + typealias FfiType = RustBuffer + + public 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)! + } + + public 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) + } + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { + let len: Int32 = try readInt(&buf) + return String(bytes: try readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! + } + + public static func write(_ value: String, into buf: inout [UInt8]) { + let len = Int32(value.utf8.count) + writeInt(&buf, len) + writeBytes(&buf, value.utf8) + } +} + + + + +public protocol WalletEngineProtocol: AnyObject, Sendable { + + func clearListener() throws + + func getBalanceSnapshot() throws -> BalanceSnapshot + + func pauseSync() throws + + /** + * ✅ UniFFI-friendly callback: Box + */ + func setListener(listener: WalletListener) throws + + func shutdown() throws + + func startSync() throws + +} +open class WalletEngine: WalletEngineProtocol, @unchecked Sendable { + fileprivate let handle: UInt64 + + /// Used to instantiate a [FFIObject] without an actual handle, for fakes in tests, mostly. +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public struct NoHandle { + public init() {} + } + + // 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`. +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + required public init(unsafeFromHandle handle: UInt64) { + self.handle = handle + } + + // This constructor can be used to instantiate a fake object. + // - Parameter noHandle: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing handle the FFI lower functions will crash. +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public init(noHandle: NoHandle) { + self.handle = 0 + } + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public func uniffiCloneHandle() -> UInt64 { + return try! rustCall { uniffi_ffi_fn_clone_walletengine(self.handle, $0) } + } +public convenience init()throws { + let handle = + try rustCallWithError(FfiConverterTypeWalletError_lift) { + uniffi_ffi_fn_constructor_walletengine_new($0 + ) +} + self.init(unsafeFromHandle: handle) +} + + deinit { + if handle == 0 { + // Mock objects have handle=0 don't try to free them + return + } + + try! rustCall { uniffi_ffi_fn_free_walletengine(handle, $0) } + } + + + + +open func clearListener()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { + uniffi_ffi_fn_method_walletengine_clear_listener( + self.uniffiCloneHandle(),$0 + ) +} +} + +open func getBalanceSnapshot()throws -> BalanceSnapshot { + return try FfiConverterTypeBalanceSnapshot_lift(try rustCallWithError(FfiConverterTypeWalletError_lift) { + uniffi_ffi_fn_method_walletengine_get_balance_snapshot( + self.uniffiCloneHandle(),$0 + ) +}) +} + +open func pauseSync()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { + uniffi_ffi_fn_method_walletengine_pause_sync( + self.uniffiCloneHandle(),$0 + ) +} +} + + /** + * ✅ UniFFI-friendly callback: Box + */ +open func setListener(listener: WalletListener)throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { + uniffi_ffi_fn_method_walletengine_set_listener( + self.uniffiCloneHandle(), + FfiConverterCallbackInterfaceWalletListener_lower(listener),$0 + ) +} +} + +open func shutdown()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { + uniffi_ffi_fn_method_walletengine_shutdown( + self.uniffiCloneHandle(),$0 + ) +} +} + +open func startSync()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { + uniffi_ffi_fn_method_walletengine_start_sync( + self.uniffiCloneHandle(),$0 + ) +} +} + + + +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeWalletEngine: FfiConverter { + typealias FfiType = UInt64 + typealias SwiftType = WalletEngine + + public static func lift(_ handle: UInt64) throws -> WalletEngine { + return WalletEngine(unsafeFromHandle: handle) + } + + public static func lower(_ value: WalletEngine) -> UInt64 { + return value.uniffiCloneHandle() + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> WalletEngine { + let handle: UInt64 = try readInt(&buf) + return try lift(handle) + } + + public static func write(_ value: WalletEngine, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeWalletEngine_lift(_ handle: UInt64) throws -> WalletEngine { + return try FfiConverterTypeWalletEngine.lift(handle) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeWalletEngine_lower(_ value: WalletEngine) -> UInt64 { + return FfiConverterTypeWalletEngine.lower(value) +} + + + + +public struct BalanceSnapshot: Equatable, Hashable { + public var confirmed: String + public var total: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(confirmed: String, total: String) { + self.confirmed = confirmed + self.total = total + } + + + + +} + +#if compiler(>=6) +extension BalanceSnapshot: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeBalanceSnapshot: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> BalanceSnapshot { + return + try BalanceSnapshot( + confirmed: FfiConverterString.read(from: &buf), + total: FfiConverterString.read(from: &buf) + ) + } + + public static func write(_ value: BalanceSnapshot, into buf: inout [UInt8]) { + FfiConverterString.write(value.confirmed, into: &buf) + FfiConverterString.write(value.total, into: &buf) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeBalanceSnapshot_lift(_ buf: RustBuffer) throws -> BalanceSnapshot { + return try FfiConverterTypeBalanceSnapshot.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeBalanceSnapshot_lower(_ value: BalanceSnapshot) -> RustBuffer { + return FfiConverterTypeBalanceSnapshot.lower(value) +} + + +public enum WalletError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { + + + + case CommandQueueClosed + case ListenerLockPoisoned + case Internal(String + ) + + + + + + + public var errorDescription: String? { + String(reflecting: self) + } + +} + +#if compiler(>=6) +extension WalletError: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeWalletError: FfiConverterRustBuffer { + typealias SwiftType = WalletError + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> WalletError { + let variant: Int32 = try readInt(&buf) + switch variant { + + + + + case 1: return .CommandQueueClosed + case 2: return .ListenerLockPoisoned + case 3: return .Internal( + try FfiConverterString.read(from: &buf) + ) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: WalletError, into buf: inout [UInt8]) { + switch value { + + + + + + case .CommandQueueClosed: + writeInt(&buf, Int32(1)) + + + case .ListenerLockPoisoned: + writeInt(&buf, Int32(2)) + + + case let .Internal(v1): + writeInt(&buf, Int32(3)) + FfiConverterString.write(v1, into: &buf) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeWalletError_lift(_ buf: RustBuffer) throws -> WalletError { + return try FfiConverterTypeWalletError.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeWalletError_lower(_ value: WalletError) -> RustBuffer { + return FfiConverterTypeWalletError.lower(value) +} + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum WalletEvent: Equatable, Hashable { + + case engineReady + case syncStarted + case syncProgress(walletHeight: UInt32, networkHeight: UInt32, percent: Float + ) + case syncPaused + case syncFinished + case balanceChanged(BalanceSnapshot + ) + case newTransaction(txid: String + ) + case error(code: String, message: String + ) + + + + + +} + +#if compiler(>=6) +extension WalletEvent: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeWalletEvent: FfiConverterRustBuffer { + typealias SwiftType = WalletEvent + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> WalletEvent { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .engineReady + + case 2: return .syncStarted + + case 3: return .syncProgress(walletHeight: try FfiConverterUInt32.read(from: &buf), networkHeight: try FfiConverterUInt32.read(from: &buf), percent: try FfiConverterFloat.read(from: &buf) + ) + + case 4: return .syncPaused + + case 5: return .syncFinished + + case 6: return .balanceChanged(try FfiConverterTypeBalanceSnapshot.read(from: &buf) + ) + + case 7: return .newTransaction(txid: try FfiConverterString.read(from: &buf) + ) + + case 8: return .error(code: try FfiConverterString.read(from: &buf), message: try FfiConverterString.read(from: &buf) + ) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: WalletEvent, into buf: inout [UInt8]) { + switch value { + + + case .engineReady: + writeInt(&buf, Int32(1)) + + + case .syncStarted: + writeInt(&buf, Int32(2)) + + + case let .syncProgress(walletHeight,networkHeight,percent): + writeInt(&buf, Int32(3)) + FfiConverterUInt32.write(walletHeight, into: &buf) + FfiConverterUInt32.write(networkHeight, into: &buf) + FfiConverterFloat.write(percent, into: &buf) + + + case .syncPaused: + writeInt(&buf, Int32(4)) + + + case .syncFinished: + writeInt(&buf, Int32(5)) + + + case let .balanceChanged(v1): + writeInt(&buf, Int32(6)) + FfiConverterTypeBalanceSnapshot.write(v1, into: &buf) + + + case let .newTransaction(txid): + writeInt(&buf, Int32(7)) + FfiConverterString.write(txid, into: &buf) + + + case let .error(code,message): + writeInt(&buf, Int32(8)) + FfiConverterString.write(code, into: &buf) + FfiConverterString.write(message, into: &buf) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeWalletEvent_lift(_ buf: RustBuffer) throws -> WalletEvent { + return try FfiConverterTypeWalletEvent.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeWalletEvent_lower(_ value: WalletEvent) -> RustBuffer { + return FfiConverterTypeWalletEvent.lower(value) +} + + + + + +public protocol WalletListener: AnyObject, Sendable { + + func onEvent(event: WalletEvent) + +} + + +// Put the implementation in a struct so we don't pollute the top-level namespace +fileprivate struct UniffiCallbackInterfaceWalletListener { + + // Create the VTable using a series of closures. + // Swift automatically converts these into C callback functions. + // + // This creates 1-element array, since this seems to be the only way to construct a const + // pointer that we can pass to the Rust code. + static let vtable: [UniffiVTableCallbackInterfaceWalletListener] = [UniffiVTableCallbackInterfaceWalletListener( + uniffiFree: { (uniffiHandle: UInt64) -> () in + do { + try FfiConverterCallbackInterfaceWalletListener.handleMap.remove(handle: uniffiHandle) + } catch { + print("Uniffi callback interface WalletListener: handle missing in uniffiFree") + } + }, + uniffiClone: { (uniffiHandle: UInt64) -> UInt64 in + do { + return try FfiConverterCallbackInterfaceWalletListener.handleMap.clone(handle: uniffiHandle) + } catch { + fatalError("Uniffi callback interface WalletListener: handle missing in uniffiClone") + } + }, + onEvent: { ( + uniffiHandle: UInt64, + event: RustBuffer, + uniffiOutReturn: UnsafeMutableRawPointer, + uniffiCallStatus: UnsafeMutablePointer + ) in + let makeCall = { + () throws -> () in + guard let uniffiObj = try? FfiConverterCallbackInterfaceWalletListener.handleMap.get(handle: uniffiHandle) else { + throw UniffiInternalError.unexpectedStaleHandle + } + return uniffiObj.onEvent( + event: try FfiConverterTypeWalletEvent_lift(event) + ) + } + + + let writeReturn = { () } + uniffiTraitInterfaceCall( + callStatus: uniffiCallStatus, + makeCall: makeCall, + writeReturn: writeReturn + ) + } + )] +} + +private func uniffiCallbackInitWalletListener() { + uniffi_ffi_fn_init_callback_vtable_walletlistener(UniffiCallbackInterfaceWalletListener.vtable) +} + +// FfiConverter protocol for callback interfaces +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterCallbackInterfaceWalletListener { + fileprivate static let handleMap = UniffiHandleMap() +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +extension FfiConverterCallbackInterfaceWalletListener : FfiConverter { + typealias SwiftType = WalletListener + typealias FfiType = UInt64 + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func lift(_ handle: UInt64) throws -> SwiftType { + try handleMap.get(handle: handle) + } + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + let handle: UInt64 = try readInt(&buf) + return try lift(handle) + } + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func lower(_ v: SwiftType) -> UInt64 { + return handleMap.insert(obj: v) + } + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func write(_ v: SwiftType, into buf: inout [UInt8]) { + writeInt(&buf, lower(v)) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterCallbackInterfaceWalletListener_lift(_ handle: UInt64) throws -> WalletListener { + return try FfiConverterCallbackInterfaceWalletListener.lift(handle) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterCallbackInterfaceWalletListener_lower(_ v: WalletListener) -> UInt64 { + return FfiConverterCallbackInterfaceWalletListener.lower(v) +} + +private enum InitializationResult { + case ok + case contractVersionMismatch + case apiChecksumMismatch +} +// Use a global variable to perform the versioning checks. Swift ensures that +// the code inside is only computed once. +private let initializationResult: InitializationResult = { + // Get the bindings contract version from our ComponentInterface + let bindings_contract_version = 30 + // Get the scaffolding contract version by calling the into the dylib + let scaffolding_contract_version = ffi_ffi_uniffi_contract_version() + if bindings_contract_version != scaffolding_contract_version { + return InitializationResult.contractVersionMismatch + } + if (uniffi_ffi_checksum_method_walletengine_clear_listener() != 65358) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_ffi_checksum_method_walletengine_get_balance_snapshot() != 57923) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_ffi_checksum_method_walletengine_pause_sync() != 29290) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_ffi_checksum_method_walletengine_set_listener() != 8699) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_ffi_checksum_method_walletengine_shutdown() != 23734) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_ffi_checksum_method_walletengine_start_sync() != 42941) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_ffi_checksum_constructor_walletengine_new() != 45836) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_ffi_checksum_method_walletlistener_on_event() != 26795) { + return InitializationResult.apiChecksumMismatch + } + + uniffiCallbackInitWalletListener() + return InitializationResult.ok +}() + +// Make the ensure init function public so that other modules which have external type references to +// our types can call it. +public func uniffiEnsureFfiInitialized() { + switch initializationResult { + case .ok: + break + case .contractVersionMismatch: + fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") + case .apiChecksumMismatch: + fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } +} + +// swiftlint:enable all \ No newline at end of file diff --git a/ffi/ios/WalletModule/Generated/ffiFFI.h b/ffi/ios/WalletModule/Generated/ffiFFI.h new file mode 100644 index 000000000..59db60430 --- /dev/null +++ b/ffi/ios/WalletModule/Generated/ffiFFI.h @@ -0,0 +1,627 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! + +#pragma once + +#include +#include +#include + +// The following structs are used to implement the lowest level +// of the FFI, and thus useful to multiple uniffied crates. +// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H. +#ifdef UNIFFI_SHARED_H + // We also try to prevent mixing versions of shared uniffi header structs. + // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4 + #ifndef UNIFFI_SHARED_HEADER_V4 + #error Combining helper code from multiple versions of uniffi is not supported + #endif // ndef UNIFFI_SHARED_HEADER_V4 +#else +#define UNIFFI_SHARED_H +#define UNIFFI_SHARED_HEADER_V4 +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ + +typedef struct RustBuffer +{ + uint64_t capacity; + uint64_t len; + uint8_t *_Nullable data; +} RustBuffer; + +typedef struct ForeignBytes +{ + int32_t len; + const uint8_t *_Nullable data; +} ForeignBytes; + +// Error definitions +typedef struct RustCallStatus { + int8_t code; + RustBuffer errorBuf; +} RustCallStatus; + +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ +#endif // def UNIFFI_SHARED_H +#ifndef UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK +#define UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK +typedef void (*UniffiRustFutureContinuationCallback)(uint64_t, int8_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK +typedef void (*UniffiForeignFutureDroppedCallback)(uint64_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE +#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE +typedef void (*UniffiCallbackInterfaceFree)(uint64_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE +#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE +typedef uint64_t (*UniffiCallbackInterfaceClone)(uint64_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT +typedef struct UniffiForeignFutureDroppedCallbackStruct { + uint64_t handle; + UniffiForeignFutureDroppedCallback _Nonnull free; +} UniffiForeignFutureDroppedCallbackStruct; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8 +typedef struct UniffiForeignFutureResultU8 { + uint8_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU8; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8 +typedef void (*UniffiForeignFutureCompleteU8)(uint64_t, UniffiForeignFutureResultU8 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8 +typedef struct UniffiForeignFutureResultI8 { + int8_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI8; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8 +typedef void (*UniffiForeignFutureCompleteI8)(uint64_t, UniffiForeignFutureResultI8 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16 +typedef struct UniffiForeignFutureResultU16 { + uint16_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU16; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16 +typedef void (*UniffiForeignFutureCompleteU16)(uint64_t, UniffiForeignFutureResultU16 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16 +typedef struct UniffiForeignFutureResultI16 { + int16_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI16; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16 +typedef void (*UniffiForeignFutureCompleteI16)(uint64_t, UniffiForeignFutureResultI16 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32 +typedef struct UniffiForeignFutureResultU32 { + uint32_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU32; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32 +typedef void (*UniffiForeignFutureCompleteU32)(uint64_t, UniffiForeignFutureResultU32 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32 +typedef struct UniffiForeignFutureResultI32 { + int32_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI32; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32 +typedef void (*UniffiForeignFutureCompleteI32)(uint64_t, UniffiForeignFutureResultI32 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64 +typedef struct UniffiForeignFutureResultU64 { + uint64_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU64; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64 +typedef void (*UniffiForeignFutureCompleteU64)(uint64_t, UniffiForeignFutureResultU64 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64 +typedef struct UniffiForeignFutureResultI64 { + int64_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI64; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64 +typedef void (*UniffiForeignFutureCompleteI64)(uint64_t, UniffiForeignFutureResultI64 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32 +typedef struct UniffiForeignFutureResultF32 { + float returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultF32; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32 +typedef void (*UniffiForeignFutureCompleteF32)(uint64_t, UniffiForeignFutureResultF32 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64 +typedef struct UniffiForeignFutureResultF64 { + double returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultF64; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64 +typedef void (*UniffiForeignFutureCompleteF64)(uint64_t, UniffiForeignFutureResultF64 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER +typedef struct UniffiForeignFutureResultRustBuffer { + RustBuffer returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultRustBuffer; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER +typedef void (*UniffiForeignFutureCompleteRustBuffer)(uint64_t, UniffiForeignFutureResultRustBuffer + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID +typedef struct UniffiForeignFutureResultVoid { + RustCallStatus callStatus; +} UniffiForeignFutureResultVoid; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID +typedef void (*UniffiForeignFutureCompleteVoid)(uint64_t, UniffiForeignFutureResultVoid + ); + +#endif +#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_WALLET_LISTENER_METHOD0 +#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_WALLET_LISTENER_METHOD0 +typedef void (*UniffiCallbackInterfaceWalletListenerMethod0)(uint64_t, RustBuffer, void* _Nonnull, + RustCallStatus *_Nonnull uniffiCallStatus + ); + +#endif +#ifndef UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_WALLET_LISTENER +#define UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_WALLET_LISTENER +typedef struct UniffiVTableCallbackInterfaceWalletListener { + UniffiCallbackInterfaceFree _Nonnull uniffiFree; + UniffiCallbackInterfaceClone _Nonnull uniffiClone; + UniffiCallbackInterfaceWalletListenerMethod0 _Nonnull onEvent; +} UniffiVTableCallbackInterfaceWalletListener; + +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_CLONE_WALLETENGINE +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_CLONE_WALLETENGINE +uint64_t uniffi_ffi_fn_clone_walletengine(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_FREE_WALLETENGINE +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_FREE_WALLETENGINE +void uniffi_ffi_fn_free_walletengine(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_CONSTRUCTOR_WALLETENGINE_NEW +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_CONSTRUCTOR_WALLETENGINE_NEW +uint64_t uniffi_ffi_fn_constructor_walletengine_new(RustCallStatus *_Nonnull out_status + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_CLEAR_LISTENER +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_CLEAR_LISTENER +void uniffi_ffi_fn_method_walletengine_clear_listener(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT +RustBuffer uniffi_ffi_fn_method_walletengine_get_balance_snapshot(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_PAUSE_SYNC +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_PAUSE_SYNC +void uniffi_ffi_fn_method_walletengine_pause_sync(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SET_LISTENER +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SET_LISTENER +void uniffi_ffi_fn_method_walletengine_set_listener(uint64_t ptr, uint64_t listener, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SHUTDOWN +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SHUTDOWN +void uniffi_ffi_fn_method_walletengine_shutdown(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_START_SYNC +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_START_SYNC +void uniffi_ffi_fn_method_walletengine_start_sync(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_INIT_CALLBACK_VTABLE_WALLETLISTENER +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_INIT_CALLBACK_VTABLE_WALLETLISTENER +void uniffi_ffi_fn_init_callback_vtable_walletlistener(const UniffiVTableCallbackInterfaceWalletListener* _Nonnull vtable +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_ALLOC +#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_ALLOC +RustBuffer ffi_ffi_rustbuffer_alloc(uint64_t size, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FROM_BYTES +#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FROM_BYTES +RustBuffer ffi_ffi_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FREE +#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FREE +void ffi_ffi_rustbuffer_free(RustBuffer buf, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_RESERVE +#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_RESERVE +RustBuffer ffi_ffi_rustbuffer_reserve(RustBuffer buf, uint64_t additional, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U8 +void ffi_ffi_rust_future_poll_u8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U8 +void ffi_ffi_rust_future_cancel_u8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U8 +void ffi_ffi_rust_future_free_u8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U8 +uint8_t ffi_ffi_rust_future_complete_u8(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I8 +void ffi_ffi_rust_future_poll_i8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I8 +void ffi_ffi_rust_future_cancel_i8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I8 +void ffi_ffi_rust_future_free_i8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I8 +int8_t ffi_ffi_rust_future_complete_i8(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U16 +void ffi_ffi_rust_future_poll_u16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U16 +void ffi_ffi_rust_future_cancel_u16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U16 +void ffi_ffi_rust_future_free_u16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U16 +uint16_t ffi_ffi_rust_future_complete_u16(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I16 +void ffi_ffi_rust_future_poll_i16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I16 +void ffi_ffi_rust_future_cancel_i16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I16 +void ffi_ffi_rust_future_free_i16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I16 +int16_t ffi_ffi_rust_future_complete_i16(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U32 +void ffi_ffi_rust_future_poll_u32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U32 +void ffi_ffi_rust_future_cancel_u32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U32 +void ffi_ffi_rust_future_free_u32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U32 +uint32_t ffi_ffi_rust_future_complete_u32(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I32 +void ffi_ffi_rust_future_poll_i32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I32 +void ffi_ffi_rust_future_cancel_i32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I32 +void ffi_ffi_rust_future_free_i32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I32 +int32_t ffi_ffi_rust_future_complete_i32(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U64 +void ffi_ffi_rust_future_poll_u64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U64 +void ffi_ffi_rust_future_cancel_u64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U64 +void ffi_ffi_rust_future_free_u64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U64 +uint64_t ffi_ffi_rust_future_complete_u64(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I64 +void ffi_ffi_rust_future_poll_i64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I64 +void ffi_ffi_rust_future_cancel_i64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I64 +void ffi_ffi_rust_future_free_i64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I64 +int64_t ffi_ffi_rust_future_complete_i64(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F32 +void ffi_ffi_rust_future_poll_f32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F32 +void ffi_ffi_rust_future_cancel_f32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F32 +void ffi_ffi_rust_future_free_f32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F32 +float ffi_ffi_rust_future_complete_f32(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F64 +void ffi_ffi_rust_future_poll_f64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F64 +void ffi_ffi_rust_future_cancel_f64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F64 +void ffi_ffi_rust_future_free_f64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F64 +double ffi_ffi_rust_future_complete_f64(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_RUST_BUFFER +void ffi_ffi_rust_future_poll_rust_buffer(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_RUST_BUFFER +void ffi_ffi_rust_future_cancel_rust_buffer(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_RUST_BUFFER +void ffi_ffi_rust_future_free_rust_buffer(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_RUST_BUFFER +RustBuffer ffi_ffi_rust_future_complete_rust_buffer(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_VOID +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_VOID +void ffi_ffi_rust_future_poll_void(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_VOID +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_VOID +void ffi_ffi_rust_future_cancel_void(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_VOID +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_VOID +void ffi_ffi_rust_future_free_void(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_VOID +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_VOID +void ffi_ffi_rust_future_complete_void(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_CLEAR_LISTENER +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_CLEAR_LISTENER +uint16_t uniffi_ffi_checksum_method_walletengine_clear_listener(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT +uint16_t uniffi_ffi_checksum_method_walletengine_get_balance_snapshot(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_PAUSE_SYNC +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_PAUSE_SYNC +uint16_t uniffi_ffi_checksum_method_walletengine_pause_sync(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SET_LISTENER +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SET_LISTENER +uint16_t uniffi_ffi_checksum_method_walletengine_set_listener(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SHUTDOWN +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SHUTDOWN +uint16_t uniffi_ffi_checksum_method_walletengine_shutdown(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_START_SYNC +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_START_SYNC +uint16_t uniffi_ffi_checksum_method_walletengine_start_sync(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_CONSTRUCTOR_WALLETENGINE_NEW +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_CONSTRUCTOR_WALLETENGINE_NEW +uint16_t uniffi_ffi_checksum_constructor_walletengine_new(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETLISTENER_ON_EVENT +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETLISTENER_ON_EVENT +uint16_t uniffi_ffi_checksum_method_walletlistener_on_event(void + +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_UNIFFI_CONTRACT_VERSION +#define UNIFFI_FFIDEF_FFI_FFI_UNIFFI_CONTRACT_VERSION +uint32_t ffi_ffi_uniffi_contract_version(void + +); +#endif + diff --git a/ffi/ios/WalletModule/Generated/ffiFFI.modulemap b/ffi/ios/WalletModule/Generated/ffiFFI.modulemap new file mode 100644 index 000000000..5507d8a8e --- /dev/null +++ b/ffi/ios/WalletModule/Generated/ffiFFI.modulemap @@ -0,0 +1,7 @@ +module ffiFFI { + header "ffiFFI.h" + export * + use "Darwin" + use "_Builtin_stdbool" + use "_Builtin_stdint" +} \ No newline at end of file diff --git a/ffi/ios/WalletModule/WalletModule.podspec b/ffi/ios/WalletModule/WalletModule.podspec new file mode 100644 index 000000000..9bed2bf12 --- /dev/null +++ b/ffi/ios/WalletModule/WalletModule.podspec @@ -0,0 +1,17 @@ +Pod::Spec.new do |s| + s.name = "WalletModule" + s.version = "0.1.0" + s.summary = "Rust wallet engine RN bridge" + s.platforms = { :ios => "13.0" } + s.source = { :path => "." } + s.source_files = "**/*.{h,m,mm,swift}" + s.swift_version = "5.0" + + # UniFFI generated Swift: + s.source_files += "Generated/**/*.{swift,h}" + + # Rust static lib(s) you built for iOS: + s.vendored_libraries = "RustLibs/*.a" + + s.dependency "React-Core" +end diff --git a/ffi/ios/WalletSDK/.gitignore b/ffi/ios/WalletSDK/.gitignore new file mode 100644 index 000000000..2b10e7795 --- /dev/null +++ b/ffi/ios/WalletSDK/.gitignore @@ -0,0 +1,3 @@ +.build +.swiftpm +Binaries/WalletFFI.xcframework/ios-* diff --git a/ffi/ios/WalletSDK/Binaries/WalletFFI.xcframework/Info.plist b/ffi/ios/WalletSDK/Binaries/WalletFFI.xcframework/Info.plist new file mode 100644 index 000000000..d31bdb13d --- /dev/null +++ b/ffi/ios/WalletSDK/Binaries/WalletFFI.xcframework/Info.plist @@ -0,0 +1,43 @@ + + + + + AvailableLibraries + + + BinaryPath + libffi.dylib + LibraryIdentifier + ios-arm64-simulator + LibraryPath + libffi.dylib + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + BinaryPath + libffi.dylib + LibraryIdentifier + ios-arm64 + LibraryPath + libffi.dylib + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/ffi/ios/WalletSDK/Package.swift b/ffi/ios/WalletSDK/Package.swift new file mode 100644 index 000000000..430f7a8cd --- /dev/null +++ b/ffi/ios/WalletSDK/Package.swift @@ -0,0 +1,37 @@ +// swift-tools-version: 5.9 +import PackageDescription + +let package = Package( + name: "WalletSDK", + platforms: [.iOS(.v13)], + products: [ + .library(name: "WalletSDK", targets: ["WalletSDK"]) + ], + targets: [ + .binaryTarget( + name: "WalletFFI", + path: "Binaries/WalletFFI.xcframework" + ), + + .systemLibrary( + name: "ffiFFI", + path: "Sources/ffiFFI" + ), + + .target( + name: "WalletSDK", + dependencies: ["WalletFFI", "ffiFFI"], + path: "Sources/WalletSDK", + sources: [ + "WalletSDK.swift", + "Generated/ffi.swift", + ] + ), + + .testTarget( + name: "WalletSDKTests", + dependencies: ["WalletSDK"], + path: "Tests/WalletSDKTests" + ), + ] +) diff --git a/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffi.swift b/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffi.swift new file mode 100644 index 000000000..eb1827cfa --- /dev/null +++ b/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffi.swift @@ -0,0 +1,1118 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! + +// swiftlint:disable all +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(ffiFFI) +import ffiFFI +#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 empty() -> RustBuffer { + RustBuffer(capacity: 0, len:0, data: nil) + } + + static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { + try! rustCall { ffi_ffi_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_ffi_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 library of its own. + +fileprivate extension Data { + init(rustBuffer: RustBuffer) { + self.init( + bytesNoCopy: rustBuffer.data!, + count: Int(rustBuffer.len), + deallocator: .none + ) + } +} + +// Define reader functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. +// +// With external types, one swift source file needs to be able to call the read +// method on another source file's FfiConverter, but then what visibility +// should Reader have? +// - If Reader is fileprivate, then this means the read() must also +// be fileprivate, which doesn't work with external types. +// - If Reader is internal/public, we'll get compile errors since both source +// files will try define the same type. +// +// Instead, the read() method and these helper functions input a tuple of data + +fileprivate func createReader(data: Data) -> (data: Data, offset: Data.Index) { + (data: data, offset: 0) +} + +// Reads an integer at the current offset, in big-endian order, and advances +// the offset on success. Throws if reading the integer would move the +// offset past the end of the buffer. +fileprivate func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { + let range = reader.offset...size + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + if T.self == UInt8.self { + let value = reader.data[reader.offset] + reader.offset += 1 + return value as! T + } + var value: T = 0 + let _ = withUnsafeMutableBytes(of: &value, { reader.data.copyBytes(to: $0, from: range)}) + reader.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 +fileprivate func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> Array { + let range = reader.offset..<(reader.offset+count) + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + var value = [UInt8](repeating: 0, count: count) + value.withUnsafeMutableBufferPointer({ buffer in + reader.data.copyBytes(to: buffer, from: range) + }) + reader.offset = range.upperBound + return value +} + +// Reads a float at the current offset. +fileprivate func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { + return Float(bitPattern: try readInt(&reader)) +} + +// Reads a float at the current offset. +fileprivate func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { + return Double(bitPattern: try readInt(&reader)) +} + +// Indicates if the offset has reached the end of the buffer. +fileprivate func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { + return reader.offset < reader.data.count +} + +// Define writer functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. See the above discussion on Readers for details. + +fileprivate func createWriter() -> [UInt8] { + return [] +} + +fileprivate func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { + writer.append(contentsOf: byteArr) +} + +// Writes an integer in big-endian order. +// +// Warning: make sure what you are trying to write +// is in the correct type! +fileprivate func writeInt(_ writer: inout [UInt8], _ value: T) { + var value = value.bigEndian + withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } +} + +fileprivate func writeFloat(_ writer: inout [UInt8], _ value: Float) { + writeInt(&writer, value.bitPattern) +} + +fileprivate func writeDouble(_ writer: inout [UInt8], _ value: Double) { + writeInt(&writer, value.bitPattern) +} + +// Protocol for types that transfer other types across the FFI. This is +// analogous to the Rust trait of the same name. +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: inout (data: Data, offset: Data.Index)) throws -> SwiftType + static func write(_ value: SwiftType, into buf: inout [UInt8]) +} + +// Types conforming to `Primitive` pass themselves directly over the FFI. +fileprivate protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType { } + +extension FfiConverterPrimitive { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func lift(_ value: FfiType) throws -> SwiftType { + return value + } + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public 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 { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func lift(_ buf: RustBuffer) throws -> SwiftType { + var reader = createReader(data: Data(rustBuffer: buf)) + let value = try read(from: &reader) + if hasRemaining(reader) { + throw UniffiInternalError.incompleteData + } + buf.deallocate() + return value + } + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func lower(_ value: SwiftType) -> RustBuffer { + var writer = createWriter() + write(value, into: &writer) + return RustBuffer(bytes: writer) + } +} +// 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 extension NSLock { + func withLock(f: () throws -> T) rethrows -> T { + self.lock() + defer { self.unlock() } + return try f() + } +} + +fileprivate let CALL_SUCCESS: Int8 = 0 +fileprivate let CALL_ERROR: Int8 = 1 +fileprivate let CALL_UNEXPECTED_ERROR: Int8 = 2 +fileprivate let CALL_CANCELLED: Int8 = 3 + +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 { + let neverThrow: ((RustBuffer) throws -> Never)? = nil + return try makeRustCall(callback, errorHandler: neverThrow) +} + +private func rustCallWithError( + _ errorHandler: @escaping (RustBuffer) throws -> E, + _ callback: (UnsafeMutablePointer) -> T) throws -> T { + try makeRustCall(callback, errorHandler: errorHandler) +} + +private func makeRustCall( + _ callback: (UnsafeMutablePointer) -> T, + errorHandler: ((RustBuffer) throws -> E)? +) throws -> T { + uniffiEnsureFfiInitialized() + var callStatus = RustCallStatus.init() + let returnedVal = callback(&callStatus) + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) + return returnedVal +} + +private func uniffiCheckCallStatus( + callStatus: RustCallStatus, + errorHandler: ((RustBuffer) throws -> E)? +) throws { + switch callStatus.code { + case CALL_SUCCESS: + return + + case CALL_ERROR: + if let errorHandler = errorHandler { + throw try errorHandler(callStatus.errorBuf) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.unexpectedRustCallError + } + + case CALL_UNEXPECTED_ERROR: + // 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") + } + + case CALL_CANCELLED: + fatalError("Cancellation not supported yet") + + default: + throw UniffiInternalError.unexpectedRustCallStatusCode + } +} + +private func uniffiTraitInterfaceCall( + callStatus: UnsafeMutablePointer, + makeCall: () throws -> T, + writeReturn: (T) -> () +) { + do { + try writeReturn(makeCall()) + } catch let error { + callStatus.pointee.code = CALL_UNEXPECTED_ERROR + callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error)) + } +} + +private func uniffiTraitInterfaceCallWithError( + callStatus: UnsafeMutablePointer, + makeCall: () throws -> T, + writeReturn: (T) -> (), + lowerError: (E) -> RustBuffer +) { + do { + try writeReturn(makeCall()) + } catch let error as E { + callStatus.pointee.code = CALL_ERROR + callStatus.pointee.errorBuf = lowerError(error) + } catch { + callStatus.pointee.code = CALL_UNEXPECTED_ERROR + callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error)) + } +} +// Initial value and increment amount for handles. +// These ensure that SWIFT handles always have the lowest bit set +fileprivate let UNIFFI_HANDLEMAP_INITIAL: UInt64 = 1 +fileprivate let UNIFFI_HANDLEMAP_DELTA: UInt64 = 2 + +fileprivate final class UniffiHandleMap: @unchecked Sendable { + // All mutation happens with this lock held, which is why we implement @unchecked Sendable. + private let lock = NSLock() + private var map: [UInt64: T] = [:] + private var currentHandle: UInt64 = UNIFFI_HANDLEMAP_INITIAL + + func insert(obj: T) -> UInt64 { + lock.withLock { + return doInsert(obj) + } + } + + // Low-level insert function, this assumes `lock` is held. + private func doInsert(_ obj: T) -> UInt64 { + let handle = currentHandle + currentHandle += UNIFFI_HANDLEMAP_DELTA + map[handle] = obj + return handle + } + + func get(handle: UInt64) throws -> T { + try lock.withLock { + guard let obj = map[handle] else { + throw UniffiInternalError.unexpectedStaleHandle + } + return obj + } + } + + func clone(handle: UInt64) throws -> UInt64 { + try lock.withLock { + guard let obj = map[handle] else { + throw UniffiInternalError.unexpectedStaleHandle + } + return doInsert(obj) + } + } + + @discardableResult + func remove(handle: UInt64) throws -> T { + try lock.withLock { + guard let obj = map.removeValue(forKey: handle) else { + throw UniffiInternalError.unexpectedStaleHandle + } + return obj + } + } + + var count: Int { + get { + map.count + } + } +} + + +// Public interface members begin here. +// Magic number for the Rust proxy to call using the same mechanism as every other method, +// to free the callback once it's dropped by Rust. +private let IDX_CALLBACK_FREE: Int32 = 0 +// Callback return codes +private let UNIFFI_CALLBACK_SUCCESS: Int32 = 0 +private let UNIFFI_CALLBACK_ERROR: Int32 = 1 +private let UNIFFI_CALLBACK_UNEXPECTED_ERROR: Int32 = 2 + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterUInt32: FfiConverterPrimitive { + typealias FfiType = UInt32 + typealias SwiftType = UInt32 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterFloat: FfiConverterPrimitive { + typealias FfiType = Float + typealias SwiftType = Float + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Float { + return try lift(readFloat(&buf)) + } + + public static func write(_ value: Float, into buf: inout [UInt8]) { + writeFloat(&buf, lower(value)) + } +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterString: FfiConverter { + typealias SwiftType = String + typealias FfiType = RustBuffer + + public 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)! + } + + public 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) + } + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { + let len: Int32 = try readInt(&buf) + return String(bytes: try readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! + } + + public static func write(_ value: String, into buf: inout [UInt8]) { + let len = Int32(value.utf8.count) + writeInt(&buf, len) + writeBytes(&buf, value.utf8) + } +} + + + + +public protocol WalletEngineProtocol: AnyObject, Sendable { + + func clearListener() throws + + func getBalanceSnapshot() throws -> BalanceSnapshot + + func pauseSync() throws + + /** + * ✅ UniFFI-friendly callback: Box + */ + func setListener(listener: WalletListener) throws + + func shutdown() throws + + func startSync() throws + +} +open class WalletEngine: WalletEngineProtocol, @unchecked Sendable { + fileprivate let handle: UInt64 + + /// Used to instantiate a [FFIObject] without an actual handle, for fakes in tests, mostly. +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public struct NoHandle { + public init() {} + } + + // 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`. +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + required public init(unsafeFromHandle handle: UInt64) { + self.handle = handle + } + + // This constructor can be used to instantiate a fake object. + // - Parameter noHandle: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing handle the FFI lower functions will crash. +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public init(noHandle: NoHandle) { + self.handle = 0 + } + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public func uniffiCloneHandle() -> UInt64 { + return try! rustCall { uniffi_ffi_fn_clone_walletengine(self.handle, $0) } + } +public convenience init()throws { + let handle = + try rustCallWithError(FfiConverterTypeWalletError_lift) { + uniffi_ffi_fn_constructor_walletengine_new($0 + ) +} + self.init(unsafeFromHandle: handle) +} + + deinit { + if handle == 0 { + // Mock objects have handle=0 don't try to free them + return + } + + try! rustCall { uniffi_ffi_fn_free_walletengine(handle, $0) } + } + + + + +open func clearListener()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { + uniffi_ffi_fn_method_walletengine_clear_listener( + self.uniffiCloneHandle(),$0 + ) +} +} + +open func getBalanceSnapshot()throws -> BalanceSnapshot { + return try FfiConverterTypeBalanceSnapshot_lift(try rustCallWithError(FfiConverterTypeWalletError_lift) { + uniffi_ffi_fn_method_walletengine_get_balance_snapshot( + self.uniffiCloneHandle(),$0 + ) +}) +} + +open func pauseSync()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { + uniffi_ffi_fn_method_walletengine_pause_sync( + self.uniffiCloneHandle(),$0 + ) +} +} + + /** + * ✅ UniFFI-friendly callback: Box + */ +open func setListener(listener: WalletListener)throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { + uniffi_ffi_fn_method_walletengine_set_listener( + self.uniffiCloneHandle(), + FfiConverterCallbackInterfaceWalletListener_lower(listener),$0 + ) +} +} + +open func shutdown()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { + uniffi_ffi_fn_method_walletengine_shutdown( + self.uniffiCloneHandle(),$0 + ) +} +} + +open func startSync()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { + uniffi_ffi_fn_method_walletengine_start_sync( + self.uniffiCloneHandle(),$0 + ) +} +} + + + +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeWalletEngine: FfiConverter { + typealias FfiType = UInt64 + typealias SwiftType = WalletEngine + + public static func lift(_ handle: UInt64) throws -> WalletEngine { + return WalletEngine(unsafeFromHandle: handle) + } + + public static func lower(_ value: WalletEngine) -> UInt64 { + return value.uniffiCloneHandle() + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> WalletEngine { + let handle: UInt64 = try readInt(&buf) + return try lift(handle) + } + + public static func write(_ value: WalletEngine, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeWalletEngine_lift(_ handle: UInt64) throws -> WalletEngine { + return try FfiConverterTypeWalletEngine.lift(handle) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeWalletEngine_lower(_ value: WalletEngine) -> UInt64 { + return FfiConverterTypeWalletEngine.lower(value) +} + + + + +public struct BalanceSnapshot: Equatable, Hashable { + public var confirmed: String + public var total: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(confirmed: String, total: String) { + self.confirmed = confirmed + self.total = total + } + + + + +} + +#if compiler(>=6) +extension BalanceSnapshot: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeBalanceSnapshot: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> BalanceSnapshot { + return + try BalanceSnapshot( + confirmed: FfiConverterString.read(from: &buf), + total: FfiConverterString.read(from: &buf) + ) + } + + public static func write(_ value: BalanceSnapshot, into buf: inout [UInt8]) { + FfiConverterString.write(value.confirmed, into: &buf) + FfiConverterString.write(value.total, into: &buf) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeBalanceSnapshot_lift(_ buf: RustBuffer) throws -> BalanceSnapshot { + return try FfiConverterTypeBalanceSnapshot.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeBalanceSnapshot_lower(_ value: BalanceSnapshot) -> RustBuffer { + return FfiConverterTypeBalanceSnapshot.lower(value) +} + + +public enum WalletError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { + + + + case CommandQueueClosed + case ListenerLockPoisoned + case Internal(String + ) + + + + + + + public var errorDescription: String? { + String(reflecting: self) + } + +} + +#if compiler(>=6) +extension WalletError: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeWalletError: FfiConverterRustBuffer { + typealias SwiftType = WalletError + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> WalletError { + let variant: Int32 = try readInt(&buf) + switch variant { + + + + + case 1: return .CommandQueueClosed + case 2: return .ListenerLockPoisoned + case 3: return .Internal( + try FfiConverterString.read(from: &buf) + ) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: WalletError, into buf: inout [UInt8]) { + switch value { + + + + + + case .CommandQueueClosed: + writeInt(&buf, Int32(1)) + + + case .ListenerLockPoisoned: + writeInt(&buf, Int32(2)) + + + case let .Internal(v1): + writeInt(&buf, Int32(3)) + FfiConverterString.write(v1, into: &buf) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeWalletError_lift(_ buf: RustBuffer) throws -> WalletError { + return try FfiConverterTypeWalletError.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeWalletError_lower(_ value: WalletError) -> RustBuffer { + return FfiConverterTypeWalletError.lower(value) +} + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum WalletEvent: Equatable, Hashable { + + case engineReady + case syncStarted + case syncProgress(walletHeight: UInt32, networkHeight: UInt32, percent: Float + ) + case syncPaused + case syncFinished + case balanceChanged(BalanceSnapshot + ) + case newTransaction(txid: String + ) + case error(code: String, message: String + ) + + + + + +} + +#if compiler(>=6) +extension WalletEvent: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeWalletEvent: FfiConverterRustBuffer { + typealias SwiftType = WalletEvent + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> WalletEvent { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .engineReady + + case 2: return .syncStarted + + case 3: return .syncProgress(walletHeight: try FfiConverterUInt32.read(from: &buf), networkHeight: try FfiConverterUInt32.read(from: &buf), percent: try FfiConverterFloat.read(from: &buf) + ) + + case 4: return .syncPaused + + case 5: return .syncFinished + + case 6: return .balanceChanged(try FfiConverterTypeBalanceSnapshot.read(from: &buf) + ) + + case 7: return .newTransaction(txid: try FfiConverterString.read(from: &buf) + ) + + case 8: return .error(code: try FfiConverterString.read(from: &buf), message: try FfiConverterString.read(from: &buf) + ) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: WalletEvent, into buf: inout [UInt8]) { + switch value { + + + case .engineReady: + writeInt(&buf, Int32(1)) + + + case .syncStarted: + writeInt(&buf, Int32(2)) + + + case let .syncProgress(walletHeight,networkHeight,percent): + writeInt(&buf, Int32(3)) + FfiConverterUInt32.write(walletHeight, into: &buf) + FfiConverterUInt32.write(networkHeight, into: &buf) + FfiConverterFloat.write(percent, into: &buf) + + + case .syncPaused: + writeInt(&buf, Int32(4)) + + + case .syncFinished: + writeInt(&buf, Int32(5)) + + + case let .balanceChanged(v1): + writeInt(&buf, Int32(6)) + FfiConverterTypeBalanceSnapshot.write(v1, into: &buf) + + + case let .newTransaction(txid): + writeInt(&buf, Int32(7)) + FfiConverterString.write(txid, into: &buf) + + + case let .error(code,message): + writeInt(&buf, Int32(8)) + FfiConverterString.write(code, into: &buf) + FfiConverterString.write(message, into: &buf) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeWalletEvent_lift(_ buf: RustBuffer) throws -> WalletEvent { + return try FfiConverterTypeWalletEvent.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeWalletEvent_lower(_ value: WalletEvent) -> RustBuffer { + return FfiConverterTypeWalletEvent.lower(value) +} + + + + + +public protocol WalletListener: AnyObject, Sendable { + + func onEvent(event: WalletEvent) + +} + + +// Put the implementation in a struct so we don't pollute the top-level namespace +fileprivate struct UniffiCallbackInterfaceWalletListener { + + // Create the VTable using a series of closures. + // Swift automatically converts these into C callback functions. + // + // This creates 1-element array, since this seems to be the only way to construct a const + // pointer that we can pass to the Rust code. + static let vtable: [UniffiVTableCallbackInterfaceWalletListener] = [UniffiVTableCallbackInterfaceWalletListener( + uniffiFree: { (uniffiHandle: UInt64) -> () in + do { + try FfiConverterCallbackInterfaceWalletListener.handleMap.remove(handle: uniffiHandle) + } catch { + print("Uniffi callback interface WalletListener: handle missing in uniffiFree") + } + }, + uniffiClone: { (uniffiHandle: UInt64) -> UInt64 in + do { + return try FfiConverterCallbackInterfaceWalletListener.handleMap.clone(handle: uniffiHandle) + } catch { + fatalError("Uniffi callback interface WalletListener: handle missing in uniffiClone") + } + }, + onEvent: { ( + uniffiHandle: UInt64, + event: RustBuffer, + uniffiOutReturn: UnsafeMutableRawPointer, + uniffiCallStatus: UnsafeMutablePointer + ) in + let makeCall = { + () throws -> () in + guard let uniffiObj = try? FfiConverterCallbackInterfaceWalletListener.handleMap.get(handle: uniffiHandle) else { + throw UniffiInternalError.unexpectedStaleHandle + } + return uniffiObj.onEvent( + event: try FfiConverterTypeWalletEvent_lift(event) + ) + } + + + let writeReturn = { () } + uniffiTraitInterfaceCall( + callStatus: uniffiCallStatus, + makeCall: makeCall, + writeReturn: writeReturn + ) + } + )] +} + +private func uniffiCallbackInitWalletListener() { + uniffi_ffi_fn_init_callback_vtable_walletlistener(UniffiCallbackInterfaceWalletListener.vtable) +} + +// FfiConverter protocol for callback interfaces +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterCallbackInterfaceWalletListener { + fileprivate static let handleMap = UniffiHandleMap() +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +extension FfiConverterCallbackInterfaceWalletListener : FfiConverter { + typealias SwiftType = WalletListener + typealias FfiType = UInt64 + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func lift(_ handle: UInt64) throws -> SwiftType { + try handleMap.get(handle: handle) + } + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + let handle: UInt64 = try readInt(&buf) + return try lift(handle) + } + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func lower(_ v: SwiftType) -> UInt64 { + return handleMap.insert(obj: v) + } + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func write(_ v: SwiftType, into buf: inout [UInt8]) { + writeInt(&buf, lower(v)) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterCallbackInterfaceWalletListener_lift(_ handle: UInt64) throws -> WalletListener { + return try FfiConverterCallbackInterfaceWalletListener.lift(handle) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterCallbackInterfaceWalletListener_lower(_ v: WalletListener) -> UInt64 { + return FfiConverterCallbackInterfaceWalletListener.lower(v) +} + +private enum InitializationResult { + case ok + case contractVersionMismatch + case apiChecksumMismatch +} +// Use a global variable to perform the versioning checks. Swift ensures that +// the code inside is only computed once. +private let initializationResult: InitializationResult = { + // Get the bindings contract version from our ComponentInterface + let bindings_contract_version = 30 + // Get the scaffolding contract version by calling the into the dylib + let scaffolding_contract_version = ffi_ffi_uniffi_contract_version() + if bindings_contract_version != scaffolding_contract_version { + return InitializationResult.contractVersionMismatch + } + if (uniffi_ffi_checksum_method_walletengine_clear_listener() != 65358) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_ffi_checksum_method_walletengine_get_balance_snapshot() != 57923) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_ffi_checksum_method_walletengine_pause_sync() != 29290) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_ffi_checksum_method_walletengine_set_listener() != 8699) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_ffi_checksum_method_walletengine_shutdown() != 23734) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_ffi_checksum_method_walletengine_start_sync() != 42941) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_ffi_checksum_constructor_walletengine_new() != 45836) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_ffi_checksum_method_walletlistener_on_event() != 26795) { + return InitializationResult.apiChecksumMismatch + } + + uniffiCallbackInitWalletListener() + return InitializationResult.ok +}() + +// Make the ensure init function public so that other modules which have external type references to +// our types can call it. +public func uniffiEnsureFfiInitialized() { + switch initializationResult { + case .ok: + break + case .contractVersionMismatch: + fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") + case .apiChecksumMismatch: + fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } +} + +// swiftlint:enable all \ No newline at end of file diff --git a/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.h b/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.h new file mode 100644 index 000000000..59db60430 --- /dev/null +++ b/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.h @@ -0,0 +1,627 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! + +#pragma once + +#include +#include +#include + +// The following structs are used to implement the lowest level +// of the FFI, and thus useful to multiple uniffied crates. +// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H. +#ifdef UNIFFI_SHARED_H + // We also try to prevent mixing versions of shared uniffi header structs. + // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4 + #ifndef UNIFFI_SHARED_HEADER_V4 + #error Combining helper code from multiple versions of uniffi is not supported + #endif // ndef UNIFFI_SHARED_HEADER_V4 +#else +#define UNIFFI_SHARED_H +#define UNIFFI_SHARED_HEADER_V4 +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ + +typedef struct RustBuffer +{ + uint64_t capacity; + uint64_t len; + uint8_t *_Nullable data; +} RustBuffer; + +typedef struct ForeignBytes +{ + int32_t len; + const uint8_t *_Nullable data; +} ForeignBytes; + +// Error definitions +typedef struct RustCallStatus { + int8_t code; + RustBuffer errorBuf; +} RustCallStatus; + +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ +#endif // def UNIFFI_SHARED_H +#ifndef UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK +#define UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK +typedef void (*UniffiRustFutureContinuationCallback)(uint64_t, int8_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK +typedef void (*UniffiForeignFutureDroppedCallback)(uint64_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE +#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE +typedef void (*UniffiCallbackInterfaceFree)(uint64_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE +#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE +typedef uint64_t (*UniffiCallbackInterfaceClone)(uint64_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT +typedef struct UniffiForeignFutureDroppedCallbackStruct { + uint64_t handle; + UniffiForeignFutureDroppedCallback _Nonnull free; +} UniffiForeignFutureDroppedCallbackStruct; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8 +typedef struct UniffiForeignFutureResultU8 { + uint8_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU8; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8 +typedef void (*UniffiForeignFutureCompleteU8)(uint64_t, UniffiForeignFutureResultU8 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8 +typedef struct UniffiForeignFutureResultI8 { + int8_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI8; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8 +typedef void (*UniffiForeignFutureCompleteI8)(uint64_t, UniffiForeignFutureResultI8 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16 +typedef struct UniffiForeignFutureResultU16 { + uint16_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU16; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16 +typedef void (*UniffiForeignFutureCompleteU16)(uint64_t, UniffiForeignFutureResultU16 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16 +typedef struct UniffiForeignFutureResultI16 { + int16_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI16; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16 +typedef void (*UniffiForeignFutureCompleteI16)(uint64_t, UniffiForeignFutureResultI16 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32 +typedef struct UniffiForeignFutureResultU32 { + uint32_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU32; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32 +typedef void (*UniffiForeignFutureCompleteU32)(uint64_t, UniffiForeignFutureResultU32 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32 +typedef struct UniffiForeignFutureResultI32 { + int32_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI32; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32 +typedef void (*UniffiForeignFutureCompleteI32)(uint64_t, UniffiForeignFutureResultI32 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64 +typedef struct UniffiForeignFutureResultU64 { + uint64_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU64; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64 +typedef void (*UniffiForeignFutureCompleteU64)(uint64_t, UniffiForeignFutureResultU64 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64 +typedef struct UniffiForeignFutureResultI64 { + int64_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI64; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64 +typedef void (*UniffiForeignFutureCompleteI64)(uint64_t, UniffiForeignFutureResultI64 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32 +typedef struct UniffiForeignFutureResultF32 { + float returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultF32; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32 +typedef void (*UniffiForeignFutureCompleteF32)(uint64_t, UniffiForeignFutureResultF32 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64 +typedef struct UniffiForeignFutureResultF64 { + double returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultF64; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64 +typedef void (*UniffiForeignFutureCompleteF64)(uint64_t, UniffiForeignFutureResultF64 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER +typedef struct UniffiForeignFutureResultRustBuffer { + RustBuffer returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultRustBuffer; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER +typedef void (*UniffiForeignFutureCompleteRustBuffer)(uint64_t, UniffiForeignFutureResultRustBuffer + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID +typedef struct UniffiForeignFutureResultVoid { + RustCallStatus callStatus; +} UniffiForeignFutureResultVoid; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID +typedef void (*UniffiForeignFutureCompleteVoid)(uint64_t, UniffiForeignFutureResultVoid + ); + +#endif +#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_WALLET_LISTENER_METHOD0 +#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_WALLET_LISTENER_METHOD0 +typedef void (*UniffiCallbackInterfaceWalletListenerMethod0)(uint64_t, RustBuffer, void* _Nonnull, + RustCallStatus *_Nonnull uniffiCallStatus + ); + +#endif +#ifndef UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_WALLET_LISTENER +#define UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_WALLET_LISTENER +typedef struct UniffiVTableCallbackInterfaceWalletListener { + UniffiCallbackInterfaceFree _Nonnull uniffiFree; + UniffiCallbackInterfaceClone _Nonnull uniffiClone; + UniffiCallbackInterfaceWalletListenerMethod0 _Nonnull onEvent; +} UniffiVTableCallbackInterfaceWalletListener; + +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_CLONE_WALLETENGINE +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_CLONE_WALLETENGINE +uint64_t uniffi_ffi_fn_clone_walletengine(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_FREE_WALLETENGINE +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_FREE_WALLETENGINE +void uniffi_ffi_fn_free_walletengine(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_CONSTRUCTOR_WALLETENGINE_NEW +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_CONSTRUCTOR_WALLETENGINE_NEW +uint64_t uniffi_ffi_fn_constructor_walletengine_new(RustCallStatus *_Nonnull out_status + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_CLEAR_LISTENER +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_CLEAR_LISTENER +void uniffi_ffi_fn_method_walletengine_clear_listener(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT +RustBuffer uniffi_ffi_fn_method_walletengine_get_balance_snapshot(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_PAUSE_SYNC +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_PAUSE_SYNC +void uniffi_ffi_fn_method_walletengine_pause_sync(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SET_LISTENER +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SET_LISTENER +void uniffi_ffi_fn_method_walletengine_set_listener(uint64_t ptr, uint64_t listener, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SHUTDOWN +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SHUTDOWN +void uniffi_ffi_fn_method_walletengine_shutdown(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_START_SYNC +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_START_SYNC +void uniffi_ffi_fn_method_walletengine_start_sync(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_INIT_CALLBACK_VTABLE_WALLETLISTENER +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_INIT_CALLBACK_VTABLE_WALLETLISTENER +void uniffi_ffi_fn_init_callback_vtable_walletlistener(const UniffiVTableCallbackInterfaceWalletListener* _Nonnull vtable +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_ALLOC +#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_ALLOC +RustBuffer ffi_ffi_rustbuffer_alloc(uint64_t size, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FROM_BYTES +#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FROM_BYTES +RustBuffer ffi_ffi_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FREE +#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FREE +void ffi_ffi_rustbuffer_free(RustBuffer buf, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_RESERVE +#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_RESERVE +RustBuffer ffi_ffi_rustbuffer_reserve(RustBuffer buf, uint64_t additional, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U8 +void ffi_ffi_rust_future_poll_u8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U8 +void ffi_ffi_rust_future_cancel_u8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U8 +void ffi_ffi_rust_future_free_u8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U8 +uint8_t ffi_ffi_rust_future_complete_u8(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I8 +void ffi_ffi_rust_future_poll_i8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I8 +void ffi_ffi_rust_future_cancel_i8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I8 +void ffi_ffi_rust_future_free_i8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I8 +int8_t ffi_ffi_rust_future_complete_i8(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U16 +void ffi_ffi_rust_future_poll_u16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U16 +void ffi_ffi_rust_future_cancel_u16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U16 +void ffi_ffi_rust_future_free_u16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U16 +uint16_t ffi_ffi_rust_future_complete_u16(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I16 +void ffi_ffi_rust_future_poll_i16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I16 +void ffi_ffi_rust_future_cancel_i16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I16 +void ffi_ffi_rust_future_free_i16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I16 +int16_t ffi_ffi_rust_future_complete_i16(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U32 +void ffi_ffi_rust_future_poll_u32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U32 +void ffi_ffi_rust_future_cancel_u32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U32 +void ffi_ffi_rust_future_free_u32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U32 +uint32_t ffi_ffi_rust_future_complete_u32(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I32 +void ffi_ffi_rust_future_poll_i32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I32 +void ffi_ffi_rust_future_cancel_i32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I32 +void ffi_ffi_rust_future_free_i32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I32 +int32_t ffi_ffi_rust_future_complete_i32(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U64 +void ffi_ffi_rust_future_poll_u64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U64 +void ffi_ffi_rust_future_cancel_u64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U64 +void ffi_ffi_rust_future_free_u64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U64 +uint64_t ffi_ffi_rust_future_complete_u64(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I64 +void ffi_ffi_rust_future_poll_i64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I64 +void ffi_ffi_rust_future_cancel_i64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I64 +void ffi_ffi_rust_future_free_i64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I64 +int64_t ffi_ffi_rust_future_complete_i64(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F32 +void ffi_ffi_rust_future_poll_f32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F32 +void ffi_ffi_rust_future_cancel_f32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F32 +void ffi_ffi_rust_future_free_f32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F32 +float ffi_ffi_rust_future_complete_f32(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F64 +void ffi_ffi_rust_future_poll_f64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F64 +void ffi_ffi_rust_future_cancel_f64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F64 +void ffi_ffi_rust_future_free_f64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F64 +double ffi_ffi_rust_future_complete_f64(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_RUST_BUFFER +void ffi_ffi_rust_future_poll_rust_buffer(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_RUST_BUFFER +void ffi_ffi_rust_future_cancel_rust_buffer(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_RUST_BUFFER +void ffi_ffi_rust_future_free_rust_buffer(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_RUST_BUFFER +RustBuffer ffi_ffi_rust_future_complete_rust_buffer(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_VOID +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_VOID +void ffi_ffi_rust_future_poll_void(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_VOID +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_VOID +void ffi_ffi_rust_future_cancel_void(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_VOID +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_VOID +void ffi_ffi_rust_future_free_void(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_VOID +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_VOID +void ffi_ffi_rust_future_complete_void(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_CLEAR_LISTENER +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_CLEAR_LISTENER +uint16_t uniffi_ffi_checksum_method_walletengine_clear_listener(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT +uint16_t uniffi_ffi_checksum_method_walletengine_get_balance_snapshot(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_PAUSE_SYNC +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_PAUSE_SYNC +uint16_t uniffi_ffi_checksum_method_walletengine_pause_sync(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SET_LISTENER +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SET_LISTENER +uint16_t uniffi_ffi_checksum_method_walletengine_set_listener(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SHUTDOWN +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SHUTDOWN +uint16_t uniffi_ffi_checksum_method_walletengine_shutdown(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_START_SYNC +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_START_SYNC +uint16_t uniffi_ffi_checksum_method_walletengine_start_sync(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_CONSTRUCTOR_WALLETENGINE_NEW +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_CONSTRUCTOR_WALLETENGINE_NEW +uint16_t uniffi_ffi_checksum_constructor_walletengine_new(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETLISTENER_ON_EVENT +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETLISTENER_ON_EVENT +uint16_t uniffi_ffi_checksum_method_walletlistener_on_event(void + +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_UNIFFI_CONTRACT_VERSION +#define UNIFFI_FFIDEF_FFI_FFI_UNIFFI_CONTRACT_VERSION +uint32_t ffi_ffi_uniffi_contract_version(void + +); +#endif + diff --git a/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.modulemap b/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.modulemap new file mode 100644 index 000000000..5507d8a8e --- /dev/null +++ b/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.modulemap @@ -0,0 +1,7 @@ +module ffiFFI { + header "ffiFFI.h" + export * + use "Darwin" + use "_Builtin_stdbool" + use "_Builtin_stdint" +} \ No newline at end of file diff --git a/ffi/ios/WalletSDK/Sources/WalletSDK/WalletSDK.swift b/ffi/ios/WalletSDK/Sources/WalletSDK/WalletSDK.swift new file mode 100644 index 000000000..226747a63 --- /dev/null +++ b/ffi/ios/WalletSDK/Sources/WalletSDK/WalletSDK.swift @@ -0,0 +1,80 @@ +import Foundation + +public enum WalletSDKError: Error { + case underlying(String) +} + +public struct Balance { + public let confirmed: String + public let total: String +} + +public enum WalletEventPublic { + case engineReady + case syncStarted + case syncProgress(walletHeight: Int, networkHeight: Int, percent: Double) + case syncPaused + case syncFinished + case balanceChanged(Balance) + case newTransaction(txid: String) + case error(code: String, message: String) +} + +public final class Wallet: WalletListener { + private let engine: WalletEngine + private var handler: ((WalletEventPublic) -> Void)? + + public init(onEvent: ((WalletEventPublic) -> Void)? = nil) throws { + self.engine = try WalletEngine() + self.handler = onEvent + try self.engine.setListener(listener: self) + } + + public func setEventHandler(_ h: ((WalletEventPublic) -> Void)?) { + self.handler = h + } + + // UniFFI callback + public func onEvent(event: WalletEvent) { + handler?(mapEvent(event)) + } + + public func startSync() throws { + try engine.startSync() + } + + public func pauseSync() throws { + try engine.pauseSync() + } + + public func shutdown() throws { + try engine.clearListener() + try engine.shutdown() + } + + public func balance() throws -> Balance { + let snap = try engine.getBalanceSnapshot() + return Balance(confirmed: snap.confirmed, total: snap.total) + } + + private func mapEvent(_ e: WalletEvent) -> WalletEventPublic { + switch e { + case .engineReady: + return .engineReady + case .syncStarted: + return .syncStarted + case .syncProgress(walletHeight: let h, networkHeight: let nh, percent: let p): + return .syncProgress(walletHeight: Int(h), networkHeight: Int(nh), percent: Double(p)) + case .syncPaused: + return .syncPaused + case .syncFinished: + return .syncFinished + case .balanceChanged(snap: let s): + return .balanceChanged(Balance(confirmed: s.confirmed, total: s.total)) + case .newTransaction(txid: let t): + return .newTransaction(txid: t) + case .error(code: let c, message: let m): + return .error(code: c, message: m) + } + } +} diff --git a/ffi/ios/WalletSDK/Sources/WalletSDKSmoke/main.swift b/ffi/ios/WalletSDK/Sources/WalletSDKSmoke/main.swift new file mode 100644 index 000000000..a197185f3 --- /dev/null +++ b/ffi/ios/WalletSDK/Sources/WalletSDKSmoke/main.swift @@ -0,0 +1,22 @@ +import Foundation +import WalletSDK + +final class Printer { + static func run() throws { + let wallet = try WalletSDK.Wallet(onEvent: { e in + print("EVENT:", e) + }) + + let bal = try wallet.balance() + print("BALANCE:", bal) + + try wallet.startSync() + + RunLoop.current.run(until: Date().addingTimeInterval(2.0)) + + try wallet.pauseSync() + try wallet.shutdown() + } +} + +do { try Printer.run() } catch { print("ERROR:", error) } diff --git a/ffi/ios/WalletSDK/Sources/ffiFFI/include/ffiFFI.h b/ffi/ios/WalletSDK/Sources/ffiFFI/include/ffiFFI.h new file mode 100644 index 000000000..59db60430 --- /dev/null +++ b/ffi/ios/WalletSDK/Sources/ffiFFI/include/ffiFFI.h @@ -0,0 +1,627 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! + +#pragma once + +#include +#include +#include + +// The following structs are used to implement the lowest level +// of the FFI, and thus useful to multiple uniffied crates. +// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H. +#ifdef UNIFFI_SHARED_H + // We also try to prevent mixing versions of shared uniffi header structs. + // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4 + #ifndef UNIFFI_SHARED_HEADER_V4 + #error Combining helper code from multiple versions of uniffi is not supported + #endif // ndef UNIFFI_SHARED_HEADER_V4 +#else +#define UNIFFI_SHARED_H +#define UNIFFI_SHARED_HEADER_V4 +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ + +typedef struct RustBuffer +{ + uint64_t capacity; + uint64_t len; + uint8_t *_Nullable data; +} RustBuffer; + +typedef struct ForeignBytes +{ + int32_t len; + const uint8_t *_Nullable data; +} ForeignBytes; + +// Error definitions +typedef struct RustCallStatus { + int8_t code; + RustBuffer errorBuf; +} RustCallStatus; + +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ +#endif // def UNIFFI_SHARED_H +#ifndef UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK +#define UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK +typedef void (*UniffiRustFutureContinuationCallback)(uint64_t, int8_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK +typedef void (*UniffiForeignFutureDroppedCallback)(uint64_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE +#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE +typedef void (*UniffiCallbackInterfaceFree)(uint64_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE +#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE +typedef uint64_t (*UniffiCallbackInterfaceClone)(uint64_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT +typedef struct UniffiForeignFutureDroppedCallbackStruct { + uint64_t handle; + UniffiForeignFutureDroppedCallback _Nonnull free; +} UniffiForeignFutureDroppedCallbackStruct; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8 +typedef struct UniffiForeignFutureResultU8 { + uint8_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU8; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8 +typedef void (*UniffiForeignFutureCompleteU8)(uint64_t, UniffiForeignFutureResultU8 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8 +typedef struct UniffiForeignFutureResultI8 { + int8_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI8; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8 +typedef void (*UniffiForeignFutureCompleteI8)(uint64_t, UniffiForeignFutureResultI8 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16 +typedef struct UniffiForeignFutureResultU16 { + uint16_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU16; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16 +typedef void (*UniffiForeignFutureCompleteU16)(uint64_t, UniffiForeignFutureResultU16 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16 +typedef struct UniffiForeignFutureResultI16 { + int16_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI16; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16 +typedef void (*UniffiForeignFutureCompleteI16)(uint64_t, UniffiForeignFutureResultI16 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32 +typedef struct UniffiForeignFutureResultU32 { + uint32_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU32; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32 +typedef void (*UniffiForeignFutureCompleteU32)(uint64_t, UniffiForeignFutureResultU32 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32 +typedef struct UniffiForeignFutureResultI32 { + int32_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI32; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32 +typedef void (*UniffiForeignFutureCompleteI32)(uint64_t, UniffiForeignFutureResultI32 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64 +typedef struct UniffiForeignFutureResultU64 { + uint64_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU64; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64 +typedef void (*UniffiForeignFutureCompleteU64)(uint64_t, UniffiForeignFutureResultU64 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64 +typedef struct UniffiForeignFutureResultI64 { + int64_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI64; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64 +typedef void (*UniffiForeignFutureCompleteI64)(uint64_t, UniffiForeignFutureResultI64 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32 +typedef struct UniffiForeignFutureResultF32 { + float returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultF32; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32 +typedef void (*UniffiForeignFutureCompleteF32)(uint64_t, UniffiForeignFutureResultF32 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64 +typedef struct UniffiForeignFutureResultF64 { + double returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultF64; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64 +typedef void (*UniffiForeignFutureCompleteF64)(uint64_t, UniffiForeignFutureResultF64 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER +typedef struct UniffiForeignFutureResultRustBuffer { + RustBuffer returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultRustBuffer; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER +typedef void (*UniffiForeignFutureCompleteRustBuffer)(uint64_t, UniffiForeignFutureResultRustBuffer + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID +typedef struct UniffiForeignFutureResultVoid { + RustCallStatus callStatus; +} UniffiForeignFutureResultVoid; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID +typedef void (*UniffiForeignFutureCompleteVoid)(uint64_t, UniffiForeignFutureResultVoid + ); + +#endif +#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_WALLET_LISTENER_METHOD0 +#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_WALLET_LISTENER_METHOD0 +typedef void (*UniffiCallbackInterfaceWalletListenerMethod0)(uint64_t, RustBuffer, void* _Nonnull, + RustCallStatus *_Nonnull uniffiCallStatus + ); + +#endif +#ifndef UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_WALLET_LISTENER +#define UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_WALLET_LISTENER +typedef struct UniffiVTableCallbackInterfaceWalletListener { + UniffiCallbackInterfaceFree _Nonnull uniffiFree; + UniffiCallbackInterfaceClone _Nonnull uniffiClone; + UniffiCallbackInterfaceWalletListenerMethod0 _Nonnull onEvent; +} UniffiVTableCallbackInterfaceWalletListener; + +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_CLONE_WALLETENGINE +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_CLONE_WALLETENGINE +uint64_t uniffi_ffi_fn_clone_walletengine(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_FREE_WALLETENGINE +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_FREE_WALLETENGINE +void uniffi_ffi_fn_free_walletengine(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_CONSTRUCTOR_WALLETENGINE_NEW +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_CONSTRUCTOR_WALLETENGINE_NEW +uint64_t uniffi_ffi_fn_constructor_walletengine_new(RustCallStatus *_Nonnull out_status + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_CLEAR_LISTENER +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_CLEAR_LISTENER +void uniffi_ffi_fn_method_walletengine_clear_listener(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT +RustBuffer uniffi_ffi_fn_method_walletengine_get_balance_snapshot(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_PAUSE_SYNC +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_PAUSE_SYNC +void uniffi_ffi_fn_method_walletengine_pause_sync(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SET_LISTENER +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SET_LISTENER +void uniffi_ffi_fn_method_walletengine_set_listener(uint64_t ptr, uint64_t listener, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SHUTDOWN +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SHUTDOWN +void uniffi_ffi_fn_method_walletengine_shutdown(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_START_SYNC +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_START_SYNC +void uniffi_ffi_fn_method_walletengine_start_sync(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_INIT_CALLBACK_VTABLE_WALLETLISTENER +#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_INIT_CALLBACK_VTABLE_WALLETLISTENER +void uniffi_ffi_fn_init_callback_vtable_walletlistener(const UniffiVTableCallbackInterfaceWalletListener* _Nonnull vtable +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_ALLOC +#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_ALLOC +RustBuffer ffi_ffi_rustbuffer_alloc(uint64_t size, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FROM_BYTES +#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FROM_BYTES +RustBuffer ffi_ffi_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FREE +#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FREE +void ffi_ffi_rustbuffer_free(RustBuffer buf, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_RESERVE +#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_RESERVE +RustBuffer ffi_ffi_rustbuffer_reserve(RustBuffer buf, uint64_t additional, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U8 +void ffi_ffi_rust_future_poll_u8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U8 +void ffi_ffi_rust_future_cancel_u8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U8 +void ffi_ffi_rust_future_free_u8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U8 +uint8_t ffi_ffi_rust_future_complete_u8(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I8 +void ffi_ffi_rust_future_poll_i8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I8 +void ffi_ffi_rust_future_cancel_i8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I8 +void ffi_ffi_rust_future_free_i8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I8 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I8 +int8_t ffi_ffi_rust_future_complete_i8(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U16 +void ffi_ffi_rust_future_poll_u16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U16 +void ffi_ffi_rust_future_cancel_u16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U16 +void ffi_ffi_rust_future_free_u16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U16 +uint16_t ffi_ffi_rust_future_complete_u16(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I16 +void ffi_ffi_rust_future_poll_i16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I16 +void ffi_ffi_rust_future_cancel_i16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I16 +void ffi_ffi_rust_future_free_i16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I16 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I16 +int16_t ffi_ffi_rust_future_complete_i16(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U32 +void ffi_ffi_rust_future_poll_u32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U32 +void ffi_ffi_rust_future_cancel_u32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U32 +void ffi_ffi_rust_future_free_u32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U32 +uint32_t ffi_ffi_rust_future_complete_u32(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I32 +void ffi_ffi_rust_future_poll_i32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I32 +void ffi_ffi_rust_future_cancel_i32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I32 +void ffi_ffi_rust_future_free_i32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I32 +int32_t ffi_ffi_rust_future_complete_i32(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U64 +void ffi_ffi_rust_future_poll_u64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U64 +void ffi_ffi_rust_future_cancel_u64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U64 +void ffi_ffi_rust_future_free_u64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U64 +uint64_t ffi_ffi_rust_future_complete_u64(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I64 +void ffi_ffi_rust_future_poll_i64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I64 +void ffi_ffi_rust_future_cancel_i64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I64 +void ffi_ffi_rust_future_free_i64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I64 +int64_t ffi_ffi_rust_future_complete_i64(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F32 +void ffi_ffi_rust_future_poll_f32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F32 +void ffi_ffi_rust_future_cancel_f32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F32 +void ffi_ffi_rust_future_free_f32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F32 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F32 +float ffi_ffi_rust_future_complete_f32(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F64 +void ffi_ffi_rust_future_poll_f64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F64 +void ffi_ffi_rust_future_cancel_f64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F64 +void ffi_ffi_rust_future_free_f64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F64 +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F64 +double ffi_ffi_rust_future_complete_f64(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_RUST_BUFFER +void ffi_ffi_rust_future_poll_rust_buffer(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_RUST_BUFFER +void ffi_ffi_rust_future_cancel_rust_buffer(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_RUST_BUFFER +void ffi_ffi_rust_future_free_rust_buffer(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_RUST_BUFFER +RustBuffer ffi_ffi_rust_future_complete_rust_buffer(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_VOID +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_VOID +void ffi_ffi_rust_future_poll_void(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_VOID +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_VOID +void ffi_ffi_rust_future_cancel_void(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_VOID +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_VOID +void ffi_ffi_rust_future_free_void(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_VOID +#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_VOID +void ffi_ffi_rust_future_complete_void(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_CLEAR_LISTENER +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_CLEAR_LISTENER +uint16_t uniffi_ffi_checksum_method_walletengine_clear_listener(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT +uint16_t uniffi_ffi_checksum_method_walletengine_get_balance_snapshot(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_PAUSE_SYNC +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_PAUSE_SYNC +uint16_t uniffi_ffi_checksum_method_walletengine_pause_sync(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SET_LISTENER +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SET_LISTENER +uint16_t uniffi_ffi_checksum_method_walletengine_set_listener(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SHUTDOWN +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SHUTDOWN +uint16_t uniffi_ffi_checksum_method_walletengine_shutdown(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_START_SYNC +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_START_SYNC +uint16_t uniffi_ffi_checksum_method_walletengine_start_sync(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_CONSTRUCTOR_WALLETENGINE_NEW +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_CONSTRUCTOR_WALLETENGINE_NEW +uint16_t uniffi_ffi_checksum_constructor_walletengine_new(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETLISTENER_ON_EVENT +#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETLISTENER_ON_EVENT +uint16_t uniffi_ffi_checksum_method_walletlistener_on_event(void + +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_FFI_UNIFFI_CONTRACT_VERSION +#define UNIFFI_FFIDEF_FFI_FFI_UNIFFI_CONTRACT_VERSION +uint32_t ffi_ffi_uniffi_contract_version(void + +); +#endif + diff --git a/ffi/ios/WalletSDK/Sources/ffiFFI/module.modulemap b/ffi/ios/WalletSDK/Sources/ffiFFI/module.modulemap new file mode 100644 index 000000000..8a7b6b4cc --- /dev/null +++ b/ffi/ios/WalletSDK/Sources/ffiFFI/module.modulemap @@ -0,0 +1,7 @@ +module ffiFFI { + header "include/ffiFFI.h" + export * + use "Darwin" + use "_Builtin_stdbool" + use "_Builtin_stdint" +} diff --git a/ffi/ios/WalletSDK/Tests/WalletSDKTests/WalletSDKTests.swift b/ffi/ios/WalletSDK/Tests/WalletSDKTests/WalletSDKTests.swift new file mode 100644 index 000000000..a62a822d5 --- /dev/null +++ b/ffi/ios/WalletSDK/Tests/WalletSDKTests/WalletSDKTests.swift @@ -0,0 +1,19 @@ +import XCTest + +@testable import WalletSDK + +final class WalletSDKTests: XCTestCase { + func testCreateWalletAndGetBalance() throws { + let wallet = try Wallet(onEvent: { event in + print("EVENT:", event) + }) + + let bal = try wallet.balance() + print("BAL:", bal) + + try wallet.startSync() + RunLoop.current.run(until: Date().addingTimeInterval(1.0)) + try wallet.pauseSync() + try wallet.shutdown() + } +} diff --git a/ffi/rust/Cargo.toml b/ffi/rust/Cargo.toml new file mode 100644 index 000000000..1a072181d --- /dev/null +++ b/ffi/rust/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "ffi" +version = "0.0.0" +edition = "2024" + +[dependencies] +thiserror.workspace = true +tokio = { workspace = true, features = ["rt-multi-thread", "time", "sync"] } +uniffi = { version = "0.31", features = ["cli"] } + +[build-dependencies] +uniffi = { version = "0.31", features = ["build"] } + + +[lib] +crate-type = ["cdylib"] +name = "ffi" + +[[bin]] +name = "generate-bindings" +path = "generate-bindings.rs" diff --git a/ffi/rust/generate-bindings.rs b/ffi/rust/generate-bindings.rs new file mode 100644 index 000000000..f6cff6cf1 --- /dev/null +++ b/ffi/rust/generate-bindings.rs @@ -0,0 +1,3 @@ +fn main() { + uniffi::uniffi_bindgen_main() +} diff --git a/ffi/rust/src/lib.rs b/ffi/rust/src/lib.rs new file mode 100644 index 000000000..96626f6e6 --- /dev/null +++ b/ffi/rust/src/lib.rs @@ -0,0 +1,190 @@ +use std::{ + panic::{self, AssertUnwindSafe}, + sync::{Arc, Mutex}, + time::Duration, +}; + +use tokio::sync::mpsc; + +uniffi::setup_scaffolding!(); + +#[derive(Debug, thiserror::Error, uniffi::Error)] +pub enum WalletError { + #[error("Command queue closed")] + CommandQueueClosed, + #[error("Listener lock poisoned")] + ListenerLockPoisoned, + #[error("Internal error: {0}")] + Internal(String), +} + +#[derive(Clone, Debug, uniffi::Record)] +pub struct BalanceSnapshot { + pub confirmed: String, + pub total: String, +} + +#[derive(Clone, Debug, uniffi::Enum)] +pub enum WalletEvent { + EngineReady, + SyncStarted, + SyncProgress { + wallet_height: u32, + network_height: u32, + percent: f32, + }, + SyncPaused, + SyncFinished, + BalanceChanged(BalanceSnapshot), + NewTransaction { + txid: String, + }, + Error { + code: String, + message: String, + }, +} + +#[uniffi::export(callback_interface)] +pub trait WalletListener: Send + Sync { + fn on_event(&self, event: WalletEvent); +} + +enum Command { + StartSync, + PauseSync, + Shutdown, +} + +struct EngineInner { + cmd_tx: mpsc::Sender, + listener: Mutex>>, +} + +#[derive(uniffi::Object)] +pub struct WalletEngine { + inner: Arc, +} + +#[uniffi::export] +impl WalletEngine { + #[uniffi::constructor] + pub fn new() -> Result { + let (cmd_tx, mut cmd_rx) = mpsc::channel::(64); + + let inner = Arc::new(EngineInner { + cmd_tx, + listener: Mutex::new(None), + }); + + let inner_for_task = inner.clone(); + + std::thread::spawn(move || { + let rt = tokio::runtime::Runtime::new().expect("tokio runtime"); + rt.block_on(async move { + emit(&inner_for_task, WalletEvent::EngineReady); + + let mut syncing = false; + + while let Some(cmd) = cmd_rx.recv().await { + match cmd { + Command::StartSync => { + if syncing { + continue; + } + syncing = true; + emit(&inner_for_task, WalletEvent::SyncStarted); + + for i in 0..=100u32 { + tokio::time::sleep(Duration::from_millis(50)).await; + + emit( + &inner_for_task, + WalletEvent::SyncProgress { + wallet_height: 1000 + i, + network_height: 1100, + percent: i as f32 / 100.0, + }, + ); + + if !syncing { + break; + } + } + + emit(&inner_for_task, WalletEvent::SyncFinished); + syncing = false; + } + Command::PauseSync => { + syncing = false; + emit(&inner_for_task, WalletEvent::SyncPaused); + } + Command::Shutdown => break, + } + } + }); + }); + + Ok(Self { inner }) + } + + // Box for UniFFI + pub fn set_listener(&self, listener: Box) -> Result<(), WalletError> { + let mut guard = self + .inner + .listener + .lock() + .map_err(|_| WalletError::ListenerLockPoisoned)?; + + *guard = Some(Arc::from(listener)); + Ok(()) + } + + pub fn clear_listener(&self) -> Result<(), WalletError> { + let mut guard = self + .inner + .listener + .lock() + .map_err(|_| WalletError::ListenerLockPoisoned)?; + *guard = None; + Ok(()) + } + + pub fn start_sync(&self) -> Result<(), WalletError> { + self.inner + .cmd_tx + .try_send(Command::StartSync) + .map_err(|_| WalletError::CommandQueueClosed) + } + + pub fn pause_sync(&self) -> Result<(), WalletError> { + self.inner + .cmd_tx + .try_send(Command::PauseSync) + .map_err(|_| WalletError::CommandQueueClosed) + } + + pub fn shutdown(&self) -> Result<(), WalletError> { + self.inner + .cmd_tx + .try_send(Command::Shutdown) + .map_err(|_| WalletError::CommandQueueClosed) + } + + pub fn get_balance_snapshot(&self) -> Result { + Ok(BalanceSnapshot { + confirmed: "0".to_string(), + total: "0".to_string(), + }) + } +} + +fn emit(inner: &EngineInner, event: WalletEvent) { + let listener_opt = inner.listener.lock().ok().and_then(|g| g.clone()); + if let Some(listener) = listener_opt { + // Avoid UnwindSafe errors. don’t let a callback panic crash the engine + let _ = panic::catch_unwind(AssertUnwindSafe(|| { + listener.on_event(event); + })); + } +} From 58112029c6a3878c7b95d8c9af5af23c7b382f34 Mon Sep 17 00:00:00 2001 From: dorianvp Date: Tue, 10 Feb 2026 18:38:54 -0300 Subject: [PATCH 02/15] chore: rust code tests --- Cargo.lock | 6 + ffi/rust/Cargo.toml | 7 + ffi/rust/src/lib.rs | 675 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 658 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 359f08c12..b0d92e081 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2137,9 +2137,15 @@ dependencies = [ name = "ffi" version = "0.0.0" dependencies = [ + "bip0039", + "http", + "pepper-sync", "thiserror 2.0.17", "tokio", "uniffi", + "zcash_primitives", + "zingo_common_components", + "zingolib", ] [[package]] diff --git a/ffi/rust/Cargo.toml b/ffi/rust/Cargo.toml index 1a072181d..8b237ea6a 100644 --- a/ffi/rust/Cargo.toml +++ b/ffi/rust/Cargo.toml @@ -4,9 +4,16 @@ version = "0.0.0" edition = "2024" [dependencies] +bip0039.workspace = true thiserror.workspace = true tokio = { workspace = true, features = ["rt-multi-thread", "time", "sync"] } uniffi = { version = "0.31", features = ["cli"] } +zcash_primitives.workspace = true + +zingolib.workspace = true +pepper-sync.workspace = true +zingo_common_components = { workspace = true, features = ["for_test"] } +http.workspace = true [build-dependencies] uniffi = { version = "0.31", features = ["build"] } diff --git a/ffi/rust/src/lib.rs b/ffi/rust/src/lib.rs index 96626f6e6..ceda9b852 100644 --- a/ffi/rust/src/lib.rs +++ b/ffi/rust/src/lib.rs @@ -1,11 +1,31 @@ use std::{ panic::{self, AssertUnwindSafe}, - sync::{Arc, Mutex}, + path::PathBuf, + str::FromStr, + sync::{Arc, Mutex, RwLock}, time::Duration, }; use tokio::sync::mpsc; +use std::num::NonZeroU32; + +use bip0039::Mnemonic; +use pepper_sync::config::{PerformanceLevel, SyncConfig, TransparentAddressDiscovery}; +use pepper_sync::wallet::SyncMode; +use zcash_primitives::consensus::BlockHeight; +use zcash_primitives::zip32::AccountId; + +use zingolib::data::PollReport; +use zingolib::lightclient::LightClient; +use zingolib::wallet::{LightWallet, WalletBase, WalletSettings}; +use zingolib::{ + config::{ChainType, ZingoConfig, construct_lightwalletd_uri}, + wallet::balance::AccountBalance, +}; + +use zingo_common_components::protocol::activation_heights::for_test; + uniffi::setup_scaffolding!(); #[derive(Debug, thiserror::Error, uniffi::Error)] @@ -14,11 +34,13 @@ pub enum WalletError { CommandQueueClosed, #[error("Listener lock poisoned")] ListenerLockPoisoned, + #[error("Wallet not initialized")] + NotInitialized, #[error("Internal error: {0}")] Internal(String), } -#[derive(Clone, Debug, uniffi::Record)] +#[derive(Clone, Debug, uniffi::Record, PartialEq, Eq)] pub struct BalanceSnapshot { pub confirmed: String, pub total: String, @@ -59,6 +81,12 @@ enum Command { struct EngineInner { cmd_tx: mpsc::Sender, listener: Mutex>>, + + // Real state + lightclient: RwLock>, + server_uri: RwLock>, + + wallet_path: RwLock>, } #[derive(uniffi::Object)] @@ -66,6 +94,87 @@ pub struct WalletEngine { inner: Arc, } +fn emit(inner: &EngineInner, event: WalletEvent) { + let listener_opt = inner.listener.lock().ok().and_then(|g| g.clone()); + if let Some(listener) = listener_opt { + let _ = panic::catch_unwind(AssertUnwindSafe(|| { + listener.on_event(event); + })); + } +} + +fn parse_chain(chain_hint: &str) -> Result { + match chain_hint { + "main" => Ok(ChainType::Mainnet), + "test" => Ok(ChainType::Testnet), + "regtest" => Ok(ChainType::Regtest(for_test::all_height_one_nus())), + other => Err(WalletError::Internal(format!( + "Invalid chain hint: {other} (expected main|test|regtest)" + ))), + } +} + +fn parse_performance(performance_level: &str) -> Result { + match performance_level { + "Maximum" => Ok(PerformanceLevel::Maximum), + "High" => Ok(PerformanceLevel::High), + "Medium" => Ok(PerformanceLevel::Medium), + "Low" => Ok(PerformanceLevel::Low), + other => Err(WalletError::Internal(format!( + "Invalid performance level: {other} (expected Maximum|High|Medium|Low)" + ))), + } +} + +fn construct_config( + server_uri: String, + chain_hint: String, + performance_level: String, + min_confirmations: u32, +) -> Result<(ZingoConfig, http::Uri), WalletError> { + let lightwalletd_uri = construct_lightwalletd_uri(Some(server_uri)); + let chaintype = parse_chain(chain_hint.as_str())?; + let performancetype = parse_performance(performance_level.as_str())?; + + let min_conf = NonZeroU32::try_from(min_confirmations) + .map_err(|_| WalletError::Internal("min_confirmations must be >= 1".into()))?; + + let config = zingolib::config::load_clientconfig( + lightwalletd_uri.clone(), + None, + chaintype, + WalletSettings { + sync_config: SyncConfig { + transparent_address_discovery: TransparentAddressDiscovery::minimal(), + performance_level: performancetype, + }, + min_confirmations: min_conf, + }, + NonZeroU32::try_from(1).expect("hard-coded integer"), + "".to_string(), + ) + .map_err(|e| WalletError::Internal(format!("Config load error: {e}")))?; + + Ok((config, lightwalletd_uri)) +} + +fn with_lightclient_mut( + inner: &EngineInner, + f: impl FnOnce(&mut LightClient) -> Result, +) -> Result { + let mut guard = inner + .lightclient + .write() + .map_err(|_| WalletError::Internal("lightclient lock poisoned".into()))?; + let lc = guard.as_mut().ok_or(WalletError::NotInitialized)?; + f(lc) +} + +/// One runtime for the engine thread. +fn create_engine_runtime() -> tokio::runtime::Runtime { + tokio::runtime::Runtime::new().expect("tokio runtime") +} + #[uniffi::export] impl WalletEngine { #[uniffi::constructor] @@ -75,15 +184,22 @@ impl WalletEngine { let inner = Arc::new(EngineInner { cmd_tx, listener: Mutex::new(None), + lightclient: RwLock::new(None), + server_uri: RwLock::new(None), + wallet_path: RwLock::new(None), }); let inner_for_task = inner.clone(); std::thread::spawn(move || { - let rt = tokio::runtime::Runtime::new().expect("tokio runtime"); + let rt = create_engine_runtime(); + let handle = rt.handle().clone(); rt.block_on(async move { emit(&inner_for_task, WalletEvent::EngineReady); + // Keep a last-seen snapshot to emit BalanceChanged only on change + let mut last_balance: Option = None; + let mut syncing = false; while let Some(cmd) = cmd_rx.recv().await { @@ -92,33 +208,145 @@ impl WalletEngine { if syncing { continue; } - syncing = true; - emit(&inner_for_task, WalletEvent::SyncStarted); - - for i in 0..=100u32 { - tokio::time::sleep(Duration::from_millis(50)).await; + // Must be initialized + let start_res = with_lightclient_mut(&inner_for_task, |lc| { + // This follows your old run_sync() logic: + if lc.sync_mode() == SyncMode::Paused { + lc.resume_sync().map_err(|e| { + WalletError::Internal(format!("resume_sync: {e}")) + })?; + Ok(()) + } else { + // Launch the zingolib sync task + handle.block_on(async { + lc.sync().await.map(|_| ()).map_err(|e| { + WalletError::Internal(format!("sync(): {e}")) + }) + }) + } + }); + if let Err(e) = start_res { emit( &inner_for_task, - WalletEvent::SyncProgress { - wallet_height: 1000 + i, - network_height: 1100, - percent: i as f32 / 100.0, + WalletEvent::Error { + code: "start_sync_failed".into(), + message: e.to_string(), }, ); + continue; + } + + emit(&inner_for_task, WalletEvent::SyncStarted); + + // Progress loop: real status from pepper_sync + completion via poll_sync() + loop { + // If paused externally, break after emitting paused + let paused = with_lightclient_mut(&inner_for_task, |lc| { + Ok(lc.sync_mode() == SyncMode::Paused) + }) + .unwrap_or(false); - if !syncing { + if paused { + emit(&inner_for_task, WalletEvent::SyncPaused); + syncing = false; + break; + } + + let progress_res: Result<(u32, u32), WalletError> = + with_lightclient_mut(&inner_for_task, |lc| { + let wh = wallet_height_u32(lc, &handle)?; + + let nh = match get_server_uri(&inner_for_task) { + Some(uri) if uri != http::Uri::default() => { + network_height_u32(uri, &handle)? + } + _ => 0, // offline or not set + }; + + Ok((wh, nh)) + }); + + if let Ok((wh, nh)) = progress_res { + let percent = if nh > 0 { + (wh as f32 / nh as f32).clamp(0.0, 1.0) + } else { + 0.0 + }; + + emit( + &inner_for_task, + WalletEvent::SyncProgress { + wallet_height: wh, + network_height: nh, + percent, + }, + ); + } + + // Emit real balance if it changed + let bal_res: Result = + with_lightclient_mut(&inner_for_task, |lc| { + handle.block_on(async { + let bal = lc + .account_balance(AccountId::ZERO) + .await + .map_err(|e| { + WalletError::Internal(format!( + "account_balance: {e}" + )) + })?; + + // Change this mapping to match the concrete balance type you have. + Ok(balance_snapshot_from_balance(&bal)) + }) + }); + + if let Ok(snap) = bal_res { + if last_balance.as_ref() != Some(&snap) { + last_balance = Some(snap.clone()); + emit(&inner_for_task, WalletEvent::BalanceChanged(snap)); + } + } + + // Completion check: zingolib's real poll_sync() + let done = with_lightclient_mut(&inner_for_task, |lc| { + Ok(matches!(lc.poll_sync(), PollReport::Ready(_))) + }) + .unwrap_or(false); + + if done { + emit(&inner_for_task, WalletEvent::SyncFinished); + syncing = false; break; } - } - emit(&inner_for_task, WalletEvent::SyncFinished); - syncing = false; + tokio::time::sleep(Duration::from_millis(250)).await; + } } + Command::PauseSync => { - syncing = false; - emit(&inner_for_task, WalletEvent::SyncPaused); + let res = with_lightclient_mut(&inner_for_task, |lc| { + lc.pause_sync().map_err(|e| { + WalletError::Internal(format!("pause_sync: {e}")) + })?; + Ok(()) + }); + + match res { + Ok(_) => { + emit(&inner_for_task, WalletEvent::SyncPaused); + } + Err(e) => emit( + &inner_for_task, + WalletEvent::Error { + code: "pause_sync_failed".into(), + message: e.to_string(), + }, + ), + } } + Command::Shutdown => break, } } @@ -128,14 +356,13 @@ impl WalletEngine { Ok(Self { inner }) } - // Box for UniFFI + /// UniFFI callback: Box pub fn set_listener(&self, listener: Box) -> Result<(), WalletError> { let mut guard = self .inner .listener .lock() .map_err(|_| WalletError::ListenerLockPoisoned)?; - *guard = Some(Arc::from(listener)); Ok(()) } @@ -150,6 +377,105 @@ impl WalletEngine { Ok(()) } + /// Initialize a brand new wallet (like old init_new) + pub fn init_new( + &self, + server_uri: String, + chain_hint: String, + performance_level: String, + min_confirmations: u32, + ) -> Result<(), WalletError> { + let (config, lw_uri) = + construct_config(server_uri, chain_hint, performance_level, min_confirmations)?; + + // Get latest block from server (real network height) then pick birthday + let rt = create_engine_runtime(); + let lw_uri_for_height = lw_uri.clone(); + + let chain_height = rt.block_on(async move { + zingolib::grpc_connector::get_latest_block(lw_uri_for_height) + .await + .map(|block_id| BlockHeight::from_u32(block_id.height as u32)) + .map_err(|e| WalletError::Internal(format!("get_latest_block: {e}"))) + })?; + + let birthday = chain_height.saturating_sub(100); + + let lc = LightClient::new(config, birthday, false) + .map_err(|e| WalletError::Internal(format!("LightClient::new: {e}")))?; + + { + let mut g = self + .inner + .lightclient + .write() + .map_err(|_| WalletError::Internal("lightclient lock poisoned".into()))?; + *g = Some(lc); + } + + { + let mut g = self + .inner + .server_uri + .write() + .map_err(|_| WalletError::Internal("server_uri lock poisoned".into()))?; + *g = Some(lw_uri); + } + + Ok(()) + } + + /// Initialize from seed (like old init_from_seed) + pub fn init_from_seed( + &self, + seed_phrase: String, + birthday: u32, + server_uri: String, + chain_hint: String, + performance_level: String, + min_confirmations: u32, + ) -> Result<(), WalletError> { + let (config, lw_uri) = + construct_config(server_uri, chain_hint, performance_level, min_confirmations)?; + + let mnemonic = Mnemonic::from_phrase(seed_phrase) + .map_err(|e| WalletError::Internal(format!("Mnemonic parse: {e}")))?; + + let wallet = LightWallet::new( + config.chain, + WalletBase::Mnemonic { + mnemonic, + no_of_accounts: config.no_of_accounts, + }, + BlockHeight::from_u32(birthday), + config.wallet_settings.clone(), + ) + .map_err(|e| WalletError::Internal(format!("LightWallet::new: {e}")))?; + + let lc = LightClient::create_from_wallet(wallet, config, false) + .map_err(|e| WalletError::Internal(format!("create_from_wallet: {e}")))?; + + { + let mut g = self + .inner + .lightclient + .write() + .map_err(|_| WalletError::Internal("lightclient lock poisoned".into()))?; + *g = Some(lc); + } + + { + let mut g = self + .inner + .server_uri + .write() + .map_err(|_| WalletError::Internal("server_uri lock poisoned".into()))?; + *g = Some(lw_uri); + } + + Ok(()) + } + pub fn start_sync(&self) -> Result<(), WalletError> { self.inner .cmd_tx @@ -171,20 +497,309 @@ impl WalletEngine { .map_err(|_| WalletError::CommandQueueClosed) } + /// Real balance (Account 0). No simulation. pub fn get_balance_snapshot(&self) -> Result { - Ok(BalanceSnapshot { - confirmed: "0".to_string(), - total: "0".to_string(), + with_lightclient_mut(&self.inner, |lc| { + let rt = create_engine_runtime(); + rt.block_on(async { + let bal = lc + .account_balance(AccountId::ZERO) + .await + .map_err(|e| WalletError::Internal(format!("account_balance: {e}")))?; + + Ok(balance_snapshot_from_balance(&bal)) + }) }) } + + /// Expose poll_sync result if you still want it. + pub fn poll_sync(&self) -> Result { + with_lightclient_mut(&self.inner, |lc| { + Ok(matches!(lc.poll_sync(), PollReport::Ready(_))) + }) + } + + /// Change server like old change_server + pub fn change_server(&self, server_uri: String) -> Result<(), WalletError> { + let uri = if server_uri.is_empty() { + http::Uri::default() + } else { + http::Uri::from_str(&server_uri) + .map_err(|e| WalletError::Internal(format!("invalid uri: {e}")))? + }; + + with_lightclient_mut(&self.inner, |lc| { + lc.set_server(uri.clone()); + Ok(()) + })?; + + let mut g = self + .inner + .server_uri + .write() + .map_err(|_| WalletError::Internal("server_uri lock poisoned".into()))?; + *g = Some(uri); + + Ok(()) + } } -fn emit(inner: &EngineInner, event: WalletEvent) { - let listener_opt = inner.listener.lock().ok().and_then(|g| g.clone()); - if let Some(listener) = listener_opt { - // Avoid UnwindSafe errors. don’t let a callback panic crash the engine - let _ = panic::catch_unwind(AssertUnwindSafe(|| { - listener.on_event(event); - })); +fn get_server_uri(inner: &EngineInner) -> Option { + inner.server_uri.read().ok().and_then(|g| g.clone()) +} + +fn wallet_height_u32( + lc: &LightClient, + handle: &tokio::runtime::Handle, +) -> Result { + handle.block_on(async { + let wallet = lc.wallet.read().await; + Ok(wallet + .sync_state + .wallet_height() + .map(u32::from) + .unwrap_or(0)) + }) +} + +fn network_height_u32( + server_uri: http::Uri, + handle: &tokio::runtime::Handle, +) -> Result { + handle.block_on(async { + zingolib::grpc_connector::get_latest_block(server_uri) + .await + .map(|block_id| block_id.height as u32) + .map_err(|e| WalletError::Internal(format!("get_latest_block: {e}"))) + }) +} + +fn balance_snapshot_from_balance(b: &AccountBalance) -> BalanceSnapshot { + let confirmed = b + .confirmed_orchard_balance + .map(|v| v.into_u64()) + .unwrap_or(0) + + b.confirmed_sapling_balance + .map(|v| v.into_u64()) + .unwrap_or(0) + + b.confirmed_transparent_balance + .map(|v| v.into_u64()) + .unwrap_or(0); + + let total = b.total_orchard_balance.map(|v| v.into_u64()).unwrap_or(0) + + b.total_sapling_balance.map(|v| v.into_u64()).unwrap_or(0) + + b.total_transparent_balance + .map(|v| v.into_u64()) + .unwrap_or(0); + BalanceSnapshot { + confirmed: confirmed.to_string(), + + total: total.to_string(), + } +} + +#[cfg(test)] +mod test { + use std::time::Duration; + + use tokio::sync::mpsc; + + use crate::{WalletEngine, WalletError, WalletEvent, WalletListener}; + + #[derive(Clone)] + struct CapturingListener { + tx: mpsc::UnboundedSender, + } + + impl WalletListener for CapturingListener { + fn on_event(&self, event: WalletEvent) { + let _ = self.tx.send(event); + } + } + + /// A listener that panics on every callback, to verify panic containment. + struct PanickingListener; + + impl WalletListener for PanickingListener { + fn on_event(&self, _event: WalletEvent) { + panic!("listener panicked"); + } + } + + async fn recv_with_timeout( + rx: &mut mpsc::UnboundedReceiver, + dur: Duration, + ) -> WalletEvent { + tokio::time::timeout(dur, rx.recv()) + .await + .expect("timeout waiting for event") + .expect("channel closed unexpectedly") + } + + async fn expect_engine_ready(rx: &mut mpsc::UnboundedReceiver) { + // EngineReady is typically the first event after listener is set, + // but depending on timing it could already have happened. + // So: wait a bit for *some* event and accept EngineReady if seen. + let ev = recv_with_timeout(rx, Duration::from_secs(2)).await; + assert!( + matches!(ev, WalletEvent::EngineReady), + "expected EngineReady, got: {ev:?}" + ); + } + + async fn expect_error_event( + rx: &mut mpsc::UnboundedReceiver, + code: &str, + ) -> WalletEvent { + // Drain until we see the desired Error code, helps tolerate extra events + let deadline = tokio::time::Instant::now() + Duration::from_secs(3); + loop { + let now = tokio::time::Instant::now(); + if now >= deadline { + panic!("timeout waiting for Error({code})"); + } + let remaining = deadline - now; + let ev = recv_with_timeout(rx, remaining).await; + if let WalletEvent::Error { code: c, .. } = &ev { + if c == code { + return ev; + } + } + } + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn emits_engine_ready() { + let engine = WalletEngine::new().expect("engine new"); + + let (tx, mut rx) = mpsc::unbounded_channel(); + engine + .set_listener(Box::new(CapturingListener { tx })) + .expect("set_listener"); + + expect_engine_ready(&mut rx).await; + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn get_balance_snapshot_errors_when_not_initialized() { + let engine = WalletEngine::new().expect("engine new"); + + let res = engine.get_balance_snapshot(); + assert!( + matches!(res, Err(WalletError::NotInitialized)), + "expected NotInitialized, got: {res:?}" + ); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn start_sync_emits_error_when_not_initialized() { + let engine = WalletEngine::new().expect("engine new"); + + let (tx, mut rx) = mpsc::unbounded_channel(); + engine + .set_listener(Box::new(CapturingListener { tx })) + .expect("set_listener"); + + expect_engine_ready(&mut rx).await; + + engine.start_sync().expect("start_sync send command"); + + // The command loop should emit an Error event when it can't start. + let ev = expect_error_event(&mut rx, "start_sync_failed").await; + match ev { + WalletEvent::Error { code, message } => { + assert_eq!(code, "start_sync_failed"); + assert!(!message.is_empty(), "expected non-empty error message"); + } + other => panic!("expected Error event, got {other:?}"), + } + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn listener_panics_do_not_crash_engine_thread() { + let engine = WalletEngine::new().expect("engine new"); + + // Install a panicking listener. + engine + .set_listener(Box::new(PanickingListener)) + .expect("set_listener panicking"); + + // Trigger an event from the engine thread. This will call listener and panic, + // but emit() must catch_unwind and keep the engine alive. + engine.start_sync().expect("start_sync send command"); + + // Give the engine a moment to process and hit the callback. + tokio::time::sleep(Duration::from_millis(200)).await; + + // Swap in a capturing listener. If the engine thread died, we won't get events now. + let (tx, mut rx) = mpsc::unbounded_channel(); + engine + .set_listener(Box::new(CapturingListener { tx })) + .expect("set_listener capturing"); + + // Now trigger another command that should result in an Error event + // (since still not initialized). If we receive it, engine thread is alive. + engine.pause_sync().expect("pause_sync send command"); + + let ev = expect_error_event(&mut rx, "pause_sync_failed").await; + assert!( + matches!(ev, WalletEvent::Error { .. }), + "expected Error, got {ev:?}" + ); + } + + // TODO: Do not use env vars. Use the infra repo somehow. + // + // ZINGO_TEST_SERVER_URI="https://..." \ + // ZINGO_TEST_CHAIN_HINT="test" \ + // ZINGO_TEST_PERF="Medium" \ + // ZINGO_TEST_MINCONF="1" \ + // cargo test -p ffi real_sync_smoke -- --ignored --nocapture + // + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + #[ignore] + async fn real_sync_smoke() { + let server_uri = std::env::var("ZINGO_TEST_SERVER_URI").expect("ZINGO_TEST_SERVER_URI"); + let chain_hint = std::env::var("ZINGO_TEST_CHAIN_HINT").unwrap_or_else(|_| "test".into()); + let perf = std::env::var("ZINGO_TEST_PERF").unwrap_or_else(|_| "Medium".into()); + let minconf: u32 = std::env::var("ZINGO_TEST_MINCONF") + .unwrap_or_else(|_| "1".into()) + .parse() + .expect("ZINGO_TEST_MINCONF must be u32"); + + let engine = WalletEngine::new().expect("engine new"); + + let (tx, mut rx) = mpsc::unbounded_channel(); + engine + .set_listener(Box::new(CapturingListener { tx })) + .expect("set_listener"); + + expect_engine_ready(&mut rx).await; + + engine + .init_new(server_uri, chain_hint, perf, minconf) + .expect("init_new"); + + engine.start_sync().expect("start_sync"); + + // Wait until SyncFinished or timeout. + let deadline = tokio::time::Instant::now() + Duration::from_secs(90); + loop { + let now = tokio::time::Instant::now(); + if now >= deadline { + panic!("timeout waiting for SyncFinished"); + } + let ev = recv_with_timeout(&mut rx, deadline - now).await; + match ev { + WalletEvent::SyncFinished => break, + WalletEvent::Error { code, message } => { + panic!("sync error: {code} {message}"); + } + _ => {} + } + } + + let bal = engine.get_balance_snapshot().expect("balance snapshot"); + println!("balance after sync: {bal:?}"); } } From b723d18534613bd65b7fb723d68e7453991402db Mon Sep 17 00:00:00 2001 From: dorianvp Date: Wed, 11 Feb 2026 00:22:17 -0300 Subject: [PATCH 03/15] chore: wip new model --- ffi/rust/src/lib.rs | 1197 ++++++++++++++++++++++++++----------------- 1 file changed, 719 insertions(+), 478 deletions(-) diff --git a/ffi/rust/src/lib.rs b/ffi/rust/src/lib.rs index ceda9b852..3ab91a7d7 100644 --- a/ffi/rust/src/lib.rs +++ b/ffi/rust/src/lib.rs @@ -1,31 +1,25 @@ use std::{ + num::NonZeroU32, panic::{self, AssertUnwindSafe}, - path::PathBuf, - str::FromStr, - sync::{Arc, Mutex, RwLock}, + sync::{Arc, Mutex}, + thread, time::Duration, }; -use tokio::sync::mpsc; - -use std::num::NonZeroU32; - use bip0039::Mnemonic; use pepper_sync::config::{PerformanceLevel, SyncConfig, TransparentAddressDiscovery}; use pepper_sync::wallet::SyncMode; +use tokio::sync::{mpsc, oneshot}; use zcash_primitives::consensus::BlockHeight; use zcash_primitives::zip32::AccountId; - -use zingolib::data::PollReport; -use zingolib::lightclient::LightClient; -use zingolib::wallet::{LightWallet, WalletBase, WalletSettings}; +use zingo_common_components::protocol::activation_heights::for_test; use zingolib::{ config::{ChainType, ZingoConfig, construct_lightwalletd_uri}, - wallet::balance::AccountBalance, + data::PollReport, + lightclient::LightClient, + wallet::{LightWallet, WalletBase, WalletSettings, balance::AccountBalance}, }; -use zingo_common_components::protocol::activation_heights::for_test; - uniffi::setup_scaffolding!(); #[derive(Debug, thiserror::Error, uniffi::Error)] @@ -40,6 +34,38 @@ pub enum WalletError { Internal(String), } +#[derive(Clone, Copy, Debug, uniffi::Enum)] +pub enum Chain { + Mainnet, + Testnet, + Regtest, +} + +#[derive(Clone, Copy, Debug, uniffi::Enum)] +pub enum Performance { + Maximum, + High, + Medium, + Low, +} + +fn chain_to_chaintype(chain: Chain) -> ChainType { + match chain { + Chain::Mainnet => ChainType::Mainnet, + Chain::Testnet => ChainType::Testnet, + Chain::Regtest => ChainType::Regtest(for_test::all_height_one_nus()), + } +} + +fn perf_to_level(p: Performance) -> PerformanceLevel { + match p { + Performance::Maximum => PerformanceLevel::Maximum, + Performance::High => PerformanceLevel::High, + Performance::Medium => PerformanceLevel::Medium, + Performance::Low => PerformanceLevel::Low, + } +} + #[derive(Clone, Debug, uniffi::Record, PartialEq, Eq)] pub struct BalanceSnapshot { pub confirmed: String, @@ -58,9 +84,6 @@ pub enum WalletEvent { SyncPaused, SyncFinished, BalanceChanged(BalanceSnapshot), - NewTransaction { - txid: String, - }, Error { code: String, message: String, @@ -72,69 +95,37 @@ pub trait WalletListener: Send + Sync { fn on_event(&self, event: WalletEvent); } -enum Command { - StartSync, - PauseSync, - Shutdown, -} - -struct EngineInner { - cmd_tx: mpsc::Sender, - listener: Mutex>>, - - // Real state - lightclient: RwLock>, - server_uri: RwLock>, - - wallet_path: RwLock>, -} - -#[derive(uniffi::Object)] -pub struct WalletEngine { - inner: Arc, -} - -fn emit(inner: &EngineInner, event: WalletEvent) { - let listener_opt = inner.listener.lock().ok().and_then(|g| g.clone()); - if let Some(listener) = listener_opt { - let _ = panic::catch_unwind(AssertUnwindSafe(|| { - listener.on_event(event); - })); - } -} +fn balance_snapshot_from_balance(b: &AccountBalance) -> BalanceSnapshot { + let confirmed = b + .confirmed_orchard_balance + .map(|v| v.into_u64()) + .unwrap_or(0) + + b.confirmed_sapling_balance + .map(|v| v.into_u64()) + .unwrap_or(0) + + b.confirmed_transparent_balance + .map(|v| v.into_u64()) + .unwrap_or(0); -fn parse_chain(chain_hint: &str) -> Result { - match chain_hint { - "main" => Ok(ChainType::Mainnet), - "test" => Ok(ChainType::Testnet), - "regtest" => Ok(ChainType::Regtest(for_test::all_height_one_nus())), - other => Err(WalletError::Internal(format!( - "Invalid chain hint: {other} (expected main|test|regtest)" - ))), - } -} + let total = b.total_orchard_balance.map(|v| v.into_u64()).unwrap_or(0) + + b.total_sapling_balance.map(|v| v.into_u64()).unwrap_or(0) + + b.total_transparent_balance + .map(|v| v.into_u64()) + .unwrap_or(0); -fn parse_performance(performance_level: &str) -> Result { - match performance_level { - "Maximum" => Ok(PerformanceLevel::Maximum), - "High" => Ok(PerformanceLevel::High), - "Medium" => Ok(PerformanceLevel::Medium), - "Low" => Ok(PerformanceLevel::Low), - other => Err(WalletError::Internal(format!( - "Invalid performance level: {other} (expected Maximum|High|Medium|Low)" - ))), + BalanceSnapshot { + confirmed: confirmed.to_string(), + total: total.to_string(), } } fn construct_config( server_uri: String, - chain_hint: String, - performance_level: String, + chain: Chain, + perf: Performance, min_confirmations: u32, ) -> Result<(ZingoConfig, http::Uri), WalletError> { let lightwalletd_uri = construct_lightwalletd_uri(Some(server_uri)); - let chaintype = parse_chain(chain_hint.as_str())?; - let performancetype = parse_performance(performance_level.as_str())?; let min_conf = NonZeroU32::try_from(min_confirmations) .map_err(|_| WalletError::Internal("min_confirmations must be >= 1".into()))?; @@ -142,11 +133,11 @@ fn construct_config( let config = zingolib::config::load_clientconfig( lightwalletd_uri.clone(), None, - chaintype, + chain_to_chaintype(chain), WalletSettings { sync_config: SyncConfig { transparent_address_discovery: TransparentAddressDiscovery::minimal(), - performance_level: performancetype, + performance_level: perf_to_level(perf), }, min_confirmations: min_conf, }, @@ -158,19 +149,54 @@ fn construct_config( Ok((config, lightwalletd_uri)) } -fn with_lightclient_mut( - inner: &EngineInner, - f: impl FnOnce(&mut LightClient) -> Result, -) -> Result { - let mut guard = inner - .lightclient - .write() - .map_err(|_| WalletError::Internal("lightclient lock poisoned".into()))?; - let lc = guard.as_mut().ok_or(WalletError::NotInitialized)?; - f(lc) +struct EngineInner { + cmd_tx: mpsc::Sender, + listener: Mutex>>, +} + +fn emit(inner: &EngineInner, event: WalletEvent) { + let listener_opt = inner.listener.lock().ok().and_then(|g| g.clone()); + if let Some(listener) = listener_opt { + let _ = panic::catch_unwind(AssertUnwindSafe(|| { + listener.on_event(event); + })); + } +} + +enum Command { + InitNew { + server_uri: String, + chain: Chain, + perf: Performance, + minconf: u32, + reply: oneshot::Sender>, + }, + InitFromSeed { + seed_phrase: String, + birthday: u32, + server_uri: String, + chain: Chain, + perf: Performance, + minconf: u32, + reply: oneshot::Sender>, + }, + GetBalance { + reply: oneshot::Sender>, + }, + GetNetworkHeight { + reply: oneshot::Sender>, + }, + StartSync, + PauseSync, + Shutdown, +} + +#[derive(uniffi::Object, Clone)] +pub struct WalletEngine { + inner: Arc, } -/// One runtime for the engine thread. +/// Engine thread runtime only. fn create_engine_runtime() -> tokio::runtime::Runtime { tokio::runtime::Runtime::new().expect("tokio runtime") } @@ -184,141 +210,268 @@ impl WalletEngine { let inner = Arc::new(EngineInner { cmd_tx, listener: Mutex::new(None), - lightclient: RwLock::new(None), - server_uri: RwLock::new(None), - wallet_path: RwLock::new(None), }); let inner_for_task = inner.clone(); - std::thread::spawn(move || { + thread::spawn(move || { let rt = create_engine_runtime(); - let handle = rt.handle().clone(); rt.block_on(async move { emit(&inner_for_task, WalletEvent::EngineReady); - // Keep a last-seen snapshot to emit BalanceChanged only on change - let mut last_balance: Option = None; + // Engine-owned state + let mut lightclient: Option = None; + let mut server_uri: Option = None; + // Keep last emitted balance snapshot + let mut last_balance: Option = None; let mut syncing = false; while let Some(cmd) = cmd_rx.recv().await { match cmd { + Command::GetNetworkHeight { reply } => { + todo!() + } + Command::InitNew { + server_uri: srv, + chain, + perf, + minconf, + reply, + } => { + let res: Result<(), WalletError> = (async { + let (config, lw_uri) = construct_config(srv, chain, perf, minconf)?; + + let chain_height = + zingolib::grpc_connector::get_latest_block(lw_uri.clone()) + .await + .map(|b| BlockHeight::from_u32(b.height as u32)) + .map_err(|e| { + WalletError::Internal(format!("get_latest_block: {e}")) + })?; + + let birthday = chain_height.saturating_sub(100); + + let lc = + LightClient::new(config, birthday, false).map_err(|e| { + WalletError::Internal(format!("LightClient::new: {e}")) + })?; + + lightclient = Some(lc); + server_uri = Some(lw_uri); + last_balance = None; + Ok(()) + }) + .await; + + let _ = reply.send(res); + } + + Command::InitFromSeed { + seed_phrase, + birthday, + server_uri: srv, + chain, + perf, + minconf, + reply, + } => { + let res: Result<(), WalletError> = (async { + let (config, lw_uri) = construct_config(srv, chain, perf, minconf)?; + + let mnemonic = Mnemonic::from_phrase(seed_phrase) + .map_err(|e| WalletError::Internal(format!("Mnemonic: {e}")))?; + + let wallet = LightWallet::new( + config.chain, + WalletBase::Mnemonic { + mnemonic, + no_of_accounts: config.no_of_accounts, + }, + BlockHeight::from_u32(birthday), + config.wallet_settings.clone(), + ) + .map_err(|e| { + WalletError::Internal(format!("LightWallet::new: {e}")) + })?; + + let lc = LightClient::create_from_wallet(wallet, config, false) + .map_err(|e| { + WalletError::Internal(format!("create_from_wallet: {e}")) + })?; + + lightclient = Some(lc); + server_uri = Some(lw_uri); + last_balance = None; + Ok(()) + }) + .await; + + let _ = reply.send(res); + } + + Command::GetBalance { reply } => { + let res: Result = (async { + let lc = lightclient.as_mut().ok_or(WalletError::NotInitialized)?; + let bal = + lc.account_balance(AccountId::ZERO).await.map_err(|e| { + WalletError::Internal(format!("account_balance: {e}")) + })?; + Ok(balance_snapshot_from_balance(&bal)) + }) + .await; + + let _ = reply.send(res); + } + Command::StartSync => { + // manual model: one round per StartSync if syncing { + // ignore repeated StartSync while running continue; } - // Must be initialized - let start_res = with_lightclient_mut(&inner_for_task, |lc| { - // This follows your old run_sync() logic: - if lc.sync_mode() == SyncMode::Paused { - lc.resume_sync().map_err(|e| { - WalletError::Internal(format!("resume_sync: {e}")) - })?; - Ok(()) - } else { - // Launch the zingolib sync task - handle.block_on(async { - lc.sync().await.map(|_| ()).map_err(|e| { - WalletError::Internal(format!("sync(): {e}")) - }) - }) - } - }); - if let Err(e) = start_res { + let Some(lc) = lightclient.as_mut() else { emit( &inner_for_task, WalletEvent::Error { code: "start_sync_failed".into(), - message: e.to_string(), + message: WalletError::NotInitialized.to_string(), }, ); continue; - } + }; + syncing = true; emit(&inner_for_task, WalletEvent::SyncStarted); - // Progress loop: real status from pepper_sync + completion via poll_sync() - loop { - // If paused externally, break after emitting paused - let paused = with_lightclient_mut(&inner_for_task, |lc| { - Ok(lc.sync_mode() == SyncMode::Paused) - }) - .unwrap_or(false); + // If sync was paused previously, resume; otherwise start a new sync task. + // This mirrors old behavior: resume if paused else sync(). + if lc.sync_mode() == SyncMode::Paused { + if let Err(e) = lc.pause_sync() { + // NOTE: if zingolib has resume_sync() use that instead; + // you showed resume_sync() in the older file. + // Replace this with lc.resume_sync(). + emit( + &inner_for_task, + WalletEvent::Error { + code: "start_sync_failed".into(), + message: format!("resume_sync: {e}"), + }, + ); + syncing = false; + break; // or continue; depending on your loop structure + } + } else { + // Start the sync task once. + if let Err(e) = lc.sync().await { + emit( + &inner_for_task, + WalletEvent::Error { + code: "sync_failed".into(), + message: e.to_string(), + }, + ); + syncing = false; + continue; + } + } + + // Progress loop: keep reporting while the sync task is running. + // We stop when poll_sync() becomes Ready(_). + let mut last_balance_emitted: Option = None; - if paused { + loop { + // If user paused, stop reporting and exit this round. + if lc.sync_mode() == SyncMode::Paused { emit(&inner_for_task, WalletEvent::SyncPaused); syncing = false; break; } - let progress_res: Result<(u32, u32), WalletError> = - with_lightclient_mut(&inner_for_task, |lc| { - let wh = wallet_height_u32(lc, &handle)?; - - let nh = match get_server_uri(&inner_for_task) { - Some(uri) if uri != http::Uri::default() => { - network_height_u32(uri, &handle)? - } - _ => 0, // offline or not set - }; - - Ok((wh, nh)) - }); + // Compute wallet height (local) + let wh = { + let w = lc.wallet.read().await; + w.sync_state + .highest_scanned_height() + .map(u32::from) + .unwrap_or(0) + }; + + // Compute network height (best effort from last known server_uri) + let nh = match server_uri.as_ref() { + Some(uri) if *uri != http::Uri::default() => { + match zingolib::grpc_connector::get_latest_block( + uri.clone(), + ) + .await + { + Ok(b) => b.height as u32, + Err(_) => 0, + } + } + _ => 0, + }; - if let Ok((wh, nh)) = progress_res { - let percent = if nh > 0 { - (wh as f32 / nh as f32).clamp(0.0, 1.0) - } else { - 0.0 - }; + let percent = if nh > 0 { + (wh as f32 / nh as f32).clamp(0.0, 1.0) + } else { + 0.0 + }; - emit( - &inner_for_task, - WalletEvent::SyncProgress { - wallet_height: wh, - network_height: nh, - percent, - }, - ); - } + emit( + &inner_for_task, + WalletEvent::SyncProgress { + wallet_height: wh, + network_height: nh, + percent, + }, + ); - // Emit real balance if it changed - let bal_res: Result = - with_lightclient_mut(&inner_for_task, |lc| { - handle.block_on(async { - let bal = lc - .account_balance(AccountId::ZERO) - .await - .map_err(|e| { - WalletError::Internal(format!( - "account_balance: {e}" - )) - })?; - - // Change this mapping to match the concrete balance type you have. - Ok(balance_snapshot_from_balance(&bal)) - }) - }); - - if let Ok(snap) = bal_res { - if last_balance.as_ref() != Some(&snap) { - last_balance = Some(snap.clone()); - emit(&inner_for_task, WalletEvent::BalanceChanged(snap)); + // Emit balance changes + match lc.account_balance(AccountId::ZERO).await { + Ok(bal) => { + let snap = balance_snapshot_from_balance(&bal); + if last_balance_emitted.as_ref() != Some(&snap) { + last_balance_emitted = Some(snap.clone()); + emit( + &inner_for_task, + WalletEvent::BalanceChanged(snap), + ); + } + } + Err(e) => { + emit( + &inner_for_task, + WalletEvent::Error { + code: "balance_failed".into(), + message: e.to_string(), + }, + ); } } - // Completion check: zingolib's real poll_sync() - let done = with_lightclient_mut(&inner_for_task, |lc| { - Ok(matches!(lc.poll_sync(), PollReport::Ready(_))) - }) - .unwrap_or(false); - - if done { - emit(&inner_for_task, WalletEvent::SyncFinished); - syncing = false; - break; + // Completion check + match lc.poll_sync() { + PollReport::Ready(Ok(_sync_result)) => { + emit(&inner_for_task, WalletEvent::SyncFinished); + syncing = false; + break; + } + PollReport::Ready(Err(e)) => { + emit( + &inner_for_task, + WalletEvent::Error { + code: "sync_failed".into(), + message: e.to_string(), + }, + ); + syncing = false; + break; + } + PollReport::NotReady | PollReport::NoHandle => { + // Still running, keep looping + } } tokio::time::sleep(Duration::from_millis(250)).await; @@ -326,17 +479,19 @@ impl WalletEngine { } Command::PauseSync => { - let res = with_lightclient_mut(&inner_for_task, |lc| { - lc.pause_sync().map_err(|e| { - WalletError::Internal(format!("pause_sync: {e}")) - })?; - Ok(()) - }); + let Some(lc) = lightclient.as_mut() else { + emit( + &inner_for_task, + WalletEvent::Error { + code: "pause_sync_failed".into(), + message: WalletError::NotInitialized.to_string(), + }, + ); + continue; + }; - match res { - Ok(_) => { - emit(&inner_for_task, WalletEvent::SyncPaused); - } + match lc.pause_sync() { + Ok(_) => emit(&inner_for_task, WalletEvent::SyncPaused), Err(e) => emit( &inner_for_task, WalletEvent::Error { @@ -356,7 +511,6 @@ impl WalletEngine { Ok(Self { inner }) } - /// UniFFI callback: Box pub fn set_listener(&self, listener: Box) -> Result<(), WalletError> { let mut guard = self .inner @@ -377,103 +531,80 @@ impl WalletEngine { Ok(()) } - /// Initialize a brand new wallet (like old init_new) pub fn init_new( &self, server_uri: String, - chain_hint: String, - performance_level: String, - min_confirmations: u32, + chain: Chain, + perf: Performance, + minconf: u32, ) -> Result<(), WalletError> { - let (config, lw_uri) = - construct_config(server_uri, chain_hint, performance_level, min_confirmations)?; - - // Get latest block from server (real network height) then pick birthday - let rt = create_engine_runtime(); - let lw_uri_for_height = lw_uri.clone(); - - let chain_height = rt.block_on(async move { - zingolib::grpc_connector::get_latest_block(lw_uri_for_height) - .await - .map(|block_id| BlockHeight::from_u32(block_id.height as u32)) - .map_err(|e| WalletError::Internal(format!("get_latest_block: {e}"))) - })?; - - let birthday = chain_height.saturating_sub(100); - - let lc = LightClient::new(config, birthday, false) - .map_err(|e| WalletError::Internal(format!("LightClient::new: {e}")))?; - - { - let mut g = self - .inner - .lightclient - .write() - .map_err(|_| WalletError::Internal("lightclient lock poisoned".into()))?; - *g = Some(lc); - } - - { - let mut g = self - .inner - .server_uri - .write() - .map_err(|_| WalletError::Internal("server_uri lock poisoned".into()))?; - *g = Some(lw_uri); - } + let (reply_tx, reply_rx) = oneshot::channel(); + self.inner + .cmd_tx + .blocking_send(Command::InitNew { + server_uri, + chain, + perf, + minconf, + reply: reply_tx, + }) + .map_err(|_| WalletError::CommandQueueClosed)?; - Ok(()) + reply_rx + .blocking_recv() + .map_err(|_| WalletError::CommandQueueClosed)? } - /// Initialize from seed (like old init_from_seed) pub fn init_from_seed( &self, seed_phrase: String, birthday: u32, server_uri: String, - chain_hint: String, - performance_level: String, - min_confirmations: u32, + chain: Chain, + perf: Performance, + minconf: u32, ) -> Result<(), WalletError> { - let (config, lw_uri) = - construct_config(server_uri, chain_hint, performance_level, min_confirmations)?; + let (reply_tx, reply_rx) = oneshot::channel(); + self.inner + .cmd_tx + .blocking_send(Command::InitFromSeed { + seed_phrase, + birthday, + server_uri, + chain, + perf, + minconf, + reply: reply_tx, + }) + .map_err(|_| WalletError::CommandQueueClosed)?; - let mnemonic = Mnemonic::from_phrase(seed_phrase) - .map_err(|e| WalletError::Internal(format!("Mnemonic parse: {e}")))?; + reply_rx + .blocking_recv() + .map_err(|_| WalletError::CommandQueueClosed)? + } - let wallet = LightWallet::new( - config.chain, - WalletBase::Mnemonic { - mnemonic, - no_of_accounts: config.no_of_accounts, - }, - BlockHeight::from_u32(birthday), - config.wallet_settings.clone(), - ) - .map_err(|e| WalletError::Internal(format!("LightWallet::new: {e}")))?; - - let lc = LightClient::create_from_wallet(wallet, config, false) - .map_err(|e| WalletError::Internal(format!("create_from_wallet: {e}")))?; - - { - let mut g = self - .inner - .lightclient - .write() - .map_err(|_| WalletError::Internal("lightclient lock poisoned".into()))?; - *g = Some(lc); - } + pub fn get_balance_snapshot(&self) -> Result { + let (reply_tx, reply_rx) = oneshot::channel(); + self.inner + .cmd_tx + .blocking_send(Command::GetBalance { reply: reply_tx }) + .map_err(|_| WalletError::CommandQueueClosed)?; - { - let mut g = self - .inner - .server_uri - .write() - .map_err(|_| WalletError::Internal("server_uri lock poisoned".into()))?; - *g = Some(lw_uri); - } + reply_rx + .blocking_recv() + .map_err(|_| WalletError::CommandQueueClosed)? + } - Ok(()) + pub fn get_network_height(&self) -> Result { + let (reply_tx, reply_rx) = oneshot::channel(); + self.inner + .cmd_tx + .blocking_send(Command::GetNetworkHeight { reply: reply_tx }) + .map_err(|_| WalletError::CommandQueueClosed)?; + + reply_rx + .blocking_recv() + .map_err(|_| WalletError::CommandQueueClosed)? } pub fn start_sync(&self) -> Result<(), WalletError> { @@ -496,119 +627,16 @@ impl WalletEngine { .try_send(Command::Shutdown) .map_err(|_| WalletError::CommandQueueClosed) } - - /// Real balance (Account 0). No simulation. - pub fn get_balance_snapshot(&self) -> Result { - with_lightclient_mut(&self.inner, |lc| { - let rt = create_engine_runtime(); - rt.block_on(async { - let bal = lc - .account_balance(AccountId::ZERO) - .await - .map_err(|e| WalletError::Internal(format!("account_balance: {e}")))?; - - Ok(balance_snapshot_from_balance(&bal)) - }) - }) - } - - /// Expose poll_sync result if you still want it. - pub fn poll_sync(&self) -> Result { - with_lightclient_mut(&self.inner, |lc| { - Ok(matches!(lc.poll_sync(), PollReport::Ready(_))) - }) - } - - /// Change server like old change_server - pub fn change_server(&self, server_uri: String) -> Result<(), WalletError> { - let uri = if server_uri.is_empty() { - http::Uri::default() - } else { - http::Uri::from_str(&server_uri) - .map_err(|e| WalletError::Internal(format!("invalid uri: {e}")))? - }; - - with_lightclient_mut(&self.inner, |lc| { - lc.set_server(uri.clone()); - Ok(()) - })?; - - let mut g = self - .inner - .server_uri - .write() - .map_err(|_| WalletError::Internal("server_uri lock poisoned".into()))?; - *g = Some(uri); - - Ok(()) - } -} - -fn get_server_uri(inner: &EngineInner) -> Option { - inner.server_uri.read().ok().and_then(|g| g.clone()) -} - -fn wallet_height_u32( - lc: &LightClient, - handle: &tokio::runtime::Handle, -) -> Result { - handle.block_on(async { - let wallet = lc.wallet.read().await; - Ok(wallet - .sync_state - .wallet_height() - .map(u32::from) - .unwrap_or(0)) - }) -} - -fn network_height_u32( - server_uri: http::Uri, - handle: &tokio::runtime::Handle, -) -> Result { - handle.block_on(async { - zingolib::grpc_connector::get_latest_block(server_uri) - .await - .map(|block_id| block_id.height as u32) - .map_err(|e| WalletError::Internal(format!("get_latest_block: {e}"))) - }) -} - -fn balance_snapshot_from_balance(b: &AccountBalance) -> BalanceSnapshot { - let confirmed = b - .confirmed_orchard_balance - .map(|v| v.into_u64()) - .unwrap_or(0) - + b.confirmed_sapling_balance - .map(|v| v.into_u64()) - .unwrap_or(0) - + b.confirmed_transparent_balance - .map(|v| v.into_u64()) - .unwrap_or(0); - - let total = b.total_orchard_balance.map(|v| v.into_u64()).unwrap_or(0) - + b.total_sapling_balance.map(|v| v.into_u64()).unwrap_or(0) - + b.total_transparent_balance - .map(|v| v.into_u64()) - .unwrap_or(0); - BalanceSnapshot { - confirmed: confirmed.to_string(), - - total: total.to_string(), - } } #[cfg(test)] -mod test { - use std::time::Duration; - - use tokio::sync::mpsc; - - use crate::{WalletEngine, WalletError, WalletEvent, WalletListener}; +mod tests { + use super::*; + use std::sync::mpsc as std_mpsc; #[derive(Clone)] struct CapturingListener { - tx: mpsc::UnboundedSender, + tx: std_mpsc::Sender, } impl WalletListener for CapturingListener { @@ -626,170 +654,125 @@ mod test { } } - async fn recv_with_timeout( - rx: &mut mpsc::UnboundedReceiver, - dur: Duration, - ) -> WalletEvent { - tokio::time::timeout(dur, rx.recv()) - .await - .expect("timeout waiting for event") - .expect("channel closed unexpectedly") - } - - async fn expect_engine_ready(rx: &mut mpsc::UnboundedReceiver) { - // EngineReady is typically the first event after listener is set, - // but depending on timing it could already have happened. - // So: wait a bit for *some* event and accept EngineReady if seen. - let ev = recv_with_timeout(rx, Duration::from_secs(2)).await; - assert!( - matches!(ev, WalletEvent::EngineReady), - "expected EngineReady, got: {ev:?}" - ); + fn recv_timeout(rx: &std_mpsc::Receiver, dur: Duration) -> WalletEvent { + rx.recv_timeout(dur).expect("timeout waiting for event") } - async fn expect_error_event( - rx: &mut mpsc::UnboundedReceiver, - code: &str, - ) -> WalletEvent { - // Drain until we see the desired Error code, helps tolerate extra events - let deadline = tokio::time::Instant::now() + Duration::from_secs(3); - loop { - let now = tokio::time::Instant::now(); - if now >= deadline { - panic!("timeout waiting for Error({code})"); - } - let remaining = deadline - now; - let ev = recv_with_timeout(rx, remaining).await; - if let WalletEvent::Error { code: c, .. } = &ev { - if c == code { - return ev; - } - } - } - } - - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] - async fn emits_engine_ready() { + #[test] + fn emits_engine_ready() { let engine = WalletEngine::new().expect("engine new"); - let (tx, mut rx) = mpsc::unbounded_channel(); + let (tx, rx) = std_mpsc::channel(); engine .set_listener(Box::new(CapturingListener { tx })) .expect("set_listener"); - expect_engine_ready(&mut rx).await; + let ev = recv_timeout(&rx, Duration::from_secs(2)); + assert!(matches!(ev, WalletEvent::EngineReady), "got: {ev:?}"); } - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] - async fn get_balance_snapshot_errors_when_not_initialized() { + #[test] + fn get_balance_snapshot_errors_when_not_initialized() { let engine = WalletEngine::new().expect("engine new"); - let res = engine.get_balance_snapshot(); assert!( matches!(res, Err(WalletError::NotInitialized)), - "expected NotInitialized, got: {res:?}" + "got: {res:?}" ); } - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] - async fn start_sync_emits_error_when_not_initialized() { + #[test] + fn start_sync_emits_error_when_not_initialized() { let engine = WalletEngine::new().expect("engine new"); - let (tx, mut rx) = mpsc::unbounded_channel(); + let (tx, rx) = std_mpsc::channel(); engine .set_listener(Box::new(CapturingListener { tx })) .expect("set_listener"); - expect_engine_ready(&mut rx).await; + // EngineReady first + let _ = recv_timeout(&rx, Duration::from_secs(2)); engine.start_sync().expect("start_sync send command"); - // The command loop should emit an Error event when it can't start. - let ev = expect_error_event(&mut rx, "start_sync_failed").await; - match ev { - WalletEvent::Error { code, message } => { - assert_eq!(code, "start_sync_failed"); - assert!(!message.is_empty(), "expected non-empty error message"); + // Should emit error from engine thread + loop { + let ev = recv_timeout(&rx, Duration::from_secs(2)); + match ev { + WalletEvent::Error { code, message } => { + assert_eq!(code, "start_sync_failed"); + assert!(!message.is_empty()); + break; + } + _ => {} } - other => panic!("expected Error event, got {other:?}"), } } - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] - async fn listener_panics_do_not_crash_engine_thread() { + #[test] + fn listener_panics_do_not_crash_engine_thread() { let engine = WalletEngine::new().expect("engine new"); - // Install a panicking listener. engine .set_listener(Box::new(PanickingListener)) .expect("set_listener panicking"); - // Trigger an event from the engine thread. This will call listener and panic, - // but emit() must catch_unwind and keep the engine alive. + // Trigger something that will cause a callback (and panic). engine.start_sync().expect("start_sync send command"); - // Give the engine a moment to process and hit the callback. - tokio::time::sleep(Duration::from_millis(200)).await; + // Give engine time to process callback panic. + std::thread::sleep(Duration::from_millis(200)); - // Swap in a capturing listener. If the engine thread died, we won't get events now. - let (tx, mut rx) = mpsc::unbounded_channel(); + // Swap in capturing listener; if engine thread died, no more events ever. + let (tx, rx) = std_mpsc::channel(); engine .set_listener(Box::new(CapturingListener { tx })) .expect("set_listener capturing"); - // Now trigger another command that should result in an Error event - // (since still not initialized). If we receive it, engine thread is alive. + // We should get EngineReady? Not necessarily (already emitted). + // Trigger pause (will error because not initialized), and we should receive it. engine.pause_sync().expect("pause_sync send command"); - let ev = expect_error_event(&mut rx, "pause_sync_failed").await; - assert!( - matches!(ev, WalletEvent::Error { .. }), - "expected Error, got {ev:?}" - ); + loop { + let ev = recv_timeout(&rx, Duration::from_secs(2)); + if let WalletEvent::Error { code, .. } = ev { + assert_eq!(code, "pause_sync_failed"); + break; + } + } } - // TODO: Do not use env vars. Use the infra repo somehow. - // - // ZINGO_TEST_SERVER_URI="https://..." \ - // ZINGO_TEST_CHAIN_HINT="test" \ - // ZINGO_TEST_PERF="Medium" \ - // ZINGO_TEST_MINCONF="1" \ - // cargo test -p ffi real_sync_smoke -- --ignored --nocapture - // - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] - #[ignore] - async fn real_sync_smoke() { - let server_uri = std::env::var("ZINGO_TEST_SERVER_URI").expect("ZINGO_TEST_SERVER_URI"); - let chain_hint = std::env::var("ZINGO_TEST_CHAIN_HINT").unwrap_or_else(|_| "test".into()); - let perf = std::env::var("ZINGO_TEST_PERF").unwrap_or_else(|_| "Medium".into()); - let minconf: u32 = std::env::var("ZINGO_TEST_MINCONF") - .unwrap_or_else(|_| "1".into()) - .parse() - .expect("ZINGO_TEST_MINCONF must be u32"); + /// Requires network up + #[test] + fn real_sync_smoke() { + let server_uri = "http://localhost:20956".to_string(); + let chain = Chain::Regtest; + let perf = Performance::High; + let minconf: u32 = 1; let engine = WalletEngine::new().expect("engine new"); - let (tx, mut rx) = mpsc::unbounded_channel(); + let (tx, rx) = std_mpsc::channel(); engine .set_listener(Box::new(CapturingListener { tx })) .expect("set_listener"); - expect_engine_ready(&mut rx).await; + // Expect EngineReady + let _ = recv_timeout(&rx, Duration::from_secs(2)); engine - .init_new(server_uri, chain_hint, perf, minconf) + .init_new(server_uri, chain, perf, minconf) .expect("init_new"); engine.start_sync().expect("start_sync"); - // Wait until SyncFinished or timeout. - let deadline = tokio::time::Instant::now() + Duration::from_secs(90); + let deadline = std::time::Instant::now() + Duration::from_secs(90); loop { - let now = tokio::time::Instant::now(); - if now >= deadline { + if std::time::Instant::now() > deadline { panic!("timeout waiting for SyncFinished"); } - let ev = recv_with_timeout(&mut rx, deadline - now).await; + + let ev = recv_timeout(&rx, Duration::from_secs(5)); match ev { WalletEvent::SyncFinished => break, WalletEvent::Error { code, message } => { @@ -800,6 +783,264 @@ mod test { } let bal = engine.get_balance_snapshot().expect("balance snapshot"); - println!("balance after sync: {bal:?}"); + eprintln!("balance after sync: {bal:?}"); + } + + /// Real sync smoke test (requires a running regtest lightwalletd at the URI). + /// Run manually: + /// cargo test -p ffi real_sync_progress_smoke -- --ignored --nocapture + #[test] + fn real_sync_progress_smoke() { + let server_uri = "http://localhost:20956".to_string(); + let chain = Chain::Regtest; + let perf = Performance::High; + let minconf: u32 = 1; + + let engine = WalletEngine::new().expect("engine new"); + + let (tx, rx) = std_mpsc::channel(); + engine + .set_listener(Box::new(CapturingListener { tx })) + .expect("set_listener"); + + // Expect EngineReady + let _ = recv_timeout(&rx, Duration::from_secs(2)); + + engine + .init_new(server_uri, chain, perf, minconf) + .expect("init_new"); + + engine.start_sync().expect("start_sync"); + + let deadline = std::time::Instant::now() + Duration::from_secs(120); + + let mut saw_started = false; + let mut saw_progress = false; + let mut last_percent: f32 = 0.0; + + loop { + if std::time::Instant::now() > deadline { + panic!( + "timeout waiting for SyncFinished (started={saw_started}, progress={saw_progress})" + ); + } + + let ev = recv_timeout(&rx, Duration::from_secs(5)); + match ev { + WalletEvent::SyncStarted => { + saw_started = true; + eprintln!("[sync] started"); + } + + WalletEvent::SyncProgress { + wallet_height, + network_height, + percent, + } => { + // Require at least one progress tick. + saw_progress = true; + + if percent + 0.05 < last_percent { + eprintln!( + "[sync] WARNING: percent regressed: {last_percent:.3} -> {percent:.3}" + ); + } + last_percent = percent; + + eprintln!( + "[sync] progress: wallet_height={wallet_height} network_height={network_height} percent={percent:.3}" + ); + } + + WalletEvent::BalanceChanged(bal) => { + eprintln!("[sync] balance changed: {bal:?}"); + } + + WalletEvent::SyncPaused => { + panic!("sync paused unexpectedly"); + } + + WalletEvent::SyncFinished => { + eprintln!("[sync] finished"); + break; + } + + WalletEvent::Error { code, message } => { + panic!("sync error: {code} {message}"); + } + + other => { + eprintln!("[sync] other event: {other:?}"); + } + } + } + + assert!(saw_started, "never saw SyncStarted"); + assert!(saw_progress, "never saw SyncProgress"); + + let bal = engine.get_balance_snapshot().expect("balance snapshot"); + eprintln!("balance after sync: {bal:?}"); + } + + /// Smoke test: sync to tip, then restart sync every 10 seconds until we + /// observe >= 5 distinct *new* network heights (via SyncProgress) beyond + /// the initial tip. + /// + /// This does NOT query latest block height externally. + /// It relies purely on SyncProgress events emitted during each sync run. + #[test] + fn real_sync_observe_5_new_block_heights_smoke() { + use std::collections::BTreeSet; + use std::sync::mpsc as std_mpsc; + use std::time::{Duration, Instant}; + + let server_uri = "http://localhost:18892".to_string(); + let chain = Chain::Regtest; + let perf = Performance::High; + let minconf: u32 = 1; + + let engine = WalletEngine::new().expect("engine new"); + + let (tx, rx) = std_mpsc::channel(); + engine + .set_listener(Box::new(CapturingListener { tx })) + .expect("set_listener"); + + // Best-effort wait for EngineReady. + let _ = recv_timeout(&rx, Duration::from_secs(2)); + + engine + .init_new(server_uri, chain, perf, minconf) + .expect("init_new"); + + // TODO: refactor. run a sync to SyncFinished and return the last seen (wh, nh) from progress. + fn sync_to_finished_and_get_last_progress( + engine: &WalletEngine, + rx: &std_mpsc::Receiver, + timeout: Duration, + label: &str, + ) -> (u32, u32) { + engine.start_sync().expect("start_sync"); + eprintln!("[{label}] started sync"); + + let deadline = Instant::now() + timeout; + let mut last_progress: Option<(u32, u32)> = None; + + loop { + if Instant::now() > deadline { + panic!("[{label}] timeout waiting for SyncFinished"); + } + + let ev = recv_timeout(rx, Duration::from_secs(5)); + match ev { + WalletEvent::SyncProgress { + wallet_height, + network_height, + percent, + } => { + last_progress = Some((wallet_height, network_height)); + eprintln!( + "[{label}] progress: wh={wallet_height} nh={network_height} pct={percent:.3}" + ); + } + WalletEvent::SyncFinished => { + let (wh, nh) = last_progress.unwrap_or((0, 0)); + eprintln!("[{label}] SyncFinished (last wh={wh} nh={nh})"); + return (wh, nh); + } + WalletEvent::Error { code, message } => { + panic!("[{label}] sync error: {code} {message}"); + } + _ => {} + } + } + } + + let per_sync_timeout = Duration::from_secs(90); + let overall_deadline = Instant::now() + Duration::from_secs(10 * 60); // 10 minutes + + let (_wh0, nh0) = + sync_to_finished_and_get_last_progress(&engine, &rx, per_sync_timeout, "initial"); + if nh0 == 0 { + eprintln!("[follow-test] warning: initial nh0=0 (did you connect to lightwalletd?)"); + } + eprintln!("[follow-test] baseline nh0={nh0}"); + + let mut observed_new_heights: BTreeSet = BTreeSet::new(); + + while observed_new_heights.len() < 5 { + if Instant::now() > overall_deadline { + panic!( + "timeout waiting for >= 5 distinct new network heights > nh0={nh0}. saw {}: {:?}", + observed_new_heights.len(), + observed_new_heights + ); + } + + // Restart sync every 10 seconds (mining frequency unknown). TODO: make this better somehow + std::thread::sleep(Duration::from_secs(10)); + engine.start_sync().expect("start_sync (restart)"); + eprintln!( + "[follow-test] restart sync attempt; currently have {}/5 heights", + observed_new_heights.len() + ); + + // For this run, we listen for progress (and/or finish). Any progress nh > nh0 counts. + let run_deadline = Instant::now() + per_sync_timeout; + loop { + if Instant::now() > run_deadline { + eprintln!("[follow-test] restart run timed out; will try again"); + break; + } + + let ev = recv_timeout(&rx, Duration::from_secs(5)); + match ev { + WalletEvent::SyncProgress { + wallet_height, + network_height, + percent, + } => { + if network_height > nh0 { + let inserted = observed_new_heights.insert(network_height); + if inserted { + eprintln!( + "[follow-test] NEW network_height observed: nh={network_height} (wh={wallet_height} pct={percent:.3}) distinct={}/5", + observed_new_heights.len() + ); + } else { + eprintln!( + "[follow-test] progress: wh={wallet_height} nh={network_height} pct={percent:.3} distinct={}/5", + observed_new_heights.len() + ); + } + } else { + eprintln!( + "[follow-test] progress (no new blocks): wh={wallet_height} nh={network_height} pct={percent:.3}" + ); + } + + if observed_new_heights.len() >= 5 { + break; + } + } + WalletEvent::SyncFinished => { + eprintln!("[follow-test] SyncFinished (restart run)"); + break; + } + WalletEvent::Error { code, message } => { + panic!("[follow-test] sync error while observing: {code} {message}"); + } + _ => {} + } + } + } + + eprintln!( + "[follow-test] PASS: observed >=5 distinct new network heights beyond nh0={nh0}: {:?}", + observed_new_heights + ); + + let bal = engine.get_balance_snapshot().expect("balance snapshot"); + eprintln!("[follow-test] balance after follow: {bal:?}"); } } From f6bad5153fb951ede05a79281f8a61793fc5b8c5 Mon Sep 17 00:00:00 2001 From: dorianvp Date: Fri, 13 Feb 2026 16:45:38 -0300 Subject: [PATCH 04/15] chore: docs and TODOs --- .gitignore | 3 + ffi/rust/src/error.rs | 11 +++ ffi/rust/src/lib.rs | 206 +++++++++++++++++++++++++++++++++++------- 3 files changed, 185 insertions(+), 35 deletions(-) create mode 100644 ffi/rust/src/error.rs diff --git a/.gitignore b/.gitignore index 0f75e9bda..11d27c8c8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ zingolib/proptest-regressions test_binaries/bins/* libtonode-tests/tests/chain_generics.proptest-regressions libtonode-tests/store_all_checkpoints_test + +.DS_Store +*.dat diff --git a/ffi/rust/src/error.rs b/ffi/rust/src/error.rs new file mode 100644 index 000000000..f21c1e7a8 --- /dev/null +++ b/ffi/rust/src/error.rs @@ -0,0 +1,11 @@ +#[derive(Debug, thiserror::Error, uniffi::Error)] +pub enum WalletError { + #[error("Command queue closed")] + CommandQueueClosed, + #[error("Listener lock poisoned")] + ListenerLockPoisoned, + #[error("Wallet not initialized")] + NotInitialized, + #[error("Internal error: {0}")] + Internal(String), +} diff --git a/ffi/rust/src/lib.rs b/ffi/rust/src/lib.rs index 3ab91a7d7..5b8da2635 100644 --- a/ffi/rust/src/lib.rs +++ b/ffi/rust/src/lib.rs @@ -1,3 +1,5 @@ +pub mod error; + use std::{ num::NonZeroU32, panic::{self, AssertUnwindSafe}, @@ -20,19 +22,9 @@ use zingolib::{ wallet::{LightWallet, WalletBase, WalletSettings, balance::AccountBalance}, }; -uniffi::setup_scaffolding!(); +use crate::error::WalletError; -#[derive(Debug, thiserror::Error, uniffi::Error)] -pub enum WalletError { - #[error("Command queue closed")] - CommandQueueClosed, - #[error("Listener lock poisoned")] - ListenerLockPoisoned, - #[error("Wallet not initialized")] - NotInitialized, - #[error("Internal error: {0}")] - Internal(String), -} +uniffi::setup_scaffolding!(); #[derive(Clone, Copy, Debug, uniffi::Enum)] pub enum Chain { @@ -120,12 +112,12 @@ fn balance_snapshot_from_balance(b: &AccountBalance) -> BalanceSnapshot { } fn construct_config( - server_uri: String, + indexer_uri: String, chain: Chain, perf: Performance, min_confirmations: u32, ) -> Result<(ZingoConfig, http::Uri), WalletError> { - let lightwalletd_uri = construct_lightwalletd_uri(Some(server_uri)); + let lightwalletd_uri = construct_lightwalletd_uri(Some(indexer_uri)); let min_conf = NonZeroU32::try_from(min_confirmations) .map_err(|_| WalletError::Internal("min_confirmations must be >= 1".into()))?; @@ -165,7 +157,7 @@ fn emit(inner: &EngineInner, event: WalletEvent) { enum Command { InitNew { - server_uri: String, + indexer_uri: String, chain: Chain, perf: Performance, minconf: u32, @@ -174,7 +166,7 @@ enum Command { InitFromSeed { seed_phrase: String, birthday: u32, - server_uri: String, + indexer_uri: String, chain: Chain, perf: Performance, minconf: u32, @@ -203,6 +195,19 @@ fn create_engine_runtime() -> tokio::runtime::Runtime { #[uniffi::export] impl WalletEngine { + /// Creates a new [`WalletEngine`] and starts the internal engine thread. + /// + /// This constructor: + /// - Allocates a command queue used to communicate with the engine thread. + /// - Spawns a dedicated OS thread that owns a Tokio runtime and all async wallet state, through the [`LightClient`]. + /// - Emits [`WalletEvent::EngineReady`] once the engine thread is running. + /// + /// ## Threading / FFI design + /// All UniFFI-exposed methods on [`WalletEngine`] are *synchronous* and safe to call from + /// Swift/Kotlin. Any async work is executed on the engine thread. + /// + /// ## Errors + /// Returns [`WalletError`] if the engine cannot be created. #[uniffi::constructor] pub fn new() -> Result { let (cmd_tx, mut cmd_rx) = mpsc::channel::(64); @@ -219,11 +224,10 @@ impl WalletEngine { rt.block_on(async move { emit(&inner_for_task, WalletEvent::EngineReady); - // Engine-owned state + // TODO: THIS NEEDS TO BE BEHIND AN ASYNC LOCK. With the current setup, sync will block the thread. let mut lightclient: Option = None; - let mut server_uri: Option = None; + let mut indexer_uri: Option = None; - // Keep last emitted balance snapshot let mut last_balance: Option = None; let mut syncing = false; @@ -233,7 +237,7 @@ impl WalletEngine { todo!() } Command::InitNew { - server_uri: srv, + indexer_uri: srv, chain, perf, minconf, @@ -258,7 +262,7 @@ impl WalletEngine { })?; lightclient = Some(lc); - server_uri = Some(lw_uri); + indexer_uri = Some(lw_uri); last_balance = None; Ok(()) }) @@ -270,7 +274,7 @@ impl WalletEngine { Command::InitFromSeed { seed_phrase, birthday, - server_uri: srv, + indexer_uri: srv, chain, perf, minconf, @@ -301,7 +305,7 @@ impl WalletEngine { })?; lightclient = Some(lc); - server_uri = Some(lw_uri); + indexer_uri = Some(lw_uri); last_balance = None; Ok(()) }) @@ -398,8 +402,8 @@ impl WalletEngine { .unwrap_or(0) }; - // Compute network height (best effort from last known server_uri) - let nh = match server_uri.as_ref() { + // Compute network height (best effort from last known indexer_uri) + let nh = match indexer_uri.as_ref() { Some(uri) if *uri != http::Uri::default() => { match zingolib::grpc_connector::get_latest_block( uri.clone(), @@ -511,6 +515,18 @@ impl WalletEngine { Ok(Self { inner }) } + /// Installs a listener that receives asynchronous [`WalletEvent`] callbacks. + /// + /// The listener is invoked from the engine thread. Implementations must be: + /// - thread-safe (`Send + Sync`) + /// - fast / non-blocking (heavy work should be offloaded by the caller) + /// + /// If the listener panics, the engine catches the panic to avoid crashing the engine thread. + /// + /// Replaces any previously installed listener. + /// + /// ## Errors + /// Returns [`WalletError::ListenerLockPoisoned`] if the listener mutex is poisoned. pub fn set_listener(&self, listener: Box) -> Result<(), WalletError> { let mut guard = self .inner @@ -521,6 +537,13 @@ impl WalletEngine { Ok(()) } + /// Clears the currently installed listener, if any. + /// + /// After calling this, no further [`WalletEvent`] callbacks will be delivered until a new + /// listener is set via [`WalletEngine::set_listener`]. + /// + /// ## Errors + /// Returns [`WalletError::ListenerLockPoisoned`] if the listener mutex is poisoned. pub fn clear_listener(&self) -> Result<(), WalletError> { let mut guard = self .inner @@ -531,9 +554,31 @@ impl WalletEngine { Ok(()) } + /// Initializes a brand-new wallet on the engine thread. + /// + /// This is the entrypoint for new wallets. It: + /// - Builds a [`ZingoConfig`] from the provided parameters. + /// - Queries the indexer for the latest block height to derive a conservative birthday. + /// - Constructs a new [`LightClient`], replacing any previously loaded wallet. + /// + /// This method is **blocking** by design. The async work is performed on the + /// engine thread and the result is returned via a oneshot reply channel. + /// + /// ## Parameters + /// - `indexer_uri`: zainod/lightwalletd URI, e.g. `http://localhost:9067` + /// - `chain`: chain selection (mainnet/testnet/regtest) + /// - `perf`: sync performance preset + /// - `minconf`: minimum confirmations for spendable funds. Must be >= 1. + /// + /// ## Events + /// Does not automatically start syncing. Call [`WalletEngine::start_sync`] to begin a sync round. + /// + /// ## Errors + /// - [`WalletError::CommandQueueClosed`] if the engine thread has exited. + /// - [`WalletError::Internal`] on config/build errors or indexer gRPC failures. pub fn init_new( &self, - server_uri: String, + indexer_uri: String, chain: Chain, perf: Performance, minconf: u32, @@ -542,7 +587,7 @@ impl WalletEngine { self.inner .cmd_tx .blocking_send(Command::InitNew { - server_uri, + indexer_uri, chain, perf, minconf, @@ -555,11 +600,36 @@ impl WalletEngine { .map_err(|_| WalletError::CommandQueueClosed)? } + /// Initializes a wallet from a seed phrase and explicit birthday height. + /// + /// This is the entrypoint for restoring from seed. It: + /// - Builds a [`ZingoConfig`] from the provided parameters. + /// - Parses the BIP39 mnemonic from `seed_phrase`. + /// - Constructs a [`LightWallet`] using the provided `birthday`. + /// - Creates a [`LightClient`] from that wallet, replacing any previously loaded wallet. + /// + /// This method is **blocking** by design (FFI-friendly). The async work is performed on the + /// engine thread and the result is returned via a oneshot reply channel. + /// + /// ## Parameters + /// - `seed_phrase`: BIP39 mnemonic words separated by spaces + /// - `birthday`: wallet birthday (starting scan height) + /// - `indexer_uri`: lightwalletd URI + /// - `chain`: chain selection (mainnet/testnet/regtest) + /// - `perf`: sync performance preset + /// - `minconf`: minimum confirmations for spendable funds. Must be >= 1. + /// + /// ## Events + /// Does not automatically start syncing. Call [`WalletEngine::start_sync`] to begin a sync round. + /// + /// ## Errors + /// - [`WalletError::CommandQueueClosed`] if the engine thread has exited. + /// - [`WalletError::Internal`] on config/mnemonic/wallet construction errors. pub fn init_from_seed( &self, seed_phrase: String, birthday: u32, - server_uri: String, + indexer_uri: String, chain: Chain, perf: Performance, minconf: u32, @@ -570,7 +640,7 @@ impl WalletEngine { .blocking_send(Command::InitFromSeed { seed_phrase, birthday, - server_uri, + indexer_uri, chain, perf, minconf, @@ -583,6 +653,18 @@ impl WalletEngine { .map_err(|_| WalletError::CommandQueueClosed)? } + /// Returns a snapshot of the wallet balance for Account 0. + /// + /// The returned [`BalanceSnapshot`] is a simplified, FFI-stable view derived from the + /// underlying zingolib [`AccountBalance`] type. + /// + /// This method is **blocking**. The balance query runs on the engine thread and the result + /// is returned via a oneshot reply channel. + /// + /// ## Errors + /// - [`WalletError::NotInitialized`] if no wallet has been initialized. + /// - [`WalletError::CommandQueueClosed`] if the engine thread has exited. + /// - [`WalletError::Internal`] if the underlying balance query fails. pub fn get_balance_snapshot(&self) -> Result { let (reply_tx, reply_rx) = oneshot::channel(); self.inner @@ -595,6 +677,19 @@ impl WalletEngine { .map_err(|_| WalletError::CommandQueueClosed)? } + /// Returns the latest known network height from the configured indexer. + /// + /// This is a gRPC call to the indexer (`get_latest_block`) and is useful for: + /// - UI display (“current tip”) + /// - tests that need to observe tip movement independently of sync progress + /// + /// This method is **blocking**. The gRPC call runs on the engine thread and the result is returned + /// via a oneshot reply channel. + /// + /// ## Errors + /// - [`WalletError::NotInitialized`] if no indexer has been configured yet. + /// - [`WalletError::CommandQueueClosed`] if the engine thread has exited. + /// - [`WalletError::Internal`] if the indexer gRPC fails. pub fn get_network_height(&self) -> Result { let (reply_tx, reply_rx) = oneshot::channel(); self.inner @@ -607,6 +702,26 @@ impl WalletEngine { .map_err(|_| WalletError::CommandQueueClosed)? } + /// Starts a **single manual sync round**. + /// + /// The sync round runs on the engine thread and emits events: + /// - [`WalletEvent::SyncStarted`] immediately when accepted + /// - repeated [`WalletEvent::SyncProgress`] updates while syncing + /// - optional [`WalletEvent::BalanceChanged`] updates when balance changes + /// - [`WalletEvent::SyncFinished`] once the sync completes successfully + /// - [`WalletEvent::Error`] if the sync fails + /// + /// ## Manual model + /// This method performs **one** round per invocation. It does not “follow” the chain forever. + /// If the network tip advances later and you want to catch up again, call `start_sync()` again. + /// + /// ## Reentrancy + /// If a sync is already running, additional `start_sync()` calls are ignored. + /// + /// ## Errors + /// Returns [`WalletError::CommandQueueClosed`] if the engine thread has exited. + /// If the wallet is not initialized, an async [`WalletEvent::Error`] is emitted with + /// `code="start_sync_failed"`. pub fn start_sync(&self) -> Result<(), WalletError> { self.inner .cmd_tx @@ -614,6 +729,16 @@ impl WalletEngine { .map_err(|_| WalletError::CommandQueueClosed) } + /// Requests that an in-progress sync pause. + /// + /// This calls into zingolib's pause mechanism. If successful, the engine emits + /// [`WalletEvent::SyncPaused`]. + /// + /// Note: pausing is best-effort. If no wallet exists, an async [`WalletEvent::Error`] is emitted + /// with `code="pause_sync_failed"`. + /// + /// ## Errors + /// Returns [`WalletError::CommandQueueClosed`] if the engine thread has exited. pub fn pause_sync(&self) -> Result<(), WalletError> { self.inner .cmd_tx @@ -621,6 +746,17 @@ impl WalletEngine { .map_err(|_| WalletError::CommandQueueClosed) } + /// Shuts down the engine thread. + /// + /// This sends a shutdown command to the engine loop. After shutdown: + /// - all subsequent method calls that require the engine thread will typically fail with + /// [`WalletError::CommandQueueClosed`] + /// - no further [`WalletEvent`] callbacks will be delivered + /// + /// Shutdown is best-effort; the command is queued if possible. + /// + /// ## Errors + /// Returns [`WalletError::CommandQueueClosed`] if the command queue is already closed. pub fn shutdown(&self) -> Result<(), WalletError> { self.inner .cmd_tx @@ -745,7 +881,7 @@ mod tests { /// Requires network up #[test] fn real_sync_smoke() { - let server_uri = "http://localhost:20956".to_string(); + let indexer_uri = "http://localhost:20956".to_string(); let chain = Chain::Regtest; let perf = Performance::High; let minconf: u32 = 1; @@ -761,7 +897,7 @@ mod tests { let _ = recv_timeout(&rx, Duration::from_secs(2)); engine - .init_new(server_uri, chain, perf, minconf) + .init_new(indexer_uri, chain, perf, minconf) .expect("init_new"); engine.start_sync().expect("start_sync"); @@ -791,7 +927,7 @@ mod tests { /// cargo test -p ffi real_sync_progress_smoke -- --ignored --nocapture #[test] fn real_sync_progress_smoke() { - let server_uri = "http://localhost:20956".to_string(); + let indexer_uri = "http://localhost:20956".to_string(); let chain = Chain::Regtest; let perf = Performance::High; let minconf: u32 = 1; @@ -807,7 +943,7 @@ mod tests { let _ = recv_timeout(&rx, Duration::from_secs(2)); engine - .init_new(server_uri, chain, perf, minconf) + .init_new(indexer_uri, chain, perf, minconf) .expect("init_new"); engine.start_sync().expect("start_sync"); @@ -894,7 +1030,7 @@ mod tests { use std::sync::mpsc as std_mpsc; use std::time::{Duration, Instant}; - let server_uri = "http://localhost:18892".to_string(); + let indexer_uri = "http://localhost:18892".to_string(); let chain = Chain::Regtest; let perf = Performance::High; let minconf: u32 = 1; @@ -910,7 +1046,7 @@ mod tests { let _ = recv_timeout(&rx, Duration::from_secs(2)); engine - .init_new(server_uri, chain, perf, minconf) + .init_new(indexer_uri, chain, perf, minconf) .expect("init_new"); // TODO: refactor. run a sync to SyncFinished and return the last seen (wh, nh) from progress. From dbd8167d8c50bebb8d9f69986ac63469df68cb65 Mon Sep 17 00:00:00 2001 From: dorianvp Date: Fri, 13 Feb 2026 18:15:58 -0300 Subject: [PATCH 05/15] chore: untrack changes --- Cargo.lock | 2 +- ffi/ios/WalletModule/Generated/ffi.swift | 1118 ----------------- ffi/ios/WalletModule/Generated/ffiFFI.h | 627 --------- .../WalletModule/Generated/ffiFFI.modulemap | 7 - ffi/ios/WalletModule/WalletModule.podspec | 17 - ffi/ios/WalletSDK/.gitignore | 3 - .../Binaries/WalletFFI.xcframework/Info.plist | 43 - ffi/ios/WalletSDK/Package.swift | 37 - .../Sources/WalletSDK/Generated/ffi.swift | 1118 ----------------- .../Sources/WalletSDK/Generated/ffiFFI.h | 627 --------- .../WalletSDK/Generated/ffiFFI.modulemap | 7 - .../Sources/WalletSDK/WalletSDK.swift | 80 -- .../Sources/WalletSDKSmoke/main.swift | 22 - .../WalletSDK/Sources/ffiFFI/include/ffiFFI.h | 627 --------- .../WalletSDK/Sources/ffiFFI/module.modulemap | 7 - .../Tests/WalletSDKTests/WalletSDKTests.swift | 19 - 16 files changed, 1 insertion(+), 4360 deletions(-) delete mode 100644 ffi/ios/WalletModule/Generated/ffi.swift delete mode 100644 ffi/ios/WalletModule/Generated/ffiFFI.h delete mode 100644 ffi/ios/WalletModule/Generated/ffiFFI.modulemap delete mode 100644 ffi/ios/WalletModule/WalletModule.podspec delete mode 100644 ffi/ios/WalletSDK/.gitignore delete mode 100644 ffi/ios/WalletSDK/Binaries/WalletFFI.xcframework/Info.plist delete mode 100644 ffi/ios/WalletSDK/Package.swift delete mode 100644 ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffi.swift delete mode 100644 ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.h delete mode 100644 ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.modulemap delete mode 100644 ffi/ios/WalletSDK/Sources/WalletSDK/WalletSDK.swift delete mode 100644 ffi/ios/WalletSDK/Sources/WalletSDKSmoke/main.swift delete mode 100644 ffi/ios/WalletSDK/Sources/ffiFFI/include/ffiFFI.h delete mode 100644 ffi/ios/WalletSDK/Sources/ffiFFI/module.modulemap delete mode 100644 ffi/ios/WalletSDK/Tests/WalletSDKTests/WalletSDKTests.swift diff --git a/Cargo.lock b/Cargo.lock index b3b21e059..bf0bad39d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2145,7 +2145,7 @@ dependencies = [ "tokio", "uniffi", "zcash_primitives", - "zingo_common_components", + "zingo_common_components 0.2.0 (git+https://github.com/zingolabs/zingo-common.git)", "zingolib", ] diff --git a/ffi/ios/WalletModule/Generated/ffi.swift b/ffi/ios/WalletModule/Generated/ffi.swift deleted file mode 100644 index eb1827cfa..000000000 --- a/ffi/ios/WalletModule/Generated/ffi.swift +++ /dev/null @@ -1,1118 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! - -// swiftlint:disable all -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(ffiFFI) -import ffiFFI -#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 empty() -> RustBuffer { - RustBuffer(capacity: 0, len:0, data: nil) - } - - static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { - try! rustCall { ffi_ffi_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_ffi_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 library of its own. - -fileprivate extension Data { - init(rustBuffer: RustBuffer) { - self.init( - bytesNoCopy: rustBuffer.data!, - count: Int(rustBuffer.len), - deallocator: .none - ) - } -} - -// Define reader functionality. Normally this would be defined in a class or -// struct, but we use standalone functions instead in order to make external -// types work. -// -// With external types, one swift source file needs to be able to call the read -// method on another source file's FfiConverter, but then what visibility -// should Reader have? -// - If Reader is fileprivate, then this means the read() must also -// be fileprivate, which doesn't work with external types. -// - If Reader is internal/public, we'll get compile errors since both source -// files will try define the same type. -// -// Instead, the read() method and these helper functions input a tuple of data - -fileprivate func createReader(data: Data) -> (data: Data, offset: Data.Index) { - (data: data, offset: 0) -} - -// Reads an integer at the current offset, in big-endian order, and advances -// the offset on success. Throws if reading the integer would move the -// offset past the end of the buffer. -fileprivate func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { - let range = reader.offset...size - guard reader.data.count >= range.upperBound else { - throw UniffiInternalError.bufferOverflow - } - if T.self == UInt8.self { - let value = reader.data[reader.offset] - reader.offset += 1 - return value as! T - } - var value: T = 0 - let _ = withUnsafeMutableBytes(of: &value, { reader.data.copyBytes(to: $0, from: range)}) - reader.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 -fileprivate func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> Array { - let range = reader.offset..<(reader.offset+count) - guard reader.data.count >= range.upperBound else { - throw UniffiInternalError.bufferOverflow - } - var value = [UInt8](repeating: 0, count: count) - value.withUnsafeMutableBufferPointer({ buffer in - reader.data.copyBytes(to: buffer, from: range) - }) - reader.offset = range.upperBound - return value -} - -// Reads a float at the current offset. -fileprivate func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { - return Float(bitPattern: try readInt(&reader)) -} - -// Reads a float at the current offset. -fileprivate func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { - return Double(bitPattern: try readInt(&reader)) -} - -// Indicates if the offset has reached the end of the buffer. -fileprivate func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { - return reader.offset < reader.data.count -} - -// Define writer functionality. Normally this would be defined in a class or -// struct, but we use standalone functions instead in order to make external -// types work. See the above discussion on Readers for details. - -fileprivate func createWriter() -> [UInt8] { - return [] -} - -fileprivate func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { - writer.append(contentsOf: byteArr) -} - -// Writes an integer in big-endian order. -// -// Warning: make sure what you are trying to write -// is in the correct type! -fileprivate func writeInt(_ writer: inout [UInt8], _ value: T) { - var value = value.bigEndian - withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } -} - -fileprivate func writeFloat(_ writer: inout [UInt8], _ value: Float) { - writeInt(&writer, value.bitPattern) -} - -fileprivate func writeDouble(_ writer: inout [UInt8], _ value: Double) { - writeInt(&writer, value.bitPattern) -} - -// Protocol for types that transfer other types across the FFI. This is -// analogous to the Rust trait of the same name. -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: inout (data: Data, offset: Data.Index)) throws -> SwiftType - static func write(_ value: SwiftType, into buf: inout [UInt8]) -} - -// Types conforming to `Primitive` pass themselves directly over the FFI. -fileprivate protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType { } - -extension FfiConverterPrimitive { -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public static func lift(_ value: FfiType) throws -> SwiftType { - return value - } - -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public 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 { -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public static func lift(_ buf: RustBuffer) throws -> SwiftType { - var reader = createReader(data: Data(rustBuffer: buf)) - let value = try read(from: &reader) - if hasRemaining(reader) { - throw UniffiInternalError.incompleteData - } - buf.deallocate() - return value - } - -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public static func lower(_ value: SwiftType) -> RustBuffer { - var writer = createWriter() - write(value, into: &writer) - return RustBuffer(bytes: writer) - } -} -// 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 extension NSLock { - func withLock(f: () throws -> T) rethrows -> T { - self.lock() - defer { self.unlock() } - return try f() - } -} - -fileprivate let CALL_SUCCESS: Int8 = 0 -fileprivate let CALL_ERROR: Int8 = 1 -fileprivate let CALL_UNEXPECTED_ERROR: Int8 = 2 -fileprivate let CALL_CANCELLED: Int8 = 3 - -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 { - let neverThrow: ((RustBuffer) throws -> Never)? = nil - return try makeRustCall(callback, errorHandler: neverThrow) -} - -private func rustCallWithError( - _ errorHandler: @escaping (RustBuffer) throws -> E, - _ callback: (UnsafeMutablePointer) -> T) throws -> T { - try makeRustCall(callback, errorHandler: errorHandler) -} - -private func makeRustCall( - _ callback: (UnsafeMutablePointer) -> T, - errorHandler: ((RustBuffer) throws -> E)? -) throws -> T { - uniffiEnsureFfiInitialized() - var callStatus = RustCallStatus.init() - let returnedVal = callback(&callStatus) - try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) - return returnedVal -} - -private func uniffiCheckCallStatus( - callStatus: RustCallStatus, - errorHandler: ((RustBuffer) throws -> E)? -) throws { - switch callStatus.code { - case CALL_SUCCESS: - return - - case CALL_ERROR: - if let errorHandler = errorHandler { - throw try errorHandler(callStatus.errorBuf) - } else { - callStatus.errorBuf.deallocate() - throw UniffiInternalError.unexpectedRustCallError - } - - case CALL_UNEXPECTED_ERROR: - // 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") - } - - case CALL_CANCELLED: - fatalError("Cancellation not supported yet") - - default: - throw UniffiInternalError.unexpectedRustCallStatusCode - } -} - -private func uniffiTraitInterfaceCall( - callStatus: UnsafeMutablePointer, - makeCall: () throws -> T, - writeReturn: (T) -> () -) { - do { - try writeReturn(makeCall()) - } catch let error { - callStatus.pointee.code = CALL_UNEXPECTED_ERROR - callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error)) - } -} - -private func uniffiTraitInterfaceCallWithError( - callStatus: UnsafeMutablePointer, - makeCall: () throws -> T, - writeReturn: (T) -> (), - lowerError: (E) -> RustBuffer -) { - do { - try writeReturn(makeCall()) - } catch let error as E { - callStatus.pointee.code = CALL_ERROR - callStatus.pointee.errorBuf = lowerError(error) - } catch { - callStatus.pointee.code = CALL_UNEXPECTED_ERROR - callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error)) - } -} -// Initial value and increment amount for handles. -// These ensure that SWIFT handles always have the lowest bit set -fileprivate let UNIFFI_HANDLEMAP_INITIAL: UInt64 = 1 -fileprivate let UNIFFI_HANDLEMAP_DELTA: UInt64 = 2 - -fileprivate final class UniffiHandleMap: @unchecked Sendable { - // All mutation happens with this lock held, which is why we implement @unchecked Sendable. - private let lock = NSLock() - private var map: [UInt64: T] = [:] - private var currentHandle: UInt64 = UNIFFI_HANDLEMAP_INITIAL - - func insert(obj: T) -> UInt64 { - lock.withLock { - return doInsert(obj) - } - } - - // Low-level insert function, this assumes `lock` is held. - private func doInsert(_ obj: T) -> UInt64 { - let handle = currentHandle - currentHandle += UNIFFI_HANDLEMAP_DELTA - map[handle] = obj - return handle - } - - func get(handle: UInt64) throws -> T { - try lock.withLock { - guard let obj = map[handle] else { - throw UniffiInternalError.unexpectedStaleHandle - } - return obj - } - } - - func clone(handle: UInt64) throws -> UInt64 { - try lock.withLock { - guard let obj = map[handle] else { - throw UniffiInternalError.unexpectedStaleHandle - } - return doInsert(obj) - } - } - - @discardableResult - func remove(handle: UInt64) throws -> T { - try lock.withLock { - guard let obj = map.removeValue(forKey: handle) else { - throw UniffiInternalError.unexpectedStaleHandle - } - return obj - } - } - - var count: Int { - get { - map.count - } - } -} - - -// Public interface members begin here. -// Magic number for the Rust proxy to call using the same mechanism as every other method, -// to free the callback once it's dropped by Rust. -private let IDX_CALLBACK_FREE: Int32 = 0 -// Callback return codes -private let UNIFFI_CALLBACK_SUCCESS: Int32 = 0 -private let UNIFFI_CALLBACK_ERROR: Int32 = 1 -private let UNIFFI_CALLBACK_UNEXPECTED_ERROR: Int32 = 2 - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -fileprivate struct FfiConverterUInt32: FfiConverterPrimitive { - typealias FfiType = UInt32 - typealias SwiftType = UInt32 - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { - return try lift(readInt(&buf)) - } - - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { - writeInt(&buf, lower(value)) - } -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -fileprivate struct FfiConverterFloat: FfiConverterPrimitive { - typealias FfiType = Float - typealias SwiftType = Float - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Float { - return try lift(readFloat(&buf)) - } - - public static func write(_ value: Float, into buf: inout [UInt8]) { - writeFloat(&buf, lower(value)) - } -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -fileprivate struct FfiConverterString: FfiConverter { - typealias SwiftType = String - typealias FfiType = RustBuffer - - public 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)! - } - - public 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) - } - } - } - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { - let len: Int32 = try readInt(&buf) - return String(bytes: try readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! - } - - public static func write(_ value: String, into buf: inout [UInt8]) { - let len = Int32(value.utf8.count) - writeInt(&buf, len) - writeBytes(&buf, value.utf8) - } -} - - - - -public protocol WalletEngineProtocol: AnyObject, Sendable { - - func clearListener() throws - - func getBalanceSnapshot() throws -> BalanceSnapshot - - func pauseSync() throws - - /** - * ✅ UniFFI-friendly callback: Box - */ - func setListener(listener: WalletListener) throws - - func shutdown() throws - - func startSync() throws - -} -open class WalletEngine: WalletEngineProtocol, @unchecked Sendable { - fileprivate let handle: UInt64 - - /// Used to instantiate a [FFIObject] without an actual handle, for fakes in tests, mostly. -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public struct NoHandle { - public init() {} - } - - // 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`. -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - required public init(unsafeFromHandle handle: UInt64) { - self.handle = handle - } - - // This constructor can be used to instantiate a fake object. - // - Parameter noHandle: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - // - // - Warning: - // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing handle the FFI lower functions will crash. -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public init(noHandle: NoHandle) { - self.handle = 0 - } - -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public func uniffiCloneHandle() -> UInt64 { - return try! rustCall { uniffi_ffi_fn_clone_walletengine(self.handle, $0) } - } -public convenience init()throws { - let handle = - try rustCallWithError(FfiConverterTypeWalletError_lift) { - uniffi_ffi_fn_constructor_walletengine_new($0 - ) -} - self.init(unsafeFromHandle: handle) -} - - deinit { - if handle == 0 { - // Mock objects have handle=0 don't try to free them - return - } - - try! rustCall { uniffi_ffi_fn_free_walletengine(handle, $0) } - } - - - - -open func clearListener()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { - uniffi_ffi_fn_method_walletengine_clear_listener( - self.uniffiCloneHandle(),$0 - ) -} -} - -open func getBalanceSnapshot()throws -> BalanceSnapshot { - return try FfiConverterTypeBalanceSnapshot_lift(try rustCallWithError(FfiConverterTypeWalletError_lift) { - uniffi_ffi_fn_method_walletengine_get_balance_snapshot( - self.uniffiCloneHandle(),$0 - ) -}) -} - -open func pauseSync()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { - uniffi_ffi_fn_method_walletengine_pause_sync( - self.uniffiCloneHandle(),$0 - ) -} -} - - /** - * ✅ UniFFI-friendly callback: Box - */ -open func setListener(listener: WalletListener)throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { - uniffi_ffi_fn_method_walletengine_set_listener( - self.uniffiCloneHandle(), - FfiConverterCallbackInterfaceWalletListener_lower(listener),$0 - ) -} -} - -open func shutdown()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { - uniffi_ffi_fn_method_walletengine_shutdown( - self.uniffiCloneHandle(),$0 - ) -} -} - -open func startSync()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { - uniffi_ffi_fn_method_walletengine_start_sync( - self.uniffiCloneHandle(),$0 - ) -} -} - - - -} - - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public struct FfiConverterTypeWalletEngine: FfiConverter { - typealias FfiType = UInt64 - typealias SwiftType = WalletEngine - - public static func lift(_ handle: UInt64) throws -> WalletEngine { - return WalletEngine(unsafeFromHandle: handle) - } - - public static func lower(_ value: WalletEngine) -> UInt64 { - return value.uniffiCloneHandle() - } - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> WalletEngine { - let handle: UInt64 = try readInt(&buf) - return try lift(handle) - } - - public static func write(_ value: WalletEngine, into buf: inout [UInt8]) { - writeInt(&buf, lower(value)) - } -} - - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeWalletEngine_lift(_ handle: UInt64) throws -> WalletEngine { - return try FfiConverterTypeWalletEngine.lift(handle) -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeWalletEngine_lower(_ value: WalletEngine) -> UInt64 { - return FfiConverterTypeWalletEngine.lower(value) -} - - - - -public struct BalanceSnapshot: Equatable, Hashable { - public var confirmed: String - public var total: String - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(confirmed: String, total: String) { - self.confirmed = confirmed - self.total = total - } - - - - -} - -#if compiler(>=6) -extension BalanceSnapshot: Sendable {} -#endif - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public struct FfiConverterTypeBalanceSnapshot: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> BalanceSnapshot { - return - try BalanceSnapshot( - confirmed: FfiConverterString.read(from: &buf), - total: FfiConverterString.read(from: &buf) - ) - } - - public static func write(_ value: BalanceSnapshot, into buf: inout [UInt8]) { - FfiConverterString.write(value.confirmed, into: &buf) - FfiConverterString.write(value.total, into: &buf) - } -} - - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeBalanceSnapshot_lift(_ buf: RustBuffer) throws -> BalanceSnapshot { - return try FfiConverterTypeBalanceSnapshot.lift(buf) -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeBalanceSnapshot_lower(_ value: BalanceSnapshot) -> RustBuffer { - return FfiConverterTypeBalanceSnapshot.lower(value) -} - - -public enum WalletError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { - - - - case CommandQueueClosed - case ListenerLockPoisoned - case Internal(String - ) - - - - - - - public var errorDescription: String? { - String(reflecting: self) - } - -} - -#if compiler(>=6) -extension WalletError: Sendable {} -#endif - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public struct FfiConverterTypeWalletError: FfiConverterRustBuffer { - typealias SwiftType = WalletError - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> WalletError { - let variant: Int32 = try readInt(&buf) - switch variant { - - - - - case 1: return .CommandQueueClosed - case 2: return .ListenerLockPoisoned - case 3: return .Internal( - try FfiConverterString.read(from: &buf) - ) - - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - public static func write(_ value: WalletError, into buf: inout [UInt8]) { - switch value { - - - - - - case .CommandQueueClosed: - writeInt(&buf, Int32(1)) - - - case .ListenerLockPoisoned: - writeInt(&buf, Int32(2)) - - - case let .Internal(v1): - writeInt(&buf, Int32(3)) - FfiConverterString.write(v1, into: &buf) - - } - } -} - - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeWalletError_lift(_ buf: RustBuffer) throws -> WalletError { - return try FfiConverterTypeWalletError.lift(buf) -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeWalletError_lower(_ value: WalletError) -> RustBuffer { - return FfiConverterTypeWalletError.lower(value) -} - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - -public enum WalletEvent: Equatable, Hashable { - - case engineReady - case syncStarted - case syncProgress(walletHeight: UInt32, networkHeight: UInt32, percent: Float - ) - case syncPaused - case syncFinished - case balanceChanged(BalanceSnapshot - ) - case newTransaction(txid: String - ) - case error(code: String, message: String - ) - - - - - -} - -#if compiler(>=6) -extension WalletEvent: Sendable {} -#endif - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public struct FfiConverterTypeWalletEvent: FfiConverterRustBuffer { - typealias SwiftType = WalletEvent - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> WalletEvent { - let variant: Int32 = try readInt(&buf) - switch variant { - - case 1: return .engineReady - - case 2: return .syncStarted - - case 3: return .syncProgress(walletHeight: try FfiConverterUInt32.read(from: &buf), networkHeight: try FfiConverterUInt32.read(from: &buf), percent: try FfiConverterFloat.read(from: &buf) - ) - - case 4: return .syncPaused - - case 5: return .syncFinished - - case 6: return .balanceChanged(try FfiConverterTypeBalanceSnapshot.read(from: &buf) - ) - - case 7: return .newTransaction(txid: try FfiConverterString.read(from: &buf) - ) - - case 8: return .error(code: try FfiConverterString.read(from: &buf), message: try FfiConverterString.read(from: &buf) - ) - - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - public static func write(_ value: WalletEvent, into buf: inout [UInt8]) { - switch value { - - - case .engineReady: - writeInt(&buf, Int32(1)) - - - case .syncStarted: - writeInt(&buf, Int32(2)) - - - case let .syncProgress(walletHeight,networkHeight,percent): - writeInt(&buf, Int32(3)) - FfiConverterUInt32.write(walletHeight, into: &buf) - FfiConverterUInt32.write(networkHeight, into: &buf) - FfiConverterFloat.write(percent, into: &buf) - - - case .syncPaused: - writeInt(&buf, Int32(4)) - - - case .syncFinished: - writeInt(&buf, Int32(5)) - - - case let .balanceChanged(v1): - writeInt(&buf, Int32(6)) - FfiConverterTypeBalanceSnapshot.write(v1, into: &buf) - - - case let .newTransaction(txid): - writeInt(&buf, Int32(7)) - FfiConverterString.write(txid, into: &buf) - - - case let .error(code,message): - writeInt(&buf, Int32(8)) - FfiConverterString.write(code, into: &buf) - FfiConverterString.write(message, into: &buf) - - } - } -} - - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeWalletEvent_lift(_ buf: RustBuffer) throws -> WalletEvent { - return try FfiConverterTypeWalletEvent.lift(buf) -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeWalletEvent_lower(_ value: WalletEvent) -> RustBuffer { - return FfiConverterTypeWalletEvent.lower(value) -} - - - - - -public protocol WalletListener: AnyObject, Sendable { - - func onEvent(event: WalletEvent) - -} - - -// Put the implementation in a struct so we don't pollute the top-level namespace -fileprivate struct UniffiCallbackInterfaceWalletListener { - - // Create the VTable using a series of closures. - // Swift automatically converts these into C callback functions. - // - // This creates 1-element array, since this seems to be the only way to construct a const - // pointer that we can pass to the Rust code. - static let vtable: [UniffiVTableCallbackInterfaceWalletListener] = [UniffiVTableCallbackInterfaceWalletListener( - uniffiFree: { (uniffiHandle: UInt64) -> () in - do { - try FfiConverterCallbackInterfaceWalletListener.handleMap.remove(handle: uniffiHandle) - } catch { - print("Uniffi callback interface WalletListener: handle missing in uniffiFree") - } - }, - uniffiClone: { (uniffiHandle: UInt64) -> UInt64 in - do { - return try FfiConverterCallbackInterfaceWalletListener.handleMap.clone(handle: uniffiHandle) - } catch { - fatalError("Uniffi callback interface WalletListener: handle missing in uniffiClone") - } - }, - onEvent: { ( - uniffiHandle: UInt64, - event: RustBuffer, - uniffiOutReturn: UnsafeMutableRawPointer, - uniffiCallStatus: UnsafeMutablePointer - ) in - let makeCall = { - () throws -> () in - guard let uniffiObj = try? FfiConverterCallbackInterfaceWalletListener.handleMap.get(handle: uniffiHandle) else { - throw UniffiInternalError.unexpectedStaleHandle - } - return uniffiObj.onEvent( - event: try FfiConverterTypeWalletEvent_lift(event) - ) - } - - - let writeReturn = { () } - uniffiTraitInterfaceCall( - callStatus: uniffiCallStatus, - makeCall: makeCall, - writeReturn: writeReturn - ) - } - )] -} - -private func uniffiCallbackInitWalletListener() { - uniffi_ffi_fn_init_callback_vtable_walletlistener(UniffiCallbackInterfaceWalletListener.vtable) -} - -// FfiConverter protocol for callback interfaces -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -fileprivate struct FfiConverterCallbackInterfaceWalletListener { - fileprivate static let handleMap = UniffiHandleMap() -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -extension FfiConverterCallbackInterfaceWalletListener : FfiConverter { - typealias SwiftType = WalletListener - typealias FfiType = UInt64 - -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public static func lift(_ handle: UInt64) throws -> SwiftType { - try handleMap.get(handle: handle) - } - -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { - let handle: UInt64 = try readInt(&buf) - return try lift(handle) - } - -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public static func lower(_ v: SwiftType) -> UInt64 { - return handleMap.insert(obj: v) - } - -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public static func write(_ v: SwiftType, into buf: inout [UInt8]) { - writeInt(&buf, lower(v)) - } -} - - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterCallbackInterfaceWalletListener_lift(_ handle: UInt64) throws -> WalletListener { - return try FfiConverterCallbackInterfaceWalletListener.lift(handle) -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterCallbackInterfaceWalletListener_lower(_ v: WalletListener) -> UInt64 { - return FfiConverterCallbackInterfaceWalletListener.lower(v) -} - -private enum InitializationResult { - case ok - case contractVersionMismatch - case apiChecksumMismatch -} -// Use a global variable to perform the versioning checks. Swift ensures that -// the code inside is only computed once. -private let initializationResult: InitializationResult = { - // Get the bindings contract version from our ComponentInterface - let bindings_contract_version = 30 - // Get the scaffolding contract version by calling the into the dylib - let scaffolding_contract_version = ffi_ffi_uniffi_contract_version() - if bindings_contract_version != scaffolding_contract_version { - return InitializationResult.contractVersionMismatch - } - if (uniffi_ffi_checksum_method_walletengine_clear_listener() != 65358) { - return InitializationResult.apiChecksumMismatch - } - if (uniffi_ffi_checksum_method_walletengine_get_balance_snapshot() != 57923) { - return InitializationResult.apiChecksumMismatch - } - if (uniffi_ffi_checksum_method_walletengine_pause_sync() != 29290) { - return InitializationResult.apiChecksumMismatch - } - if (uniffi_ffi_checksum_method_walletengine_set_listener() != 8699) { - return InitializationResult.apiChecksumMismatch - } - if (uniffi_ffi_checksum_method_walletengine_shutdown() != 23734) { - return InitializationResult.apiChecksumMismatch - } - if (uniffi_ffi_checksum_method_walletengine_start_sync() != 42941) { - return InitializationResult.apiChecksumMismatch - } - if (uniffi_ffi_checksum_constructor_walletengine_new() != 45836) { - return InitializationResult.apiChecksumMismatch - } - if (uniffi_ffi_checksum_method_walletlistener_on_event() != 26795) { - return InitializationResult.apiChecksumMismatch - } - - uniffiCallbackInitWalletListener() - return InitializationResult.ok -}() - -// Make the ensure init function public so that other modules which have external type references to -// our types can call it. -public func uniffiEnsureFfiInitialized() { - switch initializationResult { - case .ok: - break - case .contractVersionMismatch: - fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") - case .apiChecksumMismatch: - fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } -} - -// swiftlint:enable all \ No newline at end of file diff --git a/ffi/ios/WalletModule/Generated/ffiFFI.h b/ffi/ios/WalletModule/Generated/ffiFFI.h deleted file mode 100644 index 59db60430..000000000 --- a/ffi/ios/WalletModule/Generated/ffiFFI.h +++ /dev/null @@ -1,627 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! - -#pragma once - -#include -#include -#include - -// The following structs are used to implement the lowest level -// of the FFI, and thus useful to multiple uniffied crates. -// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H. -#ifdef UNIFFI_SHARED_H - // We also try to prevent mixing versions of shared uniffi header structs. - // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4 - #ifndef UNIFFI_SHARED_HEADER_V4 - #error Combining helper code from multiple versions of uniffi is not supported - #endif // ndef UNIFFI_SHARED_HEADER_V4 -#else -#define UNIFFI_SHARED_H -#define UNIFFI_SHARED_HEADER_V4 -// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ -// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ - -typedef struct RustBuffer -{ - uint64_t capacity; - uint64_t len; - uint8_t *_Nullable data; -} RustBuffer; - -typedef struct ForeignBytes -{ - int32_t len; - const uint8_t *_Nullable data; -} ForeignBytes; - -// Error definitions -typedef struct RustCallStatus { - int8_t code; - RustBuffer errorBuf; -} RustCallStatus; - -// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ -// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ -#endif // def UNIFFI_SHARED_H -#ifndef UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK -#define UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK -typedef void (*UniffiRustFutureContinuationCallback)(uint64_t, int8_t - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK -typedef void (*UniffiForeignFutureDroppedCallback)(uint64_t - ); - -#endif -#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE -#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE -typedef void (*UniffiCallbackInterfaceFree)(uint64_t - ); - -#endif -#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE -#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE -typedef uint64_t (*UniffiCallbackInterfaceClone)(uint64_t - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT -typedef struct UniffiForeignFutureDroppedCallbackStruct { - uint64_t handle; - UniffiForeignFutureDroppedCallback _Nonnull free; -} UniffiForeignFutureDroppedCallbackStruct; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8 -typedef struct UniffiForeignFutureResultU8 { - uint8_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultU8; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8 -typedef void (*UniffiForeignFutureCompleteU8)(uint64_t, UniffiForeignFutureResultU8 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8 -typedef struct UniffiForeignFutureResultI8 { - int8_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultI8; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8 -typedef void (*UniffiForeignFutureCompleteI8)(uint64_t, UniffiForeignFutureResultI8 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16 -typedef struct UniffiForeignFutureResultU16 { - uint16_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultU16; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16 -typedef void (*UniffiForeignFutureCompleteU16)(uint64_t, UniffiForeignFutureResultU16 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16 -typedef struct UniffiForeignFutureResultI16 { - int16_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultI16; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16 -typedef void (*UniffiForeignFutureCompleteI16)(uint64_t, UniffiForeignFutureResultI16 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32 -typedef struct UniffiForeignFutureResultU32 { - uint32_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultU32; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32 -typedef void (*UniffiForeignFutureCompleteU32)(uint64_t, UniffiForeignFutureResultU32 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32 -typedef struct UniffiForeignFutureResultI32 { - int32_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultI32; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32 -typedef void (*UniffiForeignFutureCompleteI32)(uint64_t, UniffiForeignFutureResultI32 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64 -typedef struct UniffiForeignFutureResultU64 { - uint64_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultU64; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64 -typedef void (*UniffiForeignFutureCompleteU64)(uint64_t, UniffiForeignFutureResultU64 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64 -typedef struct UniffiForeignFutureResultI64 { - int64_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultI64; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64 -typedef void (*UniffiForeignFutureCompleteI64)(uint64_t, UniffiForeignFutureResultI64 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32 -typedef struct UniffiForeignFutureResultF32 { - float returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultF32; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32 -typedef void (*UniffiForeignFutureCompleteF32)(uint64_t, UniffiForeignFutureResultF32 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64 -typedef struct UniffiForeignFutureResultF64 { - double returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultF64; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64 -typedef void (*UniffiForeignFutureCompleteF64)(uint64_t, UniffiForeignFutureResultF64 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER -typedef struct UniffiForeignFutureResultRustBuffer { - RustBuffer returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultRustBuffer; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER -typedef void (*UniffiForeignFutureCompleteRustBuffer)(uint64_t, UniffiForeignFutureResultRustBuffer - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID -typedef struct UniffiForeignFutureResultVoid { - RustCallStatus callStatus; -} UniffiForeignFutureResultVoid; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID -typedef void (*UniffiForeignFutureCompleteVoid)(uint64_t, UniffiForeignFutureResultVoid - ); - -#endif -#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_WALLET_LISTENER_METHOD0 -#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_WALLET_LISTENER_METHOD0 -typedef void (*UniffiCallbackInterfaceWalletListenerMethod0)(uint64_t, RustBuffer, void* _Nonnull, - RustCallStatus *_Nonnull uniffiCallStatus - ); - -#endif -#ifndef UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_WALLET_LISTENER -#define UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_WALLET_LISTENER -typedef struct UniffiVTableCallbackInterfaceWalletListener { - UniffiCallbackInterfaceFree _Nonnull uniffiFree; - UniffiCallbackInterfaceClone _Nonnull uniffiClone; - UniffiCallbackInterfaceWalletListenerMethod0 _Nonnull onEvent; -} UniffiVTableCallbackInterfaceWalletListener; - -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_CLONE_WALLETENGINE -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_CLONE_WALLETENGINE -uint64_t uniffi_ffi_fn_clone_walletengine(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_FREE_WALLETENGINE -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_FREE_WALLETENGINE -void uniffi_ffi_fn_free_walletengine(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_CONSTRUCTOR_WALLETENGINE_NEW -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_CONSTRUCTOR_WALLETENGINE_NEW -uint64_t uniffi_ffi_fn_constructor_walletengine_new(RustCallStatus *_Nonnull out_status - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_CLEAR_LISTENER -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_CLEAR_LISTENER -void uniffi_ffi_fn_method_walletengine_clear_listener(uint64_t ptr, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT -RustBuffer uniffi_ffi_fn_method_walletengine_get_balance_snapshot(uint64_t ptr, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_PAUSE_SYNC -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_PAUSE_SYNC -void uniffi_ffi_fn_method_walletengine_pause_sync(uint64_t ptr, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SET_LISTENER -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SET_LISTENER -void uniffi_ffi_fn_method_walletengine_set_listener(uint64_t ptr, uint64_t listener, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SHUTDOWN -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SHUTDOWN -void uniffi_ffi_fn_method_walletengine_shutdown(uint64_t ptr, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_START_SYNC -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_START_SYNC -void uniffi_ffi_fn_method_walletengine_start_sync(uint64_t ptr, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_INIT_CALLBACK_VTABLE_WALLETLISTENER -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_INIT_CALLBACK_VTABLE_WALLETLISTENER -void uniffi_ffi_fn_init_callback_vtable_walletlistener(const UniffiVTableCallbackInterfaceWalletListener* _Nonnull vtable -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_ALLOC -#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_ALLOC -RustBuffer ffi_ffi_rustbuffer_alloc(uint64_t size, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FROM_BYTES -#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FROM_BYTES -RustBuffer ffi_ffi_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FREE -#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FREE -void ffi_ffi_rustbuffer_free(RustBuffer buf, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_RESERVE -#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_RESERVE -RustBuffer ffi_ffi_rustbuffer_reserve(RustBuffer buf, uint64_t additional, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U8 -void ffi_ffi_rust_future_poll_u8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U8 -void ffi_ffi_rust_future_cancel_u8(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U8 -void ffi_ffi_rust_future_free_u8(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U8 -uint8_t ffi_ffi_rust_future_complete_u8(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I8 -void ffi_ffi_rust_future_poll_i8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I8 -void ffi_ffi_rust_future_cancel_i8(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I8 -void ffi_ffi_rust_future_free_i8(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I8 -int8_t ffi_ffi_rust_future_complete_i8(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U16 -void ffi_ffi_rust_future_poll_u16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U16 -void ffi_ffi_rust_future_cancel_u16(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U16 -void ffi_ffi_rust_future_free_u16(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U16 -uint16_t ffi_ffi_rust_future_complete_u16(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I16 -void ffi_ffi_rust_future_poll_i16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I16 -void ffi_ffi_rust_future_cancel_i16(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I16 -void ffi_ffi_rust_future_free_i16(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I16 -int16_t ffi_ffi_rust_future_complete_i16(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U32 -void ffi_ffi_rust_future_poll_u32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U32 -void ffi_ffi_rust_future_cancel_u32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U32 -void ffi_ffi_rust_future_free_u32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U32 -uint32_t ffi_ffi_rust_future_complete_u32(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I32 -void ffi_ffi_rust_future_poll_i32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I32 -void ffi_ffi_rust_future_cancel_i32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I32 -void ffi_ffi_rust_future_free_i32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I32 -int32_t ffi_ffi_rust_future_complete_i32(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U64 -void ffi_ffi_rust_future_poll_u64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U64 -void ffi_ffi_rust_future_cancel_u64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U64 -void ffi_ffi_rust_future_free_u64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U64 -uint64_t ffi_ffi_rust_future_complete_u64(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I64 -void ffi_ffi_rust_future_poll_i64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I64 -void ffi_ffi_rust_future_cancel_i64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I64 -void ffi_ffi_rust_future_free_i64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I64 -int64_t ffi_ffi_rust_future_complete_i64(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F32 -void ffi_ffi_rust_future_poll_f32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F32 -void ffi_ffi_rust_future_cancel_f32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F32 -void ffi_ffi_rust_future_free_f32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F32 -float ffi_ffi_rust_future_complete_f32(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F64 -void ffi_ffi_rust_future_poll_f64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F64 -void ffi_ffi_rust_future_cancel_f64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F64 -void ffi_ffi_rust_future_free_f64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F64 -double ffi_ffi_rust_future_complete_f64(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_RUST_BUFFER -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_RUST_BUFFER -void ffi_ffi_rust_future_poll_rust_buffer(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_RUST_BUFFER -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_RUST_BUFFER -void ffi_ffi_rust_future_cancel_rust_buffer(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_RUST_BUFFER -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_RUST_BUFFER -void ffi_ffi_rust_future_free_rust_buffer(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_RUST_BUFFER -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_RUST_BUFFER -RustBuffer ffi_ffi_rust_future_complete_rust_buffer(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_VOID -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_VOID -void ffi_ffi_rust_future_poll_void(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_VOID -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_VOID -void ffi_ffi_rust_future_cancel_void(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_VOID -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_VOID -void ffi_ffi_rust_future_free_void(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_VOID -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_VOID -void ffi_ffi_rust_future_complete_void(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_CLEAR_LISTENER -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_CLEAR_LISTENER -uint16_t uniffi_ffi_checksum_method_walletengine_clear_listener(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT -uint16_t uniffi_ffi_checksum_method_walletengine_get_balance_snapshot(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_PAUSE_SYNC -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_PAUSE_SYNC -uint16_t uniffi_ffi_checksum_method_walletengine_pause_sync(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SET_LISTENER -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SET_LISTENER -uint16_t uniffi_ffi_checksum_method_walletengine_set_listener(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SHUTDOWN -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SHUTDOWN -uint16_t uniffi_ffi_checksum_method_walletengine_shutdown(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_START_SYNC -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_START_SYNC -uint16_t uniffi_ffi_checksum_method_walletengine_start_sync(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_CONSTRUCTOR_WALLETENGINE_NEW -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_CONSTRUCTOR_WALLETENGINE_NEW -uint16_t uniffi_ffi_checksum_constructor_walletengine_new(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETLISTENER_ON_EVENT -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETLISTENER_ON_EVENT -uint16_t uniffi_ffi_checksum_method_walletlistener_on_event(void - -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_UNIFFI_CONTRACT_VERSION -#define UNIFFI_FFIDEF_FFI_FFI_UNIFFI_CONTRACT_VERSION -uint32_t ffi_ffi_uniffi_contract_version(void - -); -#endif - diff --git a/ffi/ios/WalletModule/Generated/ffiFFI.modulemap b/ffi/ios/WalletModule/Generated/ffiFFI.modulemap deleted file mode 100644 index 5507d8a8e..000000000 --- a/ffi/ios/WalletModule/Generated/ffiFFI.modulemap +++ /dev/null @@ -1,7 +0,0 @@ -module ffiFFI { - header "ffiFFI.h" - export * - use "Darwin" - use "_Builtin_stdbool" - use "_Builtin_stdint" -} \ No newline at end of file diff --git a/ffi/ios/WalletModule/WalletModule.podspec b/ffi/ios/WalletModule/WalletModule.podspec deleted file mode 100644 index 9bed2bf12..000000000 --- a/ffi/ios/WalletModule/WalletModule.podspec +++ /dev/null @@ -1,17 +0,0 @@ -Pod::Spec.new do |s| - s.name = "WalletModule" - s.version = "0.1.0" - s.summary = "Rust wallet engine RN bridge" - s.platforms = { :ios => "13.0" } - s.source = { :path => "." } - s.source_files = "**/*.{h,m,mm,swift}" - s.swift_version = "5.0" - - # UniFFI generated Swift: - s.source_files += "Generated/**/*.{swift,h}" - - # Rust static lib(s) you built for iOS: - s.vendored_libraries = "RustLibs/*.a" - - s.dependency "React-Core" -end diff --git a/ffi/ios/WalletSDK/.gitignore b/ffi/ios/WalletSDK/.gitignore deleted file mode 100644 index 2b10e7795..000000000 --- a/ffi/ios/WalletSDK/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.build -.swiftpm -Binaries/WalletFFI.xcframework/ios-* diff --git a/ffi/ios/WalletSDK/Binaries/WalletFFI.xcframework/Info.plist b/ffi/ios/WalletSDK/Binaries/WalletFFI.xcframework/Info.plist deleted file mode 100644 index d31bdb13d..000000000 --- a/ffi/ios/WalletSDK/Binaries/WalletFFI.xcframework/Info.plist +++ /dev/null @@ -1,43 +0,0 @@ - - - - - AvailableLibraries - - - BinaryPath - libffi.dylib - LibraryIdentifier - ios-arm64-simulator - LibraryPath - libffi.dylib - SupportedArchitectures - - arm64 - - SupportedPlatform - ios - SupportedPlatformVariant - simulator - - - BinaryPath - libffi.dylib - LibraryIdentifier - ios-arm64 - LibraryPath - libffi.dylib - SupportedArchitectures - - arm64 - - SupportedPlatform - ios - - - CFBundlePackageType - XFWK - XCFrameworkFormatVersion - 1.0 - - diff --git a/ffi/ios/WalletSDK/Package.swift b/ffi/ios/WalletSDK/Package.swift deleted file mode 100644 index 430f7a8cd..000000000 --- a/ffi/ios/WalletSDK/Package.swift +++ /dev/null @@ -1,37 +0,0 @@ -// swift-tools-version: 5.9 -import PackageDescription - -let package = Package( - name: "WalletSDK", - platforms: [.iOS(.v13)], - products: [ - .library(name: "WalletSDK", targets: ["WalletSDK"]) - ], - targets: [ - .binaryTarget( - name: "WalletFFI", - path: "Binaries/WalletFFI.xcframework" - ), - - .systemLibrary( - name: "ffiFFI", - path: "Sources/ffiFFI" - ), - - .target( - name: "WalletSDK", - dependencies: ["WalletFFI", "ffiFFI"], - path: "Sources/WalletSDK", - sources: [ - "WalletSDK.swift", - "Generated/ffi.swift", - ] - ), - - .testTarget( - name: "WalletSDKTests", - dependencies: ["WalletSDK"], - path: "Tests/WalletSDKTests" - ), - ] -) diff --git a/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffi.swift b/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffi.swift deleted file mode 100644 index eb1827cfa..000000000 --- a/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffi.swift +++ /dev/null @@ -1,1118 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! - -// swiftlint:disable all -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(ffiFFI) -import ffiFFI -#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 empty() -> RustBuffer { - RustBuffer(capacity: 0, len:0, data: nil) - } - - static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { - try! rustCall { ffi_ffi_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_ffi_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 library of its own. - -fileprivate extension Data { - init(rustBuffer: RustBuffer) { - self.init( - bytesNoCopy: rustBuffer.data!, - count: Int(rustBuffer.len), - deallocator: .none - ) - } -} - -// Define reader functionality. Normally this would be defined in a class or -// struct, but we use standalone functions instead in order to make external -// types work. -// -// With external types, one swift source file needs to be able to call the read -// method on another source file's FfiConverter, but then what visibility -// should Reader have? -// - If Reader is fileprivate, then this means the read() must also -// be fileprivate, which doesn't work with external types. -// - If Reader is internal/public, we'll get compile errors since both source -// files will try define the same type. -// -// Instead, the read() method and these helper functions input a tuple of data - -fileprivate func createReader(data: Data) -> (data: Data, offset: Data.Index) { - (data: data, offset: 0) -} - -// Reads an integer at the current offset, in big-endian order, and advances -// the offset on success. Throws if reading the integer would move the -// offset past the end of the buffer. -fileprivate func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { - let range = reader.offset...size - guard reader.data.count >= range.upperBound else { - throw UniffiInternalError.bufferOverflow - } - if T.self == UInt8.self { - let value = reader.data[reader.offset] - reader.offset += 1 - return value as! T - } - var value: T = 0 - let _ = withUnsafeMutableBytes(of: &value, { reader.data.copyBytes(to: $0, from: range)}) - reader.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 -fileprivate func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> Array { - let range = reader.offset..<(reader.offset+count) - guard reader.data.count >= range.upperBound else { - throw UniffiInternalError.bufferOverflow - } - var value = [UInt8](repeating: 0, count: count) - value.withUnsafeMutableBufferPointer({ buffer in - reader.data.copyBytes(to: buffer, from: range) - }) - reader.offset = range.upperBound - return value -} - -// Reads a float at the current offset. -fileprivate func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { - return Float(bitPattern: try readInt(&reader)) -} - -// Reads a float at the current offset. -fileprivate func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { - return Double(bitPattern: try readInt(&reader)) -} - -// Indicates if the offset has reached the end of the buffer. -fileprivate func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { - return reader.offset < reader.data.count -} - -// Define writer functionality. Normally this would be defined in a class or -// struct, but we use standalone functions instead in order to make external -// types work. See the above discussion on Readers for details. - -fileprivate func createWriter() -> [UInt8] { - return [] -} - -fileprivate func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { - writer.append(contentsOf: byteArr) -} - -// Writes an integer in big-endian order. -// -// Warning: make sure what you are trying to write -// is in the correct type! -fileprivate func writeInt(_ writer: inout [UInt8], _ value: T) { - var value = value.bigEndian - withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } -} - -fileprivate func writeFloat(_ writer: inout [UInt8], _ value: Float) { - writeInt(&writer, value.bitPattern) -} - -fileprivate func writeDouble(_ writer: inout [UInt8], _ value: Double) { - writeInt(&writer, value.bitPattern) -} - -// Protocol for types that transfer other types across the FFI. This is -// analogous to the Rust trait of the same name. -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: inout (data: Data, offset: Data.Index)) throws -> SwiftType - static func write(_ value: SwiftType, into buf: inout [UInt8]) -} - -// Types conforming to `Primitive` pass themselves directly over the FFI. -fileprivate protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType { } - -extension FfiConverterPrimitive { -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public static func lift(_ value: FfiType) throws -> SwiftType { - return value - } - -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public 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 { -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public static func lift(_ buf: RustBuffer) throws -> SwiftType { - var reader = createReader(data: Data(rustBuffer: buf)) - let value = try read(from: &reader) - if hasRemaining(reader) { - throw UniffiInternalError.incompleteData - } - buf.deallocate() - return value - } - -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public static func lower(_ value: SwiftType) -> RustBuffer { - var writer = createWriter() - write(value, into: &writer) - return RustBuffer(bytes: writer) - } -} -// 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 extension NSLock { - func withLock(f: () throws -> T) rethrows -> T { - self.lock() - defer { self.unlock() } - return try f() - } -} - -fileprivate let CALL_SUCCESS: Int8 = 0 -fileprivate let CALL_ERROR: Int8 = 1 -fileprivate let CALL_UNEXPECTED_ERROR: Int8 = 2 -fileprivate let CALL_CANCELLED: Int8 = 3 - -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 { - let neverThrow: ((RustBuffer) throws -> Never)? = nil - return try makeRustCall(callback, errorHandler: neverThrow) -} - -private func rustCallWithError( - _ errorHandler: @escaping (RustBuffer) throws -> E, - _ callback: (UnsafeMutablePointer) -> T) throws -> T { - try makeRustCall(callback, errorHandler: errorHandler) -} - -private func makeRustCall( - _ callback: (UnsafeMutablePointer) -> T, - errorHandler: ((RustBuffer) throws -> E)? -) throws -> T { - uniffiEnsureFfiInitialized() - var callStatus = RustCallStatus.init() - let returnedVal = callback(&callStatus) - try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) - return returnedVal -} - -private func uniffiCheckCallStatus( - callStatus: RustCallStatus, - errorHandler: ((RustBuffer) throws -> E)? -) throws { - switch callStatus.code { - case CALL_SUCCESS: - return - - case CALL_ERROR: - if let errorHandler = errorHandler { - throw try errorHandler(callStatus.errorBuf) - } else { - callStatus.errorBuf.deallocate() - throw UniffiInternalError.unexpectedRustCallError - } - - case CALL_UNEXPECTED_ERROR: - // 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") - } - - case CALL_CANCELLED: - fatalError("Cancellation not supported yet") - - default: - throw UniffiInternalError.unexpectedRustCallStatusCode - } -} - -private func uniffiTraitInterfaceCall( - callStatus: UnsafeMutablePointer, - makeCall: () throws -> T, - writeReturn: (T) -> () -) { - do { - try writeReturn(makeCall()) - } catch let error { - callStatus.pointee.code = CALL_UNEXPECTED_ERROR - callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error)) - } -} - -private func uniffiTraitInterfaceCallWithError( - callStatus: UnsafeMutablePointer, - makeCall: () throws -> T, - writeReturn: (T) -> (), - lowerError: (E) -> RustBuffer -) { - do { - try writeReturn(makeCall()) - } catch let error as E { - callStatus.pointee.code = CALL_ERROR - callStatus.pointee.errorBuf = lowerError(error) - } catch { - callStatus.pointee.code = CALL_UNEXPECTED_ERROR - callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error)) - } -} -// Initial value and increment amount for handles. -// These ensure that SWIFT handles always have the lowest bit set -fileprivate let UNIFFI_HANDLEMAP_INITIAL: UInt64 = 1 -fileprivate let UNIFFI_HANDLEMAP_DELTA: UInt64 = 2 - -fileprivate final class UniffiHandleMap: @unchecked Sendable { - // All mutation happens with this lock held, which is why we implement @unchecked Sendable. - private let lock = NSLock() - private var map: [UInt64: T] = [:] - private var currentHandle: UInt64 = UNIFFI_HANDLEMAP_INITIAL - - func insert(obj: T) -> UInt64 { - lock.withLock { - return doInsert(obj) - } - } - - // Low-level insert function, this assumes `lock` is held. - private func doInsert(_ obj: T) -> UInt64 { - let handle = currentHandle - currentHandle += UNIFFI_HANDLEMAP_DELTA - map[handle] = obj - return handle - } - - func get(handle: UInt64) throws -> T { - try lock.withLock { - guard let obj = map[handle] else { - throw UniffiInternalError.unexpectedStaleHandle - } - return obj - } - } - - func clone(handle: UInt64) throws -> UInt64 { - try lock.withLock { - guard let obj = map[handle] else { - throw UniffiInternalError.unexpectedStaleHandle - } - return doInsert(obj) - } - } - - @discardableResult - func remove(handle: UInt64) throws -> T { - try lock.withLock { - guard let obj = map.removeValue(forKey: handle) else { - throw UniffiInternalError.unexpectedStaleHandle - } - return obj - } - } - - var count: Int { - get { - map.count - } - } -} - - -// Public interface members begin here. -// Magic number for the Rust proxy to call using the same mechanism as every other method, -// to free the callback once it's dropped by Rust. -private let IDX_CALLBACK_FREE: Int32 = 0 -// Callback return codes -private let UNIFFI_CALLBACK_SUCCESS: Int32 = 0 -private let UNIFFI_CALLBACK_ERROR: Int32 = 1 -private let UNIFFI_CALLBACK_UNEXPECTED_ERROR: Int32 = 2 - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -fileprivate struct FfiConverterUInt32: FfiConverterPrimitive { - typealias FfiType = UInt32 - typealias SwiftType = UInt32 - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { - return try lift(readInt(&buf)) - } - - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { - writeInt(&buf, lower(value)) - } -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -fileprivate struct FfiConverterFloat: FfiConverterPrimitive { - typealias FfiType = Float - typealias SwiftType = Float - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Float { - return try lift(readFloat(&buf)) - } - - public static func write(_ value: Float, into buf: inout [UInt8]) { - writeFloat(&buf, lower(value)) - } -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -fileprivate struct FfiConverterString: FfiConverter { - typealias SwiftType = String - typealias FfiType = RustBuffer - - public 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)! - } - - public 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) - } - } - } - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { - let len: Int32 = try readInt(&buf) - return String(bytes: try readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! - } - - public static func write(_ value: String, into buf: inout [UInt8]) { - let len = Int32(value.utf8.count) - writeInt(&buf, len) - writeBytes(&buf, value.utf8) - } -} - - - - -public protocol WalletEngineProtocol: AnyObject, Sendable { - - func clearListener() throws - - func getBalanceSnapshot() throws -> BalanceSnapshot - - func pauseSync() throws - - /** - * ✅ UniFFI-friendly callback: Box - */ - func setListener(listener: WalletListener) throws - - func shutdown() throws - - func startSync() throws - -} -open class WalletEngine: WalletEngineProtocol, @unchecked Sendable { - fileprivate let handle: UInt64 - - /// Used to instantiate a [FFIObject] without an actual handle, for fakes in tests, mostly. -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public struct NoHandle { - public init() {} - } - - // 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`. -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - required public init(unsafeFromHandle handle: UInt64) { - self.handle = handle - } - - // This constructor can be used to instantiate a fake object. - // - Parameter noHandle: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - // - // - Warning: - // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing handle the FFI lower functions will crash. -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public init(noHandle: NoHandle) { - self.handle = 0 - } - -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public func uniffiCloneHandle() -> UInt64 { - return try! rustCall { uniffi_ffi_fn_clone_walletengine(self.handle, $0) } - } -public convenience init()throws { - let handle = - try rustCallWithError(FfiConverterTypeWalletError_lift) { - uniffi_ffi_fn_constructor_walletengine_new($0 - ) -} - self.init(unsafeFromHandle: handle) -} - - deinit { - if handle == 0 { - // Mock objects have handle=0 don't try to free them - return - } - - try! rustCall { uniffi_ffi_fn_free_walletengine(handle, $0) } - } - - - - -open func clearListener()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { - uniffi_ffi_fn_method_walletengine_clear_listener( - self.uniffiCloneHandle(),$0 - ) -} -} - -open func getBalanceSnapshot()throws -> BalanceSnapshot { - return try FfiConverterTypeBalanceSnapshot_lift(try rustCallWithError(FfiConverterTypeWalletError_lift) { - uniffi_ffi_fn_method_walletengine_get_balance_snapshot( - self.uniffiCloneHandle(),$0 - ) -}) -} - -open func pauseSync()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { - uniffi_ffi_fn_method_walletengine_pause_sync( - self.uniffiCloneHandle(),$0 - ) -} -} - - /** - * ✅ UniFFI-friendly callback: Box - */ -open func setListener(listener: WalletListener)throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { - uniffi_ffi_fn_method_walletengine_set_listener( - self.uniffiCloneHandle(), - FfiConverterCallbackInterfaceWalletListener_lower(listener),$0 - ) -} -} - -open func shutdown()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { - uniffi_ffi_fn_method_walletengine_shutdown( - self.uniffiCloneHandle(),$0 - ) -} -} - -open func startSync()throws {try rustCallWithError(FfiConverterTypeWalletError_lift) { - uniffi_ffi_fn_method_walletengine_start_sync( - self.uniffiCloneHandle(),$0 - ) -} -} - - - -} - - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public struct FfiConverterTypeWalletEngine: FfiConverter { - typealias FfiType = UInt64 - typealias SwiftType = WalletEngine - - public static func lift(_ handle: UInt64) throws -> WalletEngine { - return WalletEngine(unsafeFromHandle: handle) - } - - public static func lower(_ value: WalletEngine) -> UInt64 { - return value.uniffiCloneHandle() - } - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> WalletEngine { - let handle: UInt64 = try readInt(&buf) - return try lift(handle) - } - - public static func write(_ value: WalletEngine, into buf: inout [UInt8]) { - writeInt(&buf, lower(value)) - } -} - - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeWalletEngine_lift(_ handle: UInt64) throws -> WalletEngine { - return try FfiConverterTypeWalletEngine.lift(handle) -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeWalletEngine_lower(_ value: WalletEngine) -> UInt64 { - return FfiConverterTypeWalletEngine.lower(value) -} - - - - -public struct BalanceSnapshot: Equatable, Hashable { - public var confirmed: String - public var total: String - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(confirmed: String, total: String) { - self.confirmed = confirmed - self.total = total - } - - - - -} - -#if compiler(>=6) -extension BalanceSnapshot: Sendable {} -#endif - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public struct FfiConverterTypeBalanceSnapshot: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> BalanceSnapshot { - return - try BalanceSnapshot( - confirmed: FfiConverterString.read(from: &buf), - total: FfiConverterString.read(from: &buf) - ) - } - - public static func write(_ value: BalanceSnapshot, into buf: inout [UInt8]) { - FfiConverterString.write(value.confirmed, into: &buf) - FfiConverterString.write(value.total, into: &buf) - } -} - - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeBalanceSnapshot_lift(_ buf: RustBuffer) throws -> BalanceSnapshot { - return try FfiConverterTypeBalanceSnapshot.lift(buf) -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeBalanceSnapshot_lower(_ value: BalanceSnapshot) -> RustBuffer { - return FfiConverterTypeBalanceSnapshot.lower(value) -} - - -public enum WalletError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { - - - - case CommandQueueClosed - case ListenerLockPoisoned - case Internal(String - ) - - - - - - - public var errorDescription: String? { - String(reflecting: self) - } - -} - -#if compiler(>=6) -extension WalletError: Sendable {} -#endif - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public struct FfiConverterTypeWalletError: FfiConverterRustBuffer { - typealias SwiftType = WalletError - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> WalletError { - let variant: Int32 = try readInt(&buf) - switch variant { - - - - - case 1: return .CommandQueueClosed - case 2: return .ListenerLockPoisoned - case 3: return .Internal( - try FfiConverterString.read(from: &buf) - ) - - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - public static func write(_ value: WalletError, into buf: inout [UInt8]) { - switch value { - - - - - - case .CommandQueueClosed: - writeInt(&buf, Int32(1)) - - - case .ListenerLockPoisoned: - writeInt(&buf, Int32(2)) - - - case let .Internal(v1): - writeInt(&buf, Int32(3)) - FfiConverterString.write(v1, into: &buf) - - } - } -} - - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeWalletError_lift(_ buf: RustBuffer) throws -> WalletError { - return try FfiConverterTypeWalletError.lift(buf) -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeWalletError_lower(_ value: WalletError) -> RustBuffer { - return FfiConverterTypeWalletError.lower(value) -} - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - -public enum WalletEvent: Equatable, Hashable { - - case engineReady - case syncStarted - case syncProgress(walletHeight: UInt32, networkHeight: UInt32, percent: Float - ) - case syncPaused - case syncFinished - case balanceChanged(BalanceSnapshot - ) - case newTransaction(txid: String - ) - case error(code: String, message: String - ) - - - - - -} - -#if compiler(>=6) -extension WalletEvent: Sendable {} -#endif - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public struct FfiConverterTypeWalletEvent: FfiConverterRustBuffer { - typealias SwiftType = WalletEvent - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> WalletEvent { - let variant: Int32 = try readInt(&buf) - switch variant { - - case 1: return .engineReady - - case 2: return .syncStarted - - case 3: return .syncProgress(walletHeight: try FfiConverterUInt32.read(from: &buf), networkHeight: try FfiConverterUInt32.read(from: &buf), percent: try FfiConverterFloat.read(from: &buf) - ) - - case 4: return .syncPaused - - case 5: return .syncFinished - - case 6: return .balanceChanged(try FfiConverterTypeBalanceSnapshot.read(from: &buf) - ) - - case 7: return .newTransaction(txid: try FfiConverterString.read(from: &buf) - ) - - case 8: return .error(code: try FfiConverterString.read(from: &buf), message: try FfiConverterString.read(from: &buf) - ) - - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - public static func write(_ value: WalletEvent, into buf: inout [UInt8]) { - switch value { - - - case .engineReady: - writeInt(&buf, Int32(1)) - - - case .syncStarted: - writeInt(&buf, Int32(2)) - - - case let .syncProgress(walletHeight,networkHeight,percent): - writeInt(&buf, Int32(3)) - FfiConverterUInt32.write(walletHeight, into: &buf) - FfiConverterUInt32.write(networkHeight, into: &buf) - FfiConverterFloat.write(percent, into: &buf) - - - case .syncPaused: - writeInt(&buf, Int32(4)) - - - case .syncFinished: - writeInt(&buf, Int32(5)) - - - case let .balanceChanged(v1): - writeInt(&buf, Int32(6)) - FfiConverterTypeBalanceSnapshot.write(v1, into: &buf) - - - case let .newTransaction(txid): - writeInt(&buf, Int32(7)) - FfiConverterString.write(txid, into: &buf) - - - case let .error(code,message): - writeInt(&buf, Int32(8)) - FfiConverterString.write(code, into: &buf) - FfiConverterString.write(message, into: &buf) - - } - } -} - - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeWalletEvent_lift(_ buf: RustBuffer) throws -> WalletEvent { - return try FfiConverterTypeWalletEvent.lift(buf) -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterTypeWalletEvent_lower(_ value: WalletEvent) -> RustBuffer { - return FfiConverterTypeWalletEvent.lower(value) -} - - - - - -public protocol WalletListener: AnyObject, Sendable { - - func onEvent(event: WalletEvent) - -} - - -// Put the implementation in a struct so we don't pollute the top-level namespace -fileprivate struct UniffiCallbackInterfaceWalletListener { - - // Create the VTable using a series of closures. - // Swift automatically converts these into C callback functions. - // - // This creates 1-element array, since this seems to be the only way to construct a const - // pointer that we can pass to the Rust code. - static let vtable: [UniffiVTableCallbackInterfaceWalletListener] = [UniffiVTableCallbackInterfaceWalletListener( - uniffiFree: { (uniffiHandle: UInt64) -> () in - do { - try FfiConverterCallbackInterfaceWalletListener.handleMap.remove(handle: uniffiHandle) - } catch { - print("Uniffi callback interface WalletListener: handle missing in uniffiFree") - } - }, - uniffiClone: { (uniffiHandle: UInt64) -> UInt64 in - do { - return try FfiConverterCallbackInterfaceWalletListener.handleMap.clone(handle: uniffiHandle) - } catch { - fatalError("Uniffi callback interface WalletListener: handle missing in uniffiClone") - } - }, - onEvent: { ( - uniffiHandle: UInt64, - event: RustBuffer, - uniffiOutReturn: UnsafeMutableRawPointer, - uniffiCallStatus: UnsafeMutablePointer - ) in - let makeCall = { - () throws -> () in - guard let uniffiObj = try? FfiConverterCallbackInterfaceWalletListener.handleMap.get(handle: uniffiHandle) else { - throw UniffiInternalError.unexpectedStaleHandle - } - return uniffiObj.onEvent( - event: try FfiConverterTypeWalletEvent_lift(event) - ) - } - - - let writeReturn = { () } - uniffiTraitInterfaceCall( - callStatus: uniffiCallStatus, - makeCall: makeCall, - writeReturn: writeReturn - ) - } - )] -} - -private func uniffiCallbackInitWalletListener() { - uniffi_ffi_fn_init_callback_vtable_walletlistener(UniffiCallbackInterfaceWalletListener.vtable) -} - -// FfiConverter protocol for callback interfaces -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -fileprivate struct FfiConverterCallbackInterfaceWalletListener { - fileprivate static let handleMap = UniffiHandleMap() -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -extension FfiConverterCallbackInterfaceWalletListener : FfiConverter { - typealias SwiftType = WalletListener - typealias FfiType = UInt64 - -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public static func lift(_ handle: UInt64) throws -> SwiftType { - try handleMap.get(handle: handle) - } - -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { - let handle: UInt64 = try readInt(&buf) - return try lift(handle) - } - -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public static func lower(_ v: SwiftType) -> UInt64 { - return handleMap.insert(obj: v) - } - -#if swift(>=5.8) - @_documentation(visibility: private) -#endif - public static func write(_ v: SwiftType, into buf: inout [UInt8]) { - writeInt(&buf, lower(v)) - } -} - - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterCallbackInterfaceWalletListener_lift(_ handle: UInt64) throws -> WalletListener { - return try FfiConverterCallbackInterfaceWalletListener.lift(handle) -} - -#if swift(>=5.8) -@_documentation(visibility: private) -#endif -public func FfiConverterCallbackInterfaceWalletListener_lower(_ v: WalletListener) -> UInt64 { - return FfiConverterCallbackInterfaceWalletListener.lower(v) -} - -private enum InitializationResult { - case ok - case contractVersionMismatch - case apiChecksumMismatch -} -// Use a global variable to perform the versioning checks. Swift ensures that -// the code inside is only computed once. -private let initializationResult: InitializationResult = { - // Get the bindings contract version from our ComponentInterface - let bindings_contract_version = 30 - // Get the scaffolding contract version by calling the into the dylib - let scaffolding_contract_version = ffi_ffi_uniffi_contract_version() - if bindings_contract_version != scaffolding_contract_version { - return InitializationResult.contractVersionMismatch - } - if (uniffi_ffi_checksum_method_walletengine_clear_listener() != 65358) { - return InitializationResult.apiChecksumMismatch - } - if (uniffi_ffi_checksum_method_walletengine_get_balance_snapshot() != 57923) { - return InitializationResult.apiChecksumMismatch - } - if (uniffi_ffi_checksum_method_walletengine_pause_sync() != 29290) { - return InitializationResult.apiChecksumMismatch - } - if (uniffi_ffi_checksum_method_walletengine_set_listener() != 8699) { - return InitializationResult.apiChecksumMismatch - } - if (uniffi_ffi_checksum_method_walletengine_shutdown() != 23734) { - return InitializationResult.apiChecksumMismatch - } - if (uniffi_ffi_checksum_method_walletengine_start_sync() != 42941) { - return InitializationResult.apiChecksumMismatch - } - if (uniffi_ffi_checksum_constructor_walletengine_new() != 45836) { - return InitializationResult.apiChecksumMismatch - } - if (uniffi_ffi_checksum_method_walletlistener_on_event() != 26795) { - return InitializationResult.apiChecksumMismatch - } - - uniffiCallbackInitWalletListener() - return InitializationResult.ok -}() - -// Make the ensure init function public so that other modules which have external type references to -// our types can call it. -public func uniffiEnsureFfiInitialized() { - switch initializationResult { - case .ok: - break - case .contractVersionMismatch: - fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") - case .apiChecksumMismatch: - fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } -} - -// swiftlint:enable all \ No newline at end of file diff --git a/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.h b/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.h deleted file mode 100644 index 59db60430..000000000 --- a/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.h +++ /dev/null @@ -1,627 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! - -#pragma once - -#include -#include -#include - -// The following structs are used to implement the lowest level -// of the FFI, and thus useful to multiple uniffied crates. -// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H. -#ifdef UNIFFI_SHARED_H - // We also try to prevent mixing versions of shared uniffi header structs. - // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4 - #ifndef UNIFFI_SHARED_HEADER_V4 - #error Combining helper code from multiple versions of uniffi is not supported - #endif // ndef UNIFFI_SHARED_HEADER_V4 -#else -#define UNIFFI_SHARED_H -#define UNIFFI_SHARED_HEADER_V4 -// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ -// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ - -typedef struct RustBuffer -{ - uint64_t capacity; - uint64_t len; - uint8_t *_Nullable data; -} RustBuffer; - -typedef struct ForeignBytes -{ - int32_t len; - const uint8_t *_Nullable data; -} ForeignBytes; - -// Error definitions -typedef struct RustCallStatus { - int8_t code; - RustBuffer errorBuf; -} RustCallStatus; - -// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ -// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ -#endif // def UNIFFI_SHARED_H -#ifndef UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK -#define UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK -typedef void (*UniffiRustFutureContinuationCallback)(uint64_t, int8_t - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK -typedef void (*UniffiForeignFutureDroppedCallback)(uint64_t - ); - -#endif -#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE -#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE -typedef void (*UniffiCallbackInterfaceFree)(uint64_t - ); - -#endif -#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE -#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE -typedef uint64_t (*UniffiCallbackInterfaceClone)(uint64_t - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT -typedef struct UniffiForeignFutureDroppedCallbackStruct { - uint64_t handle; - UniffiForeignFutureDroppedCallback _Nonnull free; -} UniffiForeignFutureDroppedCallbackStruct; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8 -typedef struct UniffiForeignFutureResultU8 { - uint8_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultU8; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8 -typedef void (*UniffiForeignFutureCompleteU8)(uint64_t, UniffiForeignFutureResultU8 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8 -typedef struct UniffiForeignFutureResultI8 { - int8_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultI8; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8 -typedef void (*UniffiForeignFutureCompleteI8)(uint64_t, UniffiForeignFutureResultI8 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16 -typedef struct UniffiForeignFutureResultU16 { - uint16_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultU16; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16 -typedef void (*UniffiForeignFutureCompleteU16)(uint64_t, UniffiForeignFutureResultU16 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16 -typedef struct UniffiForeignFutureResultI16 { - int16_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultI16; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16 -typedef void (*UniffiForeignFutureCompleteI16)(uint64_t, UniffiForeignFutureResultI16 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32 -typedef struct UniffiForeignFutureResultU32 { - uint32_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultU32; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32 -typedef void (*UniffiForeignFutureCompleteU32)(uint64_t, UniffiForeignFutureResultU32 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32 -typedef struct UniffiForeignFutureResultI32 { - int32_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultI32; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32 -typedef void (*UniffiForeignFutureCompleteI32)(uint64_t, UniffiForeignFutureResultI32 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64 -typedef struct UniffiForeignFutureResultU64 { - uint64_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultU64; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64 -typedef void (*UniffiForeignFutureCompleteU64)(uint64_t, UniffiForeignFutureResultU64 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64 -typedef struct UniffiForeignFutureResultI64 { - int64_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultI64; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64 -typedef void (*UniffiForeignFutureCompleteI64)(uint64_t, UniffiForeignFutureResultI64 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32 -typedef struct UniffiForeignFutureResultF32 { - float returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultF32; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32 -typedef void (*UniffiForeignFutureCompleteF32)(uint64_t, UniffiForeignFutureResultF32 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64 -typedef struct UniffiForeignFutureResultF64 { - double returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultF64; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64 -typedef void (*UniffiForeignFutureCompleteF64)(uint64_t, UniffiForeignFutureResultF64 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER -typedef struct UniffiForeignFutureResultRustBuffer { - RustBuffer returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultRustBuffer; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER -typedef void (*UniffiForeignFutureCompleteRustBuffer)(uint64_t, UniffiForeignFutureResultRustBuffer - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID -typedef struct UniffiForeignFutureResultVoid { - RustCallStatus callStatus; -} UniffiForeignFutureResultVoid; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID -typedef void (*UniffiForeignFutureCompleteVoid)(uint64_t, UniffiForeignFutureResultVoid - ); - -#endif -#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_WALLET_LISTENER_METHOD0 -#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_WALLET_LISTENER_METHOD0 -typedef void (*UniffiCallbackInterfaceWalletListenerMethod0)(uint64_t, RustBuffer, void* _Nonnull, - RustCallStatus *_Nonnull uniffiCallStatus - ); - -#endif -#ifndef UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_WALLET_LISTENER -#define UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_WALLET_LISTENER -typedef struct UniffiVTableCallbackInterfaceWalletListener { - UniffiCallbackInterfaceFree _Nonnull uniffiFree; - UniffiCallbackInterfaceClone _Nonnull uniffiClone; - UniffiCallbackInterfaceWalletListenerMethod0 _Nonnull onEvent; -} UniffiVTableCallbackInterfaceWalletListener; - -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_CLONE_WALLETENGINE -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_CLONE_WALLETENGINE -uint64_t uniffi_ffi_fn_clone_walletengine(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_FREE_WALLETENGINE -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_FREE_WALLETENGINE -void uniffi_ffi_fn_free_walletengine(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_CONSTRUCTOR_WALLETENGINE_NEW -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_CONSTRUCTOR_WALLETENGINE_NEW -uint64_t uniffi_ffi_fn_constructor_walletengine_new(RustCallStatus *_Nonnull out_status - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_CLEAR_LISTENER -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_CLEAR_LISTENER -void uniffi_ffi_fn_method_walletengine_clear_listener(uint64_t ptr, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT -RustBuffer uniffi_ffi_fn_method_walletengine_get_balance_snapshot(uint64_t ptr, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_PAUSE_SYNC -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_PAUSE_SYNC -void uniffi_ffi_fn_method_walletengine_pause_sync(uint64_t ptr, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SET_LISTENER -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SET_LISTENER -void uniffi_ffi_fn_method_walletengine_set_listener(uint64_t ptr, uint64_t listener, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SHUTDOWN -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SHUTDOWN -void uniffi_ffi_fn_method_walletengine_shutdown(uint64_t ptr, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_START_SYNC -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_START_SYNC -void uniffi_ffi_fn_method_walletengine_start_sync(uint64_t ptr, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_INIT_CALLBACK_VTABLE_WALLETLISTENER -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_INIT_CALLBACK_VTABLE_WALLETLISTENER -void uniffi_ffi_fn_init_callback_vtable_walletlistener(const UniffiVTableCallbackInterfaceWalletListener* _Nonnull vtable -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_ALLOC -#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_ALLOC -RustBuffer ffi_ffi_rustbuffer_alloc(uint64_t size, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FROM_BYTES -#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FROM_BYTES -RustBuffer ffi_ffi_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FREE -#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FREE -void ffi_ffi_rustbuffer_free(RustBuffer buf, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_RESERVE -#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_RESERVE -RustBuffer ffi_ffi_rustbuffer_reserve(RustBuffer buf, uint64_t additional, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U8 -void ffi_ffi_rust_future_poll_u8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U8 -void ffi_ffi_rust_future_cancel_u8(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U8 -void ffi_ffi_rust_future_free_u8(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U8 -uint8_t ffi_ffi_rust_future_complete_u8(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I8 -void ffi_ffi_rust_future_poll_i8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I8 -void ffi_ffi_rust_future_cancel_i8(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I8 -void ffi_ffi_rust_future_free_i8(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I8 -int8_t ffi_ffi_rust_future_complete_i8(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U16 -void ffi_ffi_rust_future_poll_u16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U16 -void ffi_ffi_rust_future_cancel_u16(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U16 -void ffi_ffi_rust_future_free_u16(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U16 -uint16_t ffi_ffi_rust_future_complete_u16(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I16 -void ffi_ffi_rust_future_poll_i16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I16 -void ffi_ffi_rust_future_cancel_i16(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I16 -void ffi_ffi_rust_future_free_i16(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I16 -int16_t ffi_ffi_rust_future_complete_i16(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U32 -void ffi_ffi_rust_future_poll_u32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U32 -void ffi_ffi_rust_future_cancel_u32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U32 -void ffi_ffi_rust_future_free_u32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U32 -uint32_t ffi_ffi_rust_future_complete_u32(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I32 -void ffi_ffi_rust_future_poll_i32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I32 -void ffi_ffi_rust_future_cancel_i32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I32 -void ffi_ffi_rust_future_free_i32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I32 -int32_t ffi_ffi_rust_future_complete_i32(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U64 -void ffi_ffi_rust_future_poll_u64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U64 -void ffi_ffi_rust_future_cancel_u64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U64 -void ffi_ffi_rust_future_free_u64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U64 -uint64_t ffi_ffi_rust_future_complete_u64(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I64 -void ffi_ffi_rust_future_poll_i64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I64 -void ffi_ffi_rust_future_cancel_i64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I64 -void ffi_ffi_rust_future_free_i64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I64 -int64_t ffi_ffi_rust_future_complete_i64(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F32 -void ffi_ffi_rust_future_poll_f32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F32 -void ffi_ffi_rust_future_cancel_f32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F32 -void ffi_ffi_rust_future_free_f32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F32 -float ffi_ffi_rust_future_complete_f32(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F64 -void ffi_ffi_rust_future_poll_f64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F64 -void ffi_ffi_rust_future_cancel_f64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F64 -void ffi_ffi_rust_future_free_f64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F64 -double ffi_ffi_rust_future_complete_f64(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_RUST_BUFFER -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_RUST_BUFFER -void ffi_ffi_rust_future_poll_rust_buffer(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_RUST_BUFFER -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_RUST_BUFFER -void ffi_ffi_rust_future_cancel_rust_buffer(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_RUST_BUFFER -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_RUST_BUFFER -void ffi_ffi_rust_future_free_rust_buffer(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_RUST_BUFFER -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_RUST_BUFFER -RustBuffer ffi_ffi_rust_future_complete_rust_buffer(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_VOID -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_VOID -void ffi_ffi_rust_future_poll_void(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_VOID -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_VOID -void ffi_ffi_rust_future_cancel_void(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_VOID -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_VOID -void ffi_ffi_rust_future_free_void(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_VOID -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_VOID -void ffi_ffi_rust_future_complete_void(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_CLEAR_LISTENER -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_CLEAR_LISTENER -uint16_t uniffi_ffi_checksum_method_walletengine_clear_listener(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT -uint16_t uniffi_ffi_checksum_method_walletengine_get_balance_snapshot(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_PAUSE_SYNC -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_PAUSE_SYNC -uint16_t uniffi_ffi_checksum_method_walletengine_pause_sync(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SET_LISTENER -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SET_LISTENER -uint16_t uniffi_ffi_checksum_method_walletengine_set_listener(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SHUTDOWN -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SHUTDOWN -uint16_t uniffi_ffi_checksum_method_walletengine_shutdown(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_START_SYNC -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_START_SYNC -uint16_t uniffi_ffi_checksum_method_walletengine_start_sync(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_CONSTRUCTOR_WALLETENGINE_NEW -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_CONSTRUCTOR_WALLETENGINE_NEW -uint16_t uniffi_ffi_checksum_constructor_walletengine_new(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETLISTENER_ON_EVENT -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETLISTENER_ON_EVENT -uint16_t uniffi_ffi_checksum_method_walletlistener_on_event(void - -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_UNIFFI_CONTRACT_VERSION -#define UNIFFI_FFIDEF_FFI_FFI_UNIFFI_CONTRACT_VERSION -uint32_t ffi_ffi_uniffi_contract_version(void - -); -#endif - diff --git a/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.modulemap b/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.modulemap deleted file mode 100644 index 5507d8a8e..000000000 --- a/ffi/ios/WalletSDK/Sources/WalletSDK/Generated/ffiFFI.modulemap +++ /dev/null @@ -1,7 +0,0 @@ -module ffiFFI { - header "ffiFFI.h" - export * - use "Darwin" - use "_Builtin_stdbool" - use "_Builtin_stdint" -} \ No newline at end of file diff --git a/ffi/ios/WalletSDK/Sources/WalletSDK/WalletSDK.swift b/ffi/ios/WalletSDK/Sources/WalletSDK/WalletSDK.swift deleted file mode 100644 index 226747a63..000000000 --- a/ffi/ios/WalletSDK/Sources/WalletSDK/WalletSDK.swift +++ /dev/null @@ -1,80 +0,0 @@ -import Foundation - -public enum WalletSDKError: Error { - case underlying(String) -} - -public struct Balance { - public let confirmed: String - public let total: String -} - -public enum WalletEventPublic { - case engineReady - case syncStarted - case syncProgress(walletHeight: Int, networkHeight: Int, percent: Double) - case syncPaused - case syncFinished - case balanceChanged(Balance) - case newTransaction(txid: String) - case error(code: String, message: String) -} - -public final class Wallet: WalletListener { - private let engine: WalletEngine - private var handler: ((WalletEventPublic) -> Void)? - - public init(onEvent: ((WalletEventPublic) -> Void)? = nil) throws { - self.engine = try WalletEngine() - self.handler = onEvent - try self.engine.setListener(listener: self) - } - - public func setEventHandler(_ h: ((WalletEventPublic) -> Void)?) { - self.handler = h - } - - // UniFFI callback - public func onEvent(event: WalletEvent) { - handler?(mapEvent(event)) - } - - public func startSync() throws { - try engine.startSync() - } - - public func pauseSync() throws { - try engine.pauseSync() - } - - public func shutdown() throws { - try engine.clearListener() - try engine.shutdown() - } - - public func balance() throws -> Balance { - let snap = try engine.getBalanceSnapshot() - return Balance(confirmed: snap.confirmed, total: snap.total) - } - - private func mapEvent(_ e: WalletEvent) -> WalletEventPublic { - switch e { - case .engineReady: - return .engineReady - case .syncStarted: - return .syncStarted - case .syncProgress(walletHeight: let h, networkHeight: let nh, percent: let p): - return .syncProgress(walletHeight: Int(h), networkHeight: Int(nh), percent: Double(p)) - case .syncPaused: - return .syncPaused - case .syncFinished: - return .syncFinished - case .balanceChanged(snap: let s): - return .balanceChanged(Balance(confirmed: s.confirmed, total: s.total)) - case .newTransaction(txid: let t): - return .newTransaction(txid: t) - case .error(code: let c, message: let m): - return .error(code: c, message: m) - } - } -} diff --git a/ffi/ios/WalletSDK/Sources/WalletSDKSmoke/main.swift b/ffi/ios/WalletSDK/Sources/WalletSDKSmoke/main.swift deleted file mode 100644 index a197185f3..000000000 --- a/ffi/ios/WalletSDK/Sources/WalletSDKSmoke/main.swift +++ /dev/null @@ -1,22 +0,0 @@ -import Foundation -import WalletSDK - -final class Printer { - static func run() throws { - let wallet = try WalletSDK.Wallet(onEvent: { e in - print("EVENT:", e) - }) - - let bal = try wallet.balance() - print("BALANCE:", bal) - - try wallet.startSync() - - RunLoop.current.run(until: Date().addingTimeInterval(2.0)) - - try wallet.pauseSync() - try wallet.shutdown() - } -} - -do { try Printer.run() } catch { print("ERROR:", error) } diff --git a/ffi/ios/WalletSDK/Sources/ffiFFI/include/ffiFFI.h b/ffi/ios/WalletSDK/Sources/ffiFFI/include/ffiFFI.h deleted file mode 100644 index 59db60430..000000000 --- a/ffi/ios/WalletSDK/Sources/ffiFFI/include/ffiFFI.h +++ /dev/null @@ -1,627 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! - -#pragma once - -#include -#include -#include - -// The following structs are used to implement the lowest level -// of the FFI, and thus useful to multiple uniffied crates. -// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H. -#ifdef UNIFFI_SHARED_H - // We also try to prevent mixing versions of shared uniffi header structs. - // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4 - #ifndef UNIFFI_SHARED_HEADER_V4 - #error Combining helper code from multiple versions of uniffi is not supported - #endif // ndef UNIFFI_SHARED_HEADER_V4 -#else -#define UNIFFI_SHARED_H -#define UNIFFI_SHARED_HEADER_V4 -// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ -// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ - -typedef struct RustBuffer -{ - uint64_t capacity; - uint64_t len; - uint8_t *_Nullable data; -} RustBuffer; - -typedef struct ForeignBytes -{ - int32_t len; - const uint8_t *_Nullable data; -} ForeignBytes; - -// Error definitions -typedef struct RustCallStatus { - int8_t code; - RustBuffer errorBuf; -} RustCallStatus; - -// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ -// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ -#endif // def UNIFFI_SHARED_H -#ifndef UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK -#define UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK -typedef void (*UniffiRustFutureContinuationCallback)(uint64_t, int8_t - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK -typedef void (*UniffiForeignFutureDroppedCallback)(uint64_t - ); - -#endif -#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE -#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE -typedef void (*UniffiCallbackInterfaceFree)(uint64_t - ); - -#endif -#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE -#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE -typedef uint64_t (*UniffiCallbackInterfaceClone)(uint64_t - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT -typedef struct UniffiForeignFutureDroppedCallbackStruct { - uint64_t handle; - UniffiForeignFutureDroppedCallback _Nonnull free; -} UniffiForeignFutureDroppedCallbackStruct; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8 -typedef struct UniffiForeignFutureResultU8 { - uint8_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultU8; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8 -typedef void (*UniffiForeignFutureCompleteU8)(uint64_t, UniffiForeignFutureResultU8 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8 -typedef struct UniffiForeignFutureResultI8 { - int8_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultI8; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8 -typedef void (*UniffiForeignFutureCompleteI8)(uint64_t, UniffiForeignFutureResultI8 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16 -typedef struct UniffiForeignFutureResultU16 { - uint16_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultU16; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16 -typedef void (*UniffiForeignFutureCompleteU16)(uint64_t, UniffiForeignFutureResultU16 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16 -typedef struct UniffiForeignFutureResultI16 { - int16_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultI16; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16 -typedef void (*UniffiForeignFutureCompleteI16)(uint64_t, UniffiForeignFutureResultI16 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32 -typedef struct UniffiForeignFutureResultU32 { - uint32_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultU32; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32 -typedef void (*UniffiForeignFutureCompleteU32)(uint64_t, UniffiForeignFutureResultU32 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32 -typedef struct UniffiForeignFutureResultI32 { - int32_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultI32; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32 -typedef void (*UniffiForeignFutureCompleteI32)(uint64_t, UniffiForeignFutureResultI32 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64 -typedef struct UniffiForeignFutureResultU64 { - uint64_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultU64; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64 -typedef void (*UniffiForeignFutureCompleteU64)(uint64_t, UniffiForeignFutureResultU64 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64 -typedef struct UniffiForeignFutureResultI64 { - int64_t returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultI64; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64 -typedef void (*UniffiForeignFutureCompleteI64)(uint64_t, UniffiForeignFutureResultI64 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32 -typedef struct UniffiForeignFutureResultF32 { - float returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultF32; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32 -typedef void (*UniffiForeignFutureCompleteF32)(uint64_t, UniffiForeignFutureResultF32 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64 -typedef struct UniffiForeignFutureResultF64 { - double returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultF64; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64 -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64 -typedef void (*UniffiForeignFutureCompleteF64)(uint64_t, UniffiForeignFutureResultF64 - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER -typedef struct UniffiForeignFutureResultRustBuffer { - RustBuffer returnValue; - RustCallStatus callStatus; -} UniffiForeignFutureResultRustBuffer; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER -typedef void (*UniffiForeignFutureCompleteRustBuffer)(uint64_t, UniffiForeignFutureResultRustBuffer - ); - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID -typedef struct UniffiForeignFutureResultVoid { - RustCallStatus callStatus; -} UniffiForeignFutureResultVoid; - -#endif -#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID -#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID -typedef void (*UniffiForeignFutureCompleteVoid)(uint64_t, UniffiForeignFutureResultVoid - ); - -#endif -#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_WALLET_LISTENER_METHOD0 -#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_WALLET_LISTENER_METHOD0 -typedef void (*UniffiCallbackInterfaceWalletListenerMethod0)(uint64_t, RustBuffer, void* _Nonnull, - RustCallStatus *_Nonnull uniffiCallStatus - ); - -#endif -#ifndef UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_WALLET_LISTENER -#define UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_WALLET_LISTENER -typedef struct UniffiVTableCallbackInterfaceWalletListener { - UniffiCallbackInterfaceFree _Nonnull uniffiFree; - UniffiCallbackInterfaceClone _Nonnull uniffiClone; - UniffiCallbackInterfaceWalletListenerMethod0 _Nonnull onEvent; -} UniffiVTableCallbackInterfaceWalletListener; - -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_CLONE_WALLETENGINE -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_CLONE_WALLETENGINE -uint64_t uniffi_ffi_fn_clone_walletengine(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_FREE_WALLETENGINE -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_FREE_WALLETENGINE -void uniffi_ffi_fn_free_walletengine(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_CONSTRUCTOR_WALLETENGINE_NEW -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_CONSTRUCTOR_WALLETENGINE_NEW -uint64_t uniffi_ffi_fn_constructor_walletengine_new(RustCallStatus *_Nonnull out_status - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_CLEAR_LISTENER -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_CLEAR_LISTENER -void uniffi_ffi_fn_method_walletengine_clear_listener(uint64_t ptr, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT -RustBuffer uniffi_ffi_fn_method_walletengine_get_balance_snapshot(uint64_t ptr, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_PAUSE_SYNC -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_PAUSE_SYNC -void uniffi_ffi_fn_method_walletengine_pause_sync(uint64_t ptr, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SET_LISTENER -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SET_LISTENER -void uniffi_ffi_fn_method_walletengine_set_listener(uint64_t ptr, uint64_t listener, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SHUTDOWN -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_SHUTDOWN -void uniffi_ffi_fn_method_walletengine_shutdown(uint64_t ptr, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_START_SYNC -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_METHOD_WALLETENGINE_START_SYNC -void uniffi_ffi_fn_method_walletengine_start_sync(uint64_t ptr, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_FN_INIT_CALLBACK_VTABLE_WALLETLISTENER -#define UNIFFI_FFIDEF_UNIFFI_FFI_FN_INIT_CALLBACK_VTABLE_WALLETLISTENER -void uniffi_ffi_fn_init_callback_vtable_walletlistener(const UniffiVTableCallbackInterfaceWalletListener* _Nonnull vtable -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_ALLOC -#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_ALLOC -RustBuffer ffi_ffi_rustbuffer_alloc(uint64_t size, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FROM_BYTES -#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FROM_BYTES -RustBuffer ffi_ffi_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FREE -#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_FREE -void ffi_ffi_rustbuffer_free(RustBuffer buf, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_RESERVE -#define UNIFFI_FFIDEF_FFI_FFI_RUSTBUFFER_RESERVE -RustBuffer ffi_ffi_rustbuffer_reserve(RustBuffer buf, uint64_t additional, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U8 -void ffi_ffi_rust_future_poll_u8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U8 -void ffi_ffi_rust_future_cancel_u8(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U8 -void ffi_ffi_rust_future_free_u8(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U8 -uint8_t ffi_ffi_rust_future_complete_u8(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I8 -void ffi_ffi_rust_future_poll_i8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I8 -void ffi_ffi_rust_future_cancel_i8(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I8 -void ffi_ffi_rust_future_free_i8(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I8 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I8 -int8_t ffi_ffi_rust_future_complete_i8(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U16 -void ffi_ffi_rust_future_poll_u16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U16 -void ffi_ffi_rust_future_cancel_u16(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U16 -void ffi_ffi_rust_future_free_u16(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U16 -uint16_t ffi_ffi_rust_future_complete_u16(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I16 -void ffi_ffi_rust_future_poll_i16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I16 -void ffi_ffi_rust_future_cancel_i16(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I16 -void ffi_ffi_rust_future_free_i16(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I16 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I16 -int16_t ffi_ffi_rust_future_complete_i16(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U32 -void ffi_ffi_rust_future_poll_u32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U32 -void ffi_ffi_rust_future_cancel_u32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U32 -void ffi_ffi_rust_future_free_u32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U32 -uint32_t ffi_ffi_rust_future_complete_u32(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I32 -void ffi_ffi_rust_future_poll_i32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I32 -void ffi_ffi_rust_future_cancel_i32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I32 -void ffi_ffi_rust_future_free_i32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I32 -int32_t ffi_ffi_rust_future_complete_i32(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_U64 -void ffi_ffi_rust_future_poll_u64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_U64 -void ffi_ffi_rust_future_cancel_u64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_U64 -void ffi_ffi_rust_future_free_u64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_U64 -uint64_t ffi_ffi_rust_future_complete_u64(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_I64 -void ffi_ffi_rust_future_poll_i64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_I64 -void ffi_ffi_rust_future_cancel_i64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_I64 -void ffi_ffi_rust_future_free_i64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_I64 -int64_t ffi_ffi_rust_future_complete_i64(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F32 -void ffi_ffi_rust_future_poll_f32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F32 -void ffi_ffi_rust_future_cancel_f32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F32 -void ffi_ffi_rust_future_free_f32(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F32 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F32 -float ffi_ffi_rust_future_complete_f32(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_F64 -void ffi_ffi_rust_future_poll_f64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_F64 -void ffi_ffi_rust_future_cancel_f64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_F64 -void ffi_ffi_rust_future_free_f64(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F64 -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_F64 -double ffi_ffi_rust_future_complete_f64(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_RUST_BUFFER -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_RUST_BUFFER -void ffi_ffi_rust_future_poll_rust_buffer(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_RUST_BUFFER -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_RUST_BUFFER -void ffi_ffi_rust_future_cancel_rust_buffer(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_RUST_BUFFER -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_RUST_BUFFER -void ffi_ffi_rust_future_free_rust_buffer(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_RUST_BUFFER -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_RUST_BUFFER -RustBuffer ffi_ffi_rust_future_complete_rust_buffer(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_VOID -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_POLL_VOID -void ffi_ffi_rust_future_poll_void(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_VOID -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_CANCEL_VOID -void ffi_ffi_rust_future_cancel_void(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_VOID -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_FREE_VOID -void ffi_ffi_rust_future_free_void(uint64_t handle -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_VOID -#define UNIFFI_FFIDEF_FFI_FFI_RUST_FUTURE_COMPLETE_VOID -void ffi_ffi_rust_future_complete_void(uint64_t handle, RustCallStatus *_Nonnull out_status -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_CLEAR_LISTENER -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_CLEAR_LISTENER -uint16_t uniffi_ffi_checksum_method_walletengine_clear_listener(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_GET_BALANCE_SNAPSHOT -uint16_t uniffi_ffi_checksum_method_walletengine_get_balance_snapshot(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_PAUSE_SYNC -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_PAUSE_SYNC -uint16_t uniffi_ffi_checksum_method_walletengine_pause_sync(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SET_LISTENER -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SET_LISTENER -uint16_t uniffi_ffi_checksum_method_walletengine_set_listener(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SHUTDOWN -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_SHUTDOWN -uint16_t uniffi_ffi_checksum_method_walletengine_shutdown(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_START_SYNC -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETENGINE_START_SYNC -uint16_t uniffi_ffi_checksum_method_walletengine_start_sync(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_CONSTRUCTOR_WALLETENGINE_NEW -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_CONSTRUCTOR_WALLETENGINE_NEW -uint16_t uniffi_ffi_checksum_constructor_walletengine_new(void - -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETLISTENER_ON_EVENT -#define UNIFFI_FFIDEF_UNIFFI_FFI_CHECKSUM_METHOD_WALLETLISTENER_ON_EVENT -uint16_t uniffi_ffi_checksum_method_walletlistener_on_event(void - -); -#endif -#ifndef UNIFFI_FFIDEF_FFI_FFI_UNIFFI_CONTRACT_VERSION -#define UNIFFI_FFIDEF_FFI_FFI_UNIFFI_CONTRACT_VERSION -uint32_t ffi_ffi_uniffi_contract_version(void - -); -#endif - diff --git a/ffi/ios/WalletSDK/Sources/ffiFFI/module.modulemap b/ffi/ios/WalletSDK/Sources/ffiFFI/module.modulemap deleted file mode 100644 index 8a7b6b4cc..000000000 --- a/ffi/ios/WalletSDK/Sources/ffiFFI/module.modulemap +++ /dev/null @@ -1,7 +0,0 @@ -module ffiFFI { - header "include/ffiFFI.h" - export * - use "Darwin" - use "_Builtin_stdbool" - use "_Builtin_stdint" -} diff --git a/ffi/ios/WalletSDK/Tests/WalletSDKTests/WalletSDKTests.swift b/ffi/ios/WalletSDK/Tests/WalletSDKTests/WalletSDKTests.swift deleted file mode 100644 index a62a822d5..000000000 --- a/ffi/ios/WalletSDK/Tests/WalletSDKTests/WalletSDKTests.swift +++ /dev/null @@ -1,19 +0,0 @@ -import XCTest - -@testable import WalletSDK - -final class WalletSDKTests: XCTestCase { - func testCreateWalletAndGetBalance() throws { - let wallet = try Wallet(onEvent: { event in - print("EVENT:", event) - }) - - let bal = try wallet.balance() - print("BAL:", bal) - - try wallet.startSync() - RunLoop.current.run(until: Date().addingTimeInterval(1.0)) - try wallet.pauseSync() - try wallet.shutdown() - } -} From b1f67953c316f98dde5e131b207719f086a881d6 Mon Sep 17 00:00:00 2001 From: dorianvp Date: Fri, 13 Feb 2026 19:17:23 -0300 Subject: [PATCH 06/15] chore: use `just` to generate bindings --- ffi/rust/.gitignore | 1 + justfile | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 ffi/rust/.gitignore create mode 100644 justfile diff --git a/ffi/rust/.gitignore b/ffi/rust/.gitignore new file mode 100644 index 000000000..de2f0d0c2 --- /dev/null +++ b/ffi/rust/.gitignore @@ -0,0 +1 @@ +uniffi-output diff --git a/justfile b/justfile new file mode 100644 index 000000000..1633d73a8 --- /dev/null +++ b/justfile @@ -0,0 +1,31 @@ +# justfile + +set shell := ["bash", "-eu", "-o", "pipefail", "-c"] + +# Default task +default: build bindings + +# Build the ffi crate in release mode +build: + cargo build -p ffi --release + +# Generate all bindings (Kotlin & Swift) +bindings: build kotlin swift + +# Generate Kotlin bindings +kotlin: build + cargo run --bin generate-bindings generate \ + --library target/release/libffi.dylib \ + --language kotlin \ + --out-dir ffi/rust/uniffi-output + +# Generate Swift bindings +swift: build + cargo run --bin generate-bindings generate \ + --library target/release/libffi.dylib \ + --language swift \ + --out-dir ffi/rust/uniffi-output + +# Clean build artifacts +clean: + cargo clean From 3cd1bd53147f3bbc5eb83d5390d5c230c30a00f0 Mon Sep 17 00:00:00 2001 From: dorianvp Date: Sat, 14 Feb 2026 19:45:31 -0300 Subject: [PATCH 07/15] chore: refactor & non-blocking sync --- ffi/rust/src/config.rs | 59 ++++ ffi/rust/src/lib.rs | 662 ++++++++++++++++++++++------------------- ffi/rust/src/state.rs | 34 +++ 3 files changed, 446 insertions(+), 309 deletions(-) create mode 100644 ffi/rust/src/config.rs create mode 100644 ffi/rust/src/state.rs diff --git a/ffi/rust/src/config.rs b/ffi/rust/src/config.rs new file mode 100644 index 000000000..379a79cc5 --- /dev/null +++ b/ffi/rust/src/config.rs @@ -0,0 +1,59 @@ +use std::num::NonZeroU32; + +use pepper_sync::config::PerformanceLevel; +use zingo_common_components::protocol::activation_heights::for_test; +use zingolib::{ + config::{ + ChainType, SyncConfig, TransparentAddressDiscovery, ZingoConfig, construct_lightwalletd_uri, + }, + wallet::WalletSettings, +}; + +use crate::{Chain, Performance, error::WalletError}; + +pub fn chain_to_chaintype(chain: Chain) -> ChainType { + match chain { + Chain::Mainnet => ChainType::Mainnet, + Chain::Testnet => ChainType::Testnet, + Chain::Regtest => ChainType::Regtest(for_test::all_height_one_nus()), + } +} + +pub fn perf_to_level(p: Performance) -> PerformanceLevel { + match p { + Performance::Maximum => PerformanceLevel::Maximum, + Performance::High => PerformanceLevel::High, + Performance::Medium => PerformanceLevel::Medium, + Performance::Low => PerformanceLevel::Low, + } +} + +pub fn construct_config( + indexer_uri: String, + chain: Chain, + perf: Performance, + min_confirmations: u32, +) -> Result<(ZingoConfig, http::Uri), WalletError> { + let lightwalletd_uri = construct_lightwalletd_uri(Some(indexer_uri)); + + let min_conf = NonZeroU32::try_from(min_confirmations) + .map_err(|_| WalletError::Internal("min_confirmations must be >= 1".into()))?; + + let config = zingolib::config::load_clientconfig( + lightwalletd_uri.clone(), + None, + chain_to_chaintype(chain), + WalletSettings { + sync_config: SyncConfig { + transparent_address_discovery: TransparentAddressDiscovery::minimal(), + performance_level: perf_to_level(perf), + }, + min_confirmations: min_conf, + }, + NonZeroU32::try_from(1).expect("hard-coded integer"), + "".to_string(), + ) + .map_err(|e| WalletError::Internal(format!("Config load error: {e}")))?; + + Ok((config, lightwalletd_uri)) +} diff --git a/ffi/rust/src/lib.rs b/ffi/rust/src/lib.rs index 5b8da2635..91988d3cb 100644 --- a/ffi/rust/src/lib.rs +++ b/ffi/rust/src/lib.rs @@ -1,28 +1,25 @@ +pub mod config; pub mod error; +pub mod state; use std::{ - num::NonZeroU32, panic::{self, AssertUnwindSafe}, - sync::{Arc, Mutex}, + sync::Arc, thread, time::Duration, }; use bip0039::Mnemonic; -use pepper_sync::config::{PerformanceLevel, SyncConfig, TransparentAddressDiscovery}; use pepper_sync::wallet::SyncMode; -use tokio::sync::{mpsc, oneshot}; +use tokio::sync::{Mutex, RwLock, mpsc, oneshot}; use zcash_primitives::consensus::BlockHeight; use zcash_primitives::zip32::AccountId; -use zingo_common_components::protocol::activation_heights::for_test; use zingolib::{ - config::{ChainType, ZingoConfig, construct_lightwalletd_uri}, data::PollReport, - lightclient::LightClient, - wallet::{LightWallet, WalletBase, WalletSettings, balance::AccountBalance}, + wallet::{LightWallet, WalletBase, balance::AccountBalance}, }; -use crate::error::WalletError; +use crate::{config::construct_config, error::WalletError, state::EngineState}; uniffi::setup_scaffolding!(); @@ -41,23 +38,6 @@ pub enum Performance { Low, } -fn chain_to_chaintype(chain: Chain) -> ChainType { - match chain { - Chain::Mainnet => ChainType::Mainnet, - Chain::Testnet => ChainType::Testnet, - Chain::Regtest => ChainType::Regtest(for_test::all_height_one_nus()), - } -} - -fn perf_to_level(p: Performance) -> PerformanceLevel { - match p { - Performance::Maximum => PerformanceLevel::Maximum, - Performance::High => PerformanceLevel::High, - Performance::Medium => PerformanceLevel::Medium, - Performance::Low => PerformanceLevel::Low, - } -} - #[derive(Clone, Debug, uniffi::Record, PartialEq, Eq)] pub struct BalanceSnapshot { pub confirmed: String, @@ -111,39 +91,312 @@ fn balance_snapshot_from_balance(b: &AccountBalance) -> BalanceSnapshot { } } -fn construct_config( - indexer_uri: String, - chain: Chain, - perf: Performance, - min_confirmations: u32, -) -> Result<(ZingoConfig, http::Uri), WalletError> { - let lightwalletd_uri = construct_lightwalletd_uri(Some(indexer_uri)); - - let min_conf = NonZeroU32::try_from(min_confirmations) - .map_err(|_| WalletError::Internal("min_confirmations must be >= 1".into()))?; - - let config = zingolib::config::load_clientconfig( - lightwalletd_uri.clone(), - None, - chain_to_chaintype(chain), - WalletSettings { - sync_config: SyncConfig { - transparent_address_discovery: TransparentAddressDiscovery::minimal(), - performance_level: perf_to_level(perf), - }, - min_confirmations: min_conf, - }, - NonZeroU32::try_from(1).expect("hard-coded integer"), - "".to_string(), - ) - .map_err(|e| WalletError::Internal(format!("Config load error: {e}")))?; - - Ok((config, lightwalletd_uri)) -} - struct EngineInner { cmd_tx: mpsc::Sender, - listener: Mutex>>, + listener: std::sync::Mutex>>, +} + +impl EngineInner { + pub(crate) async fn handle_start_sync_spawn(self: Arc, st: Arc>) { + let (lc, indexer_uri) = { + let mut s = st.lock().await; + + if s.syncing { + return; + } + + let Some(lc) = s.lightclient.as_ref().cloned() else { + emit( + &self, + WalletEvent::Error { + code: "start_sync_failed".into(), + message: WalletError::NotInitialized.to_string(), + }, + ); + return; + }; + + s.syncing = true; + let indexer_uri = s.indexer_uri.clone(); + + (lc, indexer_uri) + }; + + emit(&self, WalletEvent::SyncStarted); + + // Spawn the sync loop so the command loop stays responsive. + let inner = self.clone(); + let st_for_task = st.clone(); + + let task = tokio::spawn(async move { + // Kick off sync/resume with a short write-lock section. + { + let mut guard = lc.write().await; + + if guard.sync_mode() == SyncMode::Paused { + // TODO: Replace with resume_sync() when available. + if let Err(e) = guard.pause_sync() { + emit( + &inner, + WalletEvent::Error { + code: "start_sync_failed".into(), + message: format!("resume_sync: {e}"), + }, + ); + let mut s = st_for_task.lock().await; + s.syncing = false; + return; + } + } else { + // TODO: Thisassumes sync() starts the background sync and returns reasonably quickly. + if let Err(e) = guard.sync().await { + emit( + &inner, + WalletEvent::Error { + code: "sync_failed".into(), + message: e.to_string(), + }, + ); + let mut s = st_for_task.lock().await; + s.syncing = false; + return; + } + } + } + + let mut last_balance_emitted: Option = None; + + loop { + // Read-only stuff + let (wh, poll, bal_opt) = { + let mut guard = lc.write().await; + + let wh = { + let w = guard.wallet.read().await; + w.sync_state + .highest_scanned_height() + .map(u32::from) + .unwrap_or(0) + }; + + let poll = guard.poll_sync(); + + let bal_opt = match guard.account_balance(AccountId::ZERO).await { + Ok(bal) => Some(balance_snapshot_from_balance(&bal)), + Err(_) => None, + }; + + (wh, poll, bal_opt) + }; + + // network height is independent of LightClient lock + let nh = match indexer_uri.as_ref() { + Some(uri) if *uri != http::Uri::default() => { + match zingolib::grpc_connector::get_latest_block(uri.clone()).await { + Ok(b) => b.height as u32, + Err(_) => 0, + } + } + _ => 0, + }; + + let percent = if nh > 0 { + (wh as f32 / nh as f32).clamp(0.0, 1.0) + } else { + 0.0 + }; + + emit( + &inner, + WalletEvent::SyncProgress { + wallet_height: wh, + network_height: nh, + percent, + }, + ); + + if let Some(snap) = bal_opt { + if last_balance_emitted.as_ref() != Some(&snap) { + last_balance_emitted = Some(snap.clone()); + emit(&inner, WalletEvent::BalanceChanged(snap)); + } + } + + match poll { + PollReport::Ready(Ok(_)) => { + emit(&inner, WalletEvent::SyncFinished); + let mut s = st_for_task.lock().await; + s.syncing = false; + break; + } + PollReport::Ready(Err(e)) => { + emit( + &inner, + WalletEvent::Error { + code: "sync_failed".into(), + message: e.to_string(), + }, + ); + let mut s = st_for_task.lock().await; + s.syncing = false; + break; + } + PollReport::NotReady | PollReport::NoHandle => { + // still running + } + } + + tokio::time::sleep(Duration::from_millis(250)).await; + } + }); + + let mut s = st.lock().await; + s.sync_task = Some(task); + } + + pub(crate) async fn handle_init_new( + &self, + st: &mut EngineState, + indexer_uri: String, + chain: Chain, + perf: Performance, + minconf: u32, + reply: oneshot::Sender>, + ) { + let res: Result<(), WalletError> = (async { + let (config, lw_uri) = construct_config(indexer_uri, chain, perf, minconf)?; + + let chain_height = zingolib::grpc_connector::get_latest_block(lw_uri.clone()) + .await + .map(|b| BlockHeight::from_u32(b.height as u32)) + .map_err(|e| WalletError::Internal(format!("get_latest_block: {e}")))?; + + let birthday = chain_height.saturating_sub(100); + + let lc = zingolib::lightclient::LightClient::new(config, birthday, false) + .map_err(|e| WalletError::Internal(format!("LightClient::new: {e}")))?; + + st.lightclient = Some(Arc::new(RwLock::new(lc))); + st.indexer_uri = Some(lw_uri); + st.last_balance = None; + st.syncing = false; + st.sync_task = None; + Ok(()) + }) + .await; + + let _ = reply.send(res); + } + + pub(crate) async fn handle_init_from_seed( + &self, + st: &mut EngineState, + seed_phrase: String, + birthday: u32, + indexer_uri: String, + chain: Chain, + perf: Performance, + minconf: u32, + reply: oneshot::Sender>, + ) { + let res: Result<(), WalletError> = (async { + let (config, lw_uri) = construct_config(indexer_uri, chain, perf, minconf)?; + + let mnemonic = Mnemonic::from_phrase(seed_phrase) + .map_err(|e| WalletError::Internal(format!("Mnemonic: {e}")))?; + + let wallet = LightWallet::new( + config.chain, + WalletBase::Mnemonic { + mnemonic, + no_of_accounts: config.no_of_accounts, + }, + BlockHeight::from_u32(birthday), + config.wallet_settings.clone(), + ) + .map_err(|e| WalletError::Internal(format!("LightWallet::new: {e}")))?; + + let lc = zingolib::lightclient::LightClient::create_from_wallet(wallet, config, false) + .map_err(|e| WalletError::Internal(format!("create_from_wallet: {e}")))?; + + st.lightclient = Some(Arc::new(RwLock::new(lc))); + st.indexer_uri = Some(lw_uri); + st.last_balance = None; + st.syncing = false; + st.sync_task = None; + Ok(()) + }) + .await; + + let _ = reply.send(res); + } + + pub(crate) async fn handle_get_balance( + &self, + st: &mut EngineState, + reply: oneshot::Sender>, + ) { + let res: Result = (async { + let lc = st + .lightclient + .as_ref() + .ok_or(WalletError::NotInitialized)? + .clone(); + + let guard = lc.read().await; + let bal = guard + .account_balance(AccountId::ZERO) + .await + .map_err(|e| WalletError::Internal(format!("account_balance: {e}")))?; + + Ok(balance_snapshot_from_balance(&bal)) + }) + .await; + + let _ = reply.send(res); + } + + pub(crate) async fn handle_get_network_height( + &self, + st: &mut EngineState, + reply: oneshot::Sender>, + ) { + let res: Result = (async { + let uri = st.indexer_uri.clone().ok_or(WalletError::NotInitialized)?; + let b = zingolib::grpc_connector::get_latest_block(uri) + .await + .map_err(|e| WalletError::Internal(format!("get_latest_block: {e}")))?; + Ok(b.height as u32) + }) + .await; + + let _ = reply.send(res); + } + + pub(crate) async fn handle_pause_sync(&self, st: &mut EngineState) { + let Some(lc) = st.lightclient.as_ref().cloned() else { + emit( + self, + WalletEvent::Error { + code: "pause_sync_failed".into(), + message: WalletError::NotInitialized.to_string(), + }, + ); + return; + }; + + let guard = lc.write().await; + match guard.pause_sync() { + Ok(_) => emit(self, WalletEvent::SyncPaused), + Err(e) => emit( + self, + WalletEvent::Error { + code: "pause_sync_failed".into(), + message: e.to_string(), + }, + ), + } + } } fn emit(inner: &EngineInner, event: WalletEvent) { @@ -193,6 +446,7 @@ fn create_engine_runtime() -> tokio::runtime::Runtime { tokio::runtime::Runtime::new().expect("tokio runtime") } +// TODO: THIS NEEDS TO BE BEHIND AN ASYNC LOCK. With the current setup, sync will block the thread. #[uniffi::export] impl WalletEngine { /// Creates a new [`WalletEngine`] and starts the internal engine thread. @@ -214,7 +468,7 @@ impl WalletEngine { let inner = Arc::new(EngineInner { cmd_tx, - listener: Mutex::new(None), + listener: std::sync::Mutex::new(None), }); let inner_for_task = inner.clone(); @@ -224,286 +478,76 @@ impl WalletEngine { rt.block_on(async move { emit(&inner_for_task, WalletEvent::EngineReady); - // TODO: THIS NEEDS TO BE BEHIND AN ASYNC LOCK. With the current setup, sync will block the thread. - let mut lightclient: Option = None; - let mut indexer_uri: Option = None; - - let mut last_balance: Option = None; - let mut syncing = false; + let st = Arc::new(Mutex::new(EngineState::new())); while let Some(cmd) = cmd_rx.recv().await { match cmd { - Command::GetNetworkHeight { reply } => { - todo!() - } Command::InitNew { - indexer_uri: srv, + indexer_uri, chain, perf, minconf, reply, } => { - let res: Result<(), WalletError> = (async { - let (config, lw_uri) = construct_config(srv, chain, perf, minconf)?; - - let chain_height = - zingolib::grpc_connector::get_latest_block(lw_uri.clone()) - .await - .map(|b| BlockHeight::from_u32(b.height as u32)) - .map_err(|e| { - WalletError::Internal(format!("get_latest_block: {e}")) - })?; - - let birthday = chain_height.saturating_sub(100); - - let lc = - LightClient::new(config, birthday, false).map_err(|e| { - WalletError::Internal(format!("LightClient::new: {e}")) - })?; - - lightclient = Some(lc); - indexer_uri = Some(lw_uri); - last_balance = None; - Ok(()) - }) - .await; - - let _ = reply.send(res); + let mut guard = st.lock().await; + inner_for_task + .handle_init_new( + &mut guard, + indexer_uri, + chain, + perf, + minconf, + reply, + ) + .await; } Command::InitFromSeed { seed_phrase, birthday, - indexer_uri: srv, + indexer_uri, chain, perf, minconf, reply, } => { - let res: Result<(), WalletError> = (async { - let (config, lw_uri) = construct_config(srv, chain, perf, minconf)?; - - let mnemonic = Mnemonic::from_phrase(seed_phrase) - .map_err(|e| WalletError::Internal(format!("Mnemonic: {e}")))?; - - let wallet = LightWallet::new( - config.chain, - WalletBase::Mnemonic { - mnemonic, - no_of_accounts: config.no_of_accounts, - }, - BlockHeight::from_u32(birthday), - config.wallet_settings.clone(), + let mut guard = st.lock().await; + inner_for_task + .handle_init_from_seed( + &mut guard, + seed_phrase, + birthday, + indexer_uri, + chain, + perf, + minconf, + reply, ) - .map_err(|e| { - WalletError::Internal(format!("LightWallet::new: {e}")) - })?; - - let lc = LightClient::create_from_wallet(wallet, config, false) - .map_err(|e| { - WalletError::Internal(format!("create_from_wallet: {e}")) - })?; - - lightclient = Some(lc); - indexer_uri = Some(lw_uri); - last_balance = None; - Ok(()) - }) - .await; - - let _ = reply.send(res); + .await; } Command::GetBalance { reply } => { - let res: Result = (async { - let lc = lightclient.as_mut().ok_or(WalletError::NotInitialized)?; - let bal = - lc.account_balance(AccountId::ZERO).await.map_err(|e| { - WalletError::Internal(format!("account_balance: {e}")) - })?; - Ok(balance_snapshot_from_balance(&bal)) - }) - .await; - - let _ = reply.send(res); + let mut guard = st.lock().await; + inner_for_task.handle_get_balance(&mut guard, reply).await; } - Command::StartSync => { - // manual model: one round per StartSync - if syncing { - // ignore repeated StartSync while running - continue; - } - - let Some(lc) = lightclient.as_mut() else { - emit( - &inner_for_task, - WalletEvent::Error { - code: "start_sync_failed".into(), - message: WalletError::NotInitialized.to_string(), - }, - ); - continue; - }; - - syncing = true; - emit(&inner_for_task, WalletEvent::SyncStarted); - - // If sync was paused previously, resume; otherwise start a new sync task. - // This mirrors old behavior: resume if paused else sync(). - if lc.sync_mode() == SyncMode::Paused { - if let Err(e) = lc.pause_sync() { - // NOTE: if zingolib has resume_sync() use that instead; - // you showed resume_sync() in the older file. - // Replace this with lc.resume_sync(). - emit( - &inner_for_task, - WalletEvent::Error { - code: "start_sync_failed".into(), - message: format!("resume_sync: {e}"), - }, - ); - syncing = false; - break; // or continue; depending on your loop structure - } - } else { - // Start the sync task once. - if let Err(e) = lc.sync().await { - emit( - &inner_for_task, - WalletEvent::Error { - code: "sync_failed".into(), - message: e.to_string(), - }, - ); - syncing = false; - continue; - } - } - - // Progress loop: keep reporting while the sync task is running. - // We stop when poll_sync() becomes Ready(_). - let mut last_balance_emitted: Option = None; - - loop { - // If user paused, stop reporting and exit this round. - if lc.sync_mode() == SyncMode::Paused { - emit(&inner_for_task, WalletEvent::SyncPaused); - syncing = false; - break; - } - - // Compute wallet height (local) - let wh = { - let w = lc.wallet.read().await; - w.sync_state - .highest_scanned_height() - .map(u32::from) - .unwrap_or(0) - }; - - // Compute network height (best effort from last known indexer_uri) - let nh = match indexer_uri.as_ref() { - Some(uri) if *uri != http::Uri::default() => { - match zingolib::grpc_connector::get_latest_block( - uri.clone(), - ) - .await - { - Ok(b) => b.height as u32, - Err(_) => 0, - } - } - _ => 0, - }; - - let percent = if nh > 0 { - (wh as f32 / nh as f32).clamp(0.0, 1.0) - } else { - 0.0 - }; - - emit( - &inner_for_task, - WalletEvent::SyncProgress { - wallet_height: wh, - network_height: nh, - percent, - }, - ); + Command::GetNetworkHeight { reply } => { + let mut guard = st.lock().await; + inner_for_task + .handle_get_network_height(&mut guard, reply) + .await; + } - // Emit balance changes - match lc.account_balance(AccountId::ZERO).await { - Ok(bal) => { - let snap = balance_snapshot_from_balance(&bal); - if last_balance_emitted.as_ref() != Some(&snap) { - last_balance_emitted = Some(snap.clone()); - emit( - &inner_for_task, - WalletEvent::BalanceChanged(snap), - ); - } - } - Err(e) => { - emit( - &inner_for_task, - WalletEvent::Error { - code: "balance_failed".into(), - message: e.to_string(), - }, - ); - } - } - - // Completion check - match lc.poll_sync() { - PollReport::Ready(Ok(_sync_result)) => { - emit(&inner_for_task, WalletEvent::SyncFinished); - syncing = false; - break; - } - PollReport::Ready(Err(e)) => { - emit( - &inner_for_task, - WalletEvent::Error { - code: "sync_failed".into(), - message: e.to_string(), - }, - ); - syncing = false; - break; - } - PollReport::NotReady | PollReport::NoHandle => { - // Still running, keep looping - } - } - - tokio::time::sleep(Duration::from_millis(250)).await; - } + Command::StartSync => { + inner_for_task + .clone() + .handle_start_sync_spawn(st.clone()) + .await; } Command::PauseSync => { - let Some(lc) = lightclient.as_mut() else { - emit( - &inner_for_task, - WalletEvent::Error { - code: "pause_sync_failed".into(), - message: WalletError::NotInitialized.to_string(), - }, - ); - continue; - }; - - match lc.pause_sync() { - Ok(_) => emit(&inner_for_task, WalletEvent::SyncPaused), - Err(e) => emit( - &inner_for_task, - WalletEvent::Error { - code: "pause_sync_failed".into(), - message: e.to_string(), - }, - ), - } + let mut guard = st.lock().await; + inner_for_task.handle_pause_sync(&mut guard).await; } Command::Shutdown => break, diff --git a/ffi/rust/src/state.rs b/ffi/rust/src/state.rs new file mode 100644 index 000000000..92a2bf08e --- /dev/null +++ b/ffi/rust/src/state.rs @@ -0,0 +1,34 @@ +use std::sync::Arc; + +use tokio::{sync::RwLock, task::JoinHandle}; +use zingolib::lightclient::LightClient; + +use crate::BalanceSnapshot; + +pub(crate) struct EngineState { + // TODO: add more documentation + /// `LightClient` lives behind an async RW lock so that sync only takes the lock when starting + /// pausing or stopping, and so that read-only calls (like getting the wallet's balance and + /// fetching the chain height) can use a read lock. + pub(crate) lightclient: Option>>, + pub(crate) indexer_uri: Option, + + pub(crate) syncing: bool, + pub(crate) sync_task: Option>, + + pub(crate) last_balance: Option, +} + +impl EngineState { + pub(crate) fn new() -> Self { + Self { + lightclient: None, + indexer_uri: None, + + syncing: false, + sync_task: None, + + last_balance: None, + } + } +} From f537ed71fef938d903482acab4e79b397faf26e5 Mon Sep 17 00:00:00 2001 From: dorianvp Date: Mon, 16 Feb 2026 12:38:38 -0300 Subject: [PATCH 08/15] chore: update cargo lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index be1e1469d..96ae554b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2155,7 +2155,7 @@ dependencies = [ name = "ffi" version = "0.0.0" dependencies = [ - "bip0039", + "bip0039 0.13.4", "http", "pepper-sync", "thiserror 2.0.17", From 4a82c7047985c9a523b8ec2cd6b435214f677f9f Mon Sep 17 00:00:00 2001 From: dorianvp Date: Wed, 18 Feb 2026 12:43:03 -0300 Subject: [PATCH 09/15] chore: add `RestoreParams` --- Cargo.lock | 28 ++++++++++++++-------------- ffi/rust/src/lib.rs | 37 ++++++++++++++++++++++--------------- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3eef92bef..7fc4e3784 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -303,7 +303,7 @@ dependencies = [ "rustc-hash 2.1.1", "serde", "serde_derive", - "syn 2.0.111", + "syn 2.0.116", ] [[package]] @@ -964,7 +964,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -1126,14 +1126,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.116", ] [[package]] @@ -2177,7 +2177,7 @@ dependencies = [ "bip0039 0.13.4", "http", "pepper-sync", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "uniffi", "zcash_primitives", @@ -5646,7 +5646,7 @@ checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.116", ] [[package]] @@ -7966,12 +7966,12 @@ dependencies = [ "glob", "goblin", "heck", - "indexmap 2.12.1", + "indexmap 2.13.0", "once_cell", "serde", "tempfile", "textwrap", - "toml 0.9.10+spec-1.1.0", + "toml 0.8.23", "uniffi_internal_macros", "uniffi_meta", "uniffi_pipeline", @@ -8008,10 +8008,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98f51ebca0d9a4b2aa6c644d5ede45c56f73906b96403c08a1985e75ccb64a01" dependencies = [ "anyhow", - "indexmap 2.12.1", + "indexmap 2.13.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.116", ] [[package]] @@ -8026,8 +8026,8 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.111", - "toml 0.9.10+spec-1.1.0", + "syn 2.0.116", + "toml 0.8.23", "uniffi_meta", ] @@ -8051,7 +8051,7 @@ checksum = "a806dddc8208f22efd7e95a5cdf88ed43d0f3271e8f63b47e757a8bbdb43b63a" dependencies = [ "anyhow", "heck", - "indexmap 2.12.1", + "indexmap 2.13.0", "tempfile", "uniffi_internal_macros", ] diff --git a/ffi/rust/src/lib.rs b/ffi/rust/src/lib.rs index 91988d3cb..7314b67c9 100644 --- a/ffi/rust/src/lib.rs +++ b/ffi/rust/src/lib.rs @@ -44,6 +44,21 @@ pub struct BalanceSnapshot { pub total: String, } +#[derive(Clone, Debug, uniffi::Record, PartialEq, Eq)] +pub struct SeedPhrase { + pub words: String, +} + +#[derive(Clone, Debug, uniffi::Record)] +pub struct RestoreParams { + pub seed_phrase: SeedPhrase, + pub birthday: u32, + pub indexer_uri: String, + pub chain: Chain, + pub perf: Performance, + pub minconf: u32, +} + #[derive(Clone, Debug, uniffi::Enum)] pub enum WalletEvent { EngineReady, @@ -669,25 +684,17 @@ impl WalletEngine { /// ## Errors /// - [`WalletError::CommandQueueClosed`] if the engine thread has exited. /// - [`WalletError::Internal`] on config/mnemonic/wallet construction errors. - pub fn init_from_seed( - &self, - seed_phrase: String, - birthday: u32, - indexer_uri: String, - chain: Chain, - perf: Performance, - minconf: u32, - ) -> Result<(), WalletError> { + pub fn init_from_seed(&self, params: RestoreParams) -> Result<(), WalletError> { let (reply_tx, reply_rx) = oneshot::channel(); self.inner .cmd_tx .blocking_send(Command::InitFromSeed { - seed_phrase, - birthday, - indexer_uri, - chain, - perf, - minconf, + seed_phrase: params.seed_phrase.words, + birthday: params.birthday, + indexer_uri: params.indexer_uri, + chain: params.chain, + perf: params.perf, + minconf: params.minconf, reply: reply_tx, }) .map_err(|_| WalletError::CommandQueueClosed)?; From 6cefb10f6e0343faccc49650713c147646c6ffb0 Mon Sep 17 00:00:00 2001 From: dorianvp Date: Wed, 18 Feb 2026 14:33:25 -0300 Subject: [PATCH 10/15] chore: add example --- Cargo.toml | 2 +- ffi/rust/Cargo.toml | 3 +- ffi/rust/examples/basic.rs | 80 ++++++++++++++++++++++++++++++++++++++ ffi/rust/src/lib.rs | 1 + 4 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 ffi/rust/examples/basic.rs diff --git a/Cargo.toml b/Cargo.toml index 75a582356..2b4180fed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -126,7 +126,7 @@ pepper-sync = { path = "pepper-sync" } zingolib = { path = "zingolib" } zcash_local_net = { git = "https://github.com/zingolabs/infrastructure.git", rev = "e4714fd" } zingo_test_vectors = { git = "https://github.com/zingolabs/infrastructure.git", rev = "e4714fd" } +ffi = { path = "ffi/rust" } [profile.test] opt-level = 3 - diff --git a/ffi/rust/Cargo.toml b/ffi/rust/Cargo.toml index 8b237ea6a..63cb26163 100644 --- a/ffi/rust/Cargo.toml +++ b/ffi/rust/Cargo.toml @@ -20,7 +20,8 @@ uniffi = { version = "0.31", features = ["build"] } [lib] -crate-type = ["cdylib"] +# rlib is necessary to run examples +crate-type = ["rlib", "cdylib"] name = "ffi" [[bin]] diff --git a/ffi/rust/examples/basic.rs b/ffi/rust/examples/basic.rs new file mode 100644 index 000000000..7be468e83 --- /dev/null +++ b/ffi/rust/examples/basic.rs @@ -0,0 +1,80 @@ +use std::{env, time::Duration}; + +use bip0039::{English, Mnemonic}; +use ffi::{ + Chain, Performance, RestoreParams, SeedPhrase, WalletEngine, WalletEvent, WalletListener, +}; + +struct PrintListener; +impl WalletListener for PrintListener { + fn on_event(&self, event: WalletEvent) { + println!("[event] {event:?}"); + } +} + +fn require_env(name: &str) -> String { + env::var(name).unwrap_or_else(|_| { + eprintln!("Missing required env var: {name}"); + eprintln!("Example:"); + eprintln!(" {name}=..."); + std::process::exit(2); + }) +} + +fn preflight(seed_words: &str, indexer_uri: &str) { + if let Err(e) = Mnemonic::::from_phrase(seed_words.to_string()) { + eprintln!("Invalid ZINGO_SEED mnemonic: {e}"); + std::process::exit(2); + } + + match indexer_uri.parse::() { + Ok(uri) => { + let scheme_ok = uri.scheme_str() == Some("http") || uri.scheme_str() == Some("https"); + let has_authority = uri.authority().is_some(); + if !scheme_ok || !has_authority { + eprintln!( + "Invalid ZINGO_INDEXER_URI='{indexer_uri}'. Expected http(s)://host:port" + ); + std::process::exit(2); + } + } + Err(e) => { + eprintln!("Invalid ZINGO_INDEXER_URI='{indexer_uri}': {e}"); + std::process::exit(2); + } + } +} + +pub fn main() { + let seed_words = require_env("ZINGO_SEED"); + let indexer_uri = require_env("ZINGO_INDEXER_URI"); + + let birthday = 1; + + let chain = Chain::Regtest; + + let perf = Performance::High; + + let minconf = 1; + + preflight(&seed_words, &indexer_uri); + + let engine = WalletEngine::new().expect("engine new"); + engine + .set_listener(Box::new(PrintListener)) + .expect("set listener"); + + engine + .init_from_seed(RestoreParams { + seed_phrase: SeedPhrase { words: seed_words }, + birthday, + indexer_uri, + chain, + perf, + minconf, + }) + .unwrap(); + + engine.start_sync().unwrap(); + std::thread::sleep(Duration::from_secs(20)); +} diff --git a/ffi/rust/src/lib.rs b/ffi/rust/src/lib.rs index 7314b67c9..1e8831b72 100644 --- a/ffi/rust/src/lib.rs +++ b/ffi/rust/src/lib.rs @@ -215,6 +215,7 @@ impl EngineInner { _ => 0, }; + // TODO: this should be a proper percentage, or should not exist let percent = if nh > 0 { (wh as f32 / nh as f32).clamp(0.0, 1.0) } else { From ec42df4826ba6169b4ed12aae99edcd5bfe29c28 Mon Sep 17 00:00:00 2001 From: dorianvp Date: Thu, 19 Feb 2026 22:23:58 -0300 Subject: [PATCH 11/15] chore: UFVK --- ffi/rust/examples/ufvk.rs | 51 +++++++++++++ ffi/rust/src/lib.rs | 156 +++++++++++++++++++++++++++++++++----- 2 files changed, 186 insertions(+), 21 deletions(-) create mode 100644 ffi/rust/examples/ufvk.rs diff --git a/ffi/rust/examples/ufvk.rs b/ffi/rust/examples/ufvk.rs new file mode 100644 index 000000000..4f0001367 --- /dev/null +++ b/ffi/rust/examples/ufvk.rs @@ -0,0 +1,51 @@ +use std::{env, time::Duration}; + +use ffi::{Chain, Performance, UFVKImportParams, WalletEngine, WalletEvent, WalletListener}; + +struct PrintListener; +impl WalletListener for PrintListener { + fn on_event(&self, event: WalletEvent) { + println!("[event] {event:?}"); + } +} + +fn require_env(name: &str) -> String { + env::var(name).unwrap_or_else(|_| { + eprintln!("Missing required env var: {name}"); + eprintln!("Example:"); + eprintln!(" {name}=..."); + std::process::exit(2); + }) +} + +pub fn main() { + let ufvk = require_env("ZINGO_UFVK"); + let indexer_uri = require_env("ZINGO_INDEXER_URI"); + + let birthday = 1; + + let chain = Chain::Regtest; + + let perf = Performance::High; + + let minconf = 1; + + let engine = WalletEngine::new().expect("engine new"); + engine + .set_listener(Box::new(PrintListener)) + .expect("set listener"); + + engine + .init_from_ufvk(UFVKImportParams { + ufvk: ufvk.to_string(), + birthday, + indexer_uri, + chain, + perf, + minconf, + }) + .unwrap(); + + engine.start_sync().unwrap(); + std::thread::sleep(Duration::from_secs(20)); +} diff --git a/ffi/rust/src/lib.rs b/ffi/rust/src/lib.rs index 1e8831b72..677f2fb3c 100644 --- a/ffi/rust/src/lib.rs +++ b/ffi/rust/src/lib.rs @@ -59,6 +59,16 @@ pub struct RestoreParams { pub minconf: u32, } +#[derive(Clone, Debug, uniffi::Record)] +pub struct UFVKImportParams { + pub ufvk: String, + pub birthday: u32, + pub indexer_uri: String, + pub chain: Chain, + pub perf: Performance, + pub minconf: u32, +} + #[derive(Clone, Debug, uniffi::Enum)] pub enum WalletEvent { EngineReady, @@ -112,15 +122,18 @@ struct EngineInner { } impl EngineInner { - pub(crate) async fn handle_start_sync_spawn(self: Arc, st: Arc>) { - let (lc, indexer_uri) = { - let mut s = st.lock().await; + pub(crate) async fn handle_start_sync_spawn( + self: Arc, + engine_state: Arc>, + ) { + let (lightclient, indexer_uri) = { + let mut state = engine_state.lock().await; - if s.syncing { + if state.syncing { return; } - let Some(lc) = s.lightclient.as_ref().cloned() else { + let Some(lc) = state.lightclient.as_ref().cloned() else { emit( &self, WalletEvent::Error { @@ -131,8 +144,8 @@ impl EngineInner { return; }; - s.syncing = true; - let indexer_uri = s.indexer_uri.clone(); + state.syncing = true; + let indexer_uri = state.indexer_uri.clone(); (lc, indexer_uri) }; @@ -141,12 +154,12 @@ impl EngineInner { // Spawn the sync loop so the command loop stays responsive. let inner = self.clone(); - let st_for_task = st.clone(); + let st_for_task = engine_state.clone(); let task = tokio::spawn(async move { // Kick off sync/resume with a short write-lock section. { - let mut guard = lc.write().await; + let mut guard = lightclient.write().await; if guard.sync_mode() == SyncMode::Paused { // TODO: Replace with resume_sync() when available. @@ -183,10 +196,10 @@ impl EngineInner { loop { // Read-only stuff - let (wh, poll, bal_opt) = { - let mut guard = lc.write().await; + let (highest_scanned_height, poll_report, balance_snapshot) = { + let mut guard = lightclient.write().await; - let wh = { + let wallet_height = { let w = guard.wallet.read().await; w.sync_state .highest_scanned_height() @@ -201,11 +214,11 @@ impl EngineInner { Err(_) => None, }; - (wh, poll, bal_opt) + (wallet_height, poll, bal_opt) }; // network height is independent of LightClient lock - let nh = match indexer_uri.as_ref() { + let network_height = match indexer_uri.as_ref() { Some(uri) if *uri != http::Uri::default() => { match zingolib::grpc_connector::get_latest_block(uri.clone()).await { Ok(b) => b.height as u32, @@ -216,8 +229,8 @@ impl EngineInner { }; // TODO: this should be a proper percentage, or should not exist - let percent = if nh > 0 { - (wh as f32 / nh as f32).clamp(0.0, 1.0) + let percent = if network_height > 0 { + (highest_scanned_height as f32 / network_height as f32).clamp(0.0, 1.0) } else { 0.0 }; @@ -225,20 +238,20 @@ impl EngineInner { emit( &inner, WalletEvent::SyncProgress { - wallet_height: wh, - network_height: nh, + wallet_height: highest_scanned_height, + network_height, percent, }, ); - if let Some(snap) = bal_opt { + if let Some(snap) = balance_snapshot { if last_balance_emitted.as_ref() != Some(&snap) { last_balance_emitted = Some(snap.clone()); emit(&inner, WalletEvent::BalanceChanged(snap)); } } - match poll { + match poll_report { PollReport::Ready(Ok(_)) => { emit(&inner, WalletEvent::SyncFinished); let mut s = st_for_task.lock().await; @@ -266,7 +279,7 @@ impl EngineInner { } }); - let mut s = st.lock().await; + let mut s = engine_state.lock().await; s.sync_task = Some(task); } @@ -347,6 +360,43 @@ impl EngineInner { let _ = reply.send(res); } + pub(crate) async fn handle_init_view_only( + &self, + st: &mut EngineState, + viewing_key: String, + birthday: u32, + indexer_uri: String, + chain: Chain, + perf: Performance, + minconf: u32, + reply: oneshot::Sender>, + ) { + let res: Result<(), WalletError> = (async { + let (config, lw_uri) = construct_config(indexer_uri, chain, perf, minconf)?; + + let wallet = LightWallet::new( + config.chain, + WalletBase::Ufvk(viewing_key), + BlockHeight::from_u32(birthday), + config.wallet_settings.clone(), + ) + .map_err(|e| WalletError::Internal(format!("LightWallet::new: {e}")))?; + + let lc = zingolib::lightclient::LightClient::create_from_wallet(wallet, config, false) + .map_err(|e| WalletError::Internal(format!("create_from_wallet: {e}")))?; + + st.lightclient = Some(Arc::new(RwLock::new(lc))); + st.indexer_uri = Some(lw_uri); + st.last_balance = None; + st.syncing = false; + st.sync_task = None; + Ok(()) + }) + .await; + + let _ = reply.send(res); + } + pub(crate) async fn handle_get_balance( &self, st: &mut EngineState, @@ -424,6 +474,7 @@ fn emit(inner: &EngineInner, event: WalletEvent) { } } +// TODO; Remove repetition!! enum Command { InitNew { indexer_uri: String, @@ -441,6 +492,15 @@ enum Command { minconf: u32, reply: oneshot::Sender>, }, + InitViewOnly { + viewing_key: String, // TODO: Use ViewingKeyType + birthday: u32, + indexer_uri: String, + chain: Chain, + perf: Performance, + minconf: u32, + reply: oneshot::Sender>, + }, GetBalance { reply: oneshot::Sender>, }, @@ -452,6 +512,16 @@ enum Command { Shutdown, } +enum ViewingKeyType { + Unified(UnifiedViewingKeyType), +} + +enum UnifiedViewingKeyType { + Full(String), + Incoming, + Outgoing, +} + #[derive(uniffi::Object, Clone)] pub struct WalletEngine { inner: Arc, @@ -542,6 +612,30 @@ impl WalletEngine { .await; } + Command::InitViewOnly { + viewing_key, + birthday, + indexer_uri, + chain, + perf, + minconf, + reply, + } => { + let mut guard = st.lock().await; + inner_for_task + .handle_init_view_only( + &mut guard, + viewing_key, + birthday, + indexer_uri, + chain, + perf, + minconf, + reply, + ) + .await; + } + Command::GetBalance { reply } => { let mut guard = st.lock().await; inner_for_task.handle_get_balance(&mut guard, reply).await; @@ -705,6 +799,26 @@ impl WalletEngine { .map_err(|_| WalletError::CommandQueueClosed)? } + pub fn init_from_ufvk(&self, params: UFVKImportParams) -> Result<(), WalletError> { + let (reply_tx, reply_rx) = oneshot::channel(); + self.inner + .cmd_tx + .blocking_send(Command::InitViewOnly { + viewing_key: params.ufvk, + birthday: params.birthday, + indexer_uri: params.indexer_uri, + chain: params.chain, + perf: params.perf, + minconf: params.minconf, + reply: reply_tx, + }) + .map_err(|_| WalletError::CommandQueueClosed)?; + + reply_rx + .blocking_recv() + .map_err(|_| WalletError::CommandQueueClosed)? + } + /// Returns a snapshot of the wallet balance for Account 0. /// /// The returned [`BalanceSnapshot`] is a simplified, FFI-stable view derived from the From d9c35a38b3505f1e9ff41228f758a6b2a7dbd39a Mon Sep 17 00:00:00 2001 From: dorianvp Date: Fri, 20 Feb 2026 00:02:57 -0300 Subject: [PATCH 12/15] chore: small fixes --- ffi/rust/src/lib.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/ffi/rust/src/lib.rs b/ffi/rust/src/lib.rs index 677f2fb3c..6ceef620e 100644 --- a/ffi/rust/src/lib.rs +++ b/ffi/rust/src/lib.rs @@ -493,7 +493,7 @@ enum Command { reply: oneshot::Sender>, }, InitViewOnly { - viewing_key: String, // TODO: Use ViewingKeyType + viewing_key: String, birthday: u32, indexer_uri: String, chain: Chain, @@ -512,16 +512,6 @@ enum Command { Shutdown, } -enum ViewingKeyType { - Unified(UnifiedViewingKeyType), -} - -enum UnifiedViewingKeyType { - Full(String), - Incoming, - Outgoing, -} - #[derive(uniffi::Object, Clone)] pub struct WalletEngine { inner: Arc, @@ -992,12 +982,10 @@ mod tests { .set_listener(Box::new(CapturingListener { tx })) .expect("set_listener"); - // EngineReady first let _ = recv_timeout(&rx, Duration::from_secs(2)); engine.start_sync().expect("start_sync send command"); - // Should emit error from engine thread loop { let ev = recv_timeout(&rx, Duration::from_secs(2)); match ev { From 7489daf00908b589f864af53e833a8e32e77c173 Mon Sep 17 00:00:00 2001 From: dorianvp Date: Fri, 20 Feb 2026 00:04:40 -0300 Subject: [PATCH 13/15] chore: ignore smoke tests --- ffi/rust/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ffi/rust/src/lib.rs b/ffi/rust/src/lib.rs index 6ceef620e..1458ed6d5 100644 --- a/ffi/rust/src/lib.rs +++ b/ffi/rust/src/lib.rs @@ -1034,6 +1034,7 @@ mod tests { /// Requires network up #[test] + #[ignore = "requires non-existing running regtest networkd"] fn real_sync_smoke() { let indexer_uri = "http://localhost:20956".to_string(); let chain = Chain::Regtest; @@ -1080,6 +1081,7 @@ mod tests { /// Run manually: /// cargo test -p ffi real_sync_progress_smoke -- --ignored --nocapture #[test] + #[ignore = "requires non-existing running regtest networkd"] fn real_sync_progress_smoke() { let indexer_uri = "http://localhost:20956".to_string(); let chain = Chain::Regtest; @@ -1179,6 +1181,7 @@ mod tests { /// This does NOT query latest block height externally. /// It relies purely on SyncProgress events emitted during each sync run. #[test] + #[ignore = "requires non-existing running regtest networkd"] fn real_sync_observe_5_new_block_heights_smoke() { use std::collections::BTreeSet; use std::sync::mpsc as std_mpsc; From 60e8a24d98e49aef41ff93aef40d2dca156b2165 Mon Sep 17 00:00:00 2001 From: dorianvp Date: Tue, 24 Feb 2026 12:56:41 -0300 Subject: [PATCH 14/15] chore: trait & tests --- Cargo.lock | 1 + ffi/rust/Cargo.toml | 1 + ffi/rust/src/lib.rs | 656 +++++++++++++++++++++++++++++++++--------- ffi/rust/src/state.rs | 49 +++- 4 files changed, 564 insertions(+), 143 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index db326a0fd..060cae2da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2164,6 +2164,7 @@ dependencies = [ name = "ffi" version = "0.0.0" dependencies = [ + "async-trait", "bip0039 0.13.4", "http", "pepper-sync", diff --git a/ffi/rust/Cargo.toml b/ffi/rust/Cargo.toml index 63cb26163..b2590cfc4 100644 --- a/ffi/rust/Cargo.toml +++ b/ffi/rust/Cargo.toml @@ -14,6 +14,7 @@ zingolib.workspace = true pepper-sync.workspace = true zingo_common_components = { workspace = true, features = ["for_test"] } http.workspace = true +async-trait = "0.1.89" [build-dependencies] uniffi = { version = "0.31", features = ["build"] } diff --git a/ffi/rust/src/lib.rs b/ffi/rust/src/lib.rs index 1458ed6d5..c4f1b0c4d 100644 --- a/ffi/rust/src/lib.rs +++ b/ffi/rust/src/lib.rs @@ -9,8 +9,10 @@ use std::{ time::Duration, }; +use async_trait::async_trait; + use bip0039::Mnemonic; -use pepper_sync::wallet::SyncMode; +use pepper_sync::{error::SyncError, sync::SyncResult, wallet::SyncMode}; use tokio::sync::{Mutex, RwLock, mpsc, oneshot}; use zcash_primitives::consensus::BlockHeight; use zcash_primitives::zip32::AccountId; @@ -92,6 +94,178 @@ pub trait WalletListener: Send + Sync { fn on_event(&self, event: WalletEvent); } +#[async_trait] +pub trait WalletBackend: Send + Sync { + /// Starts a sync run. + /// + /// This is expected to *kick off* syncing and return reasonably quickly. + /// It should **not** block until the sync is fully complete. + /// + /// Typical behavior: + /// - If the backend is currently paused, this should resume. + /// - If no sync is running, this should start a new one. + /// - If a sync is already running, this may return `Ok(())` (idempotent) or a + /// descriptive error string, depending on your policy. + /// + /// Errors: + /// - Returns `Err(String)` for backend-specific failures (e.g. cannot start sync, + /// bad internal state). + async fn start_sync(&self) -> Result<(), String>; + + /// Polls the status of the currently running sync task. + /// + /// This should be a *non-blocking* operation that reports progress/completion + /// for the sync started via [`WalletBackend::start_sync`]. + /// + /// The engine will typically call this on a timer (e.g. every 250ms) to drive + /// event emission: + /// - `PollReport::NotReady` → still syncing + /// - `PollReport::Ready(Ok(_))` → finished successfully + /// - `PollReport::Ready(Err(_))` → finished with error + /// - `PollReport::NoHandle` → no sync is currently running / nothing to poll + /// + /// Note: + /// - Even though this is `async`, implementations should keep it fast. Use a + /// short lock section if you must acquire interior mutability. + async fn poll_sync(&self) -> PollReport>; + + /// Requests that an in-progress sync pause. + /// + /// This is best-effort: depending on the backend, the sync may pause at the + /// next safe point, or it may complete before pausing. + /// + /// Typical behavior: + /// - If syncing is active, request a pause and return `Ok(())` if the request + /// was accepted. + /// - If no sync is running, this may return `Ok(())` or an error, depending on policy. + /// + /// Errors: + /// - Returns `Err(String)` for backend-specific failures (e.g. cannot pause). + async fn pause_sync(&self) -> Result<(), String>; + + /// Returns the current sync mode/state. + /// + /// This is used by the engine to determine whether a sync is paused vs running, + /// and to gate transitions (e.g. “start sync” may mean “resume”). + async fn sync_mode(&self) -> SyncMode; + + // data + async fn wallet_height(&self) -> u32; + async fn balance_snapshot(&self) -> Option; + async fn network_height(&self) -> u32; +} + +/// Zingolib-backed implementation. +/// Keeps all zingolib state behind async locks so engine can remain responsive. +pub struct ZingolibBackend { + lc: Arc>, + indexer_uri: http::Uri, +} + +impl ZingolibBackend { + pub fn new(lc: zingolib::lightclient::LightClient, indexer_uri: http::Uri) -> Self { + Self { + lc: Arc::new(RwLock::new(lc)), + indexer_uri, + } + } +} + +#[async_trait] +impl WalletBackend for ZingolibBackend { + async fn start_sync(&self) -> Result<(), String> { + let mut guard = self.lc.write().await; + + if guard.sync_mode() == SyncMode::Paused { + // TODO: replace with proper resume when available + guard.resume_sync().map_err(|e| e.to_string()) + } else { + guard.sync().await.map_err(|e| e.to_string()) + } + } + + async fn poll_sync(&self) -> PollReport> { + // poll_sync requires &mut self on LightClient + let mut guard = self.lc.write().await; + let return_value = guard.poll_sync(); + match return_value { + PollReport::NotReady => PollReport::NotReady, + PollReport::Ready(r) => match r { + Ok(r) => PollReport::Ready(Ok(r)), + Err(e) => { + let matched_error = match e { + SyncError::MempoolError(mempool_error) => { + WalletError::Internal(mempool_error.to_string()) + } + SyncError::ScanError(scan_error) => { + WalletError::Internal(scan_error.to_string()) + } + SyncError::ServerError(server_error) => { + WalletError::Internal(server_error.to_string()) + } + SyncError::SyncModeError(sync_mode_error) => { + WalletError::Internal(sync_mode_error.to_string()) + } + SyncError::ChainError(_, _, _) => { + WalletError::Internal("ChainError".to_string()) + } + SyncError::ShardTreeError(shard_tree_error) => { + WalletError::Internal(shard_tree_error.to_string()) + } + SyncError::TruncationError(_, _) => { + WalletError::Internal("TruncationError".to_string()) + } + SyncError::TransparentAddressDerivationError(error) => { + WalletError::Internal(error.to_string()) + } + SyncError::WalletError(e) => WalletError::Internal(e.to_string()), + }; + return PollReport::Ready(Err(pepper_sync::error::SyncError::WalletError( + matched_error, + ))); + } + }, + PollReport::NoHandle => PollReport::NoHandle, + } + } + + async fn pause_sync(&self) -> Result<(), String> { + let guard = self.lc.write().await; + guard.pause_sync().map_err(|e| e.to_string())?; + Ok(()) + } + + async fn sync_mode(&self) -> SyncMode { + let guard = self.lc.read().await; + guard.sync_mode() + } + + async fn wallet_height(&self) -> u32 { + let guard = self.lc.read().await; + let w = guard.wallet.read().await; + w.sync_state + .highest_scanned_height() + .map(u32::from) + .unwrap_or(0) + } + + async fn balance_snapshot(&self) -> Option { + let guard = self.lc.read().await; + guard + .account_balance(AccountId::ZERO) + .await + .ok() + .map(|b| balance_snapshot_from_balance(&b)) + } + + async fn network_height(&self) -> u32 { + zingolib::grpc_connector::get_latest_block(self.indexer_uri.clone()) + .await + .map(|b| b.height as u32) + .unwrap_or(0) + } +} + fn balance_snapshot_from_balance(b: &AccountBalance) -> BalanceSnapshot { let confirmed = b .confirmed_orchard_balance @@ -126,14 +300,14 @@ impl EngineInner { self: Arc, engine_state: Arc>, ) { - let (lightclient, indexer_uri) = { + let backend = { let mut state = engine_state.lock().await; if state.syncing { return; } - let Some(lc) = state.lightclient.as_ref().cloned() else { + let Some(backend) = state.backend.as_ref().cloned() else { emit( &self, WalletEvent::Error { @@ -145,92 +319,43 @@ impl EngineInner { }; state.syncing = true; - let indexer_uri = state.indexer_uri.clone(); - - (lc, indexer_uri) + backend }; emit(&self, WalletEvent::SyncStarted); - // Spawn the sync loop so the command loop stays responsive. let inner = self.clone(); let st_for_task = engine_state.clone(); let task = tokio::spawn(async move { - // Kick off sync/resume with a short write-lock section. - { - let mut guard = lightclient.write().await; - - if guard.sync_mode() == SyncMode::Paused { - // TODO: Replace with resume_sync() when available. - if let Err(e) = guard.pause_sync() { - emit( - &inner, - WalletEvent::Error { - code: "start_sync_failed".into(), - message: format!("resume_sync: {e}"), - }, - ); - let mut s = st_for_task.lock().await; - s.syncing = false; - return; - } - } else { - // TODO: Thisassumes sync() starts the background sync and returns reasonably quickly. - if let Err(e) = guard.sync().await { - emit( - &inner, - WalletEvent::Error { - code: "sync_failed".into(), - message: e.to_string(), - }, - ); - let mut s = st_for_task.lock().await; - s.syncing = false; - return; - } - } + if let Err(e) = backend.start_sync().await { + emit( + &inner, + WalletEvent::Error { + code: "sync_failed".into(), + message: e, + }, + ); + let mut s = st_for_task.lock().await; + s.syncing = false; + return; } let mut last_balance_emitted: Option = None; loop { - // Read-only stuff - let (highest_scanned_height, poll_report, balance_snapshot) = { - let mut guard = lightclient.write().await; - - let wallet_height = { - let w = guard.wallet.read().await; - w.sync_state - .highest_scanned_height() - .map(u32::from) - .unwrap_or(0) - }; - - let poll = guard.poll_sync(); - - let bal_opt = match guard.account_balance(AccountId::ZERO).await { - Ok(bal) => Some(balance_snapshot_from_balance(&bal)), - Err(_) => None, - }; - - (wallet_height, poll, bal_opt) - }; + if backend.sync_mode().await == SyncMode::Paused { + emit(&inner, WalletEvent::SyncPaused); + let mut s = st_for_task.lock().await; + s.syncing = false; + break; + } - // network height is independent of LightClient lock - let network_height = match indexer_uri.as_ref() { - Some(uri) if *uri != http::Uri::default() => { - match zingolib::grpc_connector::get_latest_block(uri.clone()).await { - Ok(b) => b.height as u32, - Err(_) => 0, - } - } - _ => 0, - }; + let wallet_height = backend.wallet_height().await; + let network_height = backend.network_height().await; - // TODO: this should be a proper percentage, or should not exist let percent = if network_height > 0 { - (highest_scanned_height as f32 / network_height as f32).clamp(0.0, 1.0) + (wallet_height as f32 / network_height as f32).clamp(0.0, 1.0) } else { 0.0 }; @@ -238,20 +363,20 @@ impl EngineInner { emit( &inner, WalletEvent::SyncProgress { - wallet_height: highest_scanned_height, + wallet_height, network_height, percent, }, ); - if let Some(snap) = balance_snapshot { + if let Some(snap) = backend.balance_snapshot().await { if last_balance_emitted.as_ref() != Some(&snap) { last_balance_emitted = Some(snap.clone()); emit(&inner, WalletEvent::BalanceChanged(snap)); } } - match poll_report { + match backend.poll_sync().await { PollReport::Ready(Ok(_)) => { emit(&inner, WalletEvent::SyncFinished); let mut s = st_for_task.lock().await; @@ -270,9 +395,7 @@ impl EngineInner { s.syncing = false; break; } - PollReport::NotReady | PollReport::NoHandle => { - // still running - } + PollReport::NotReady | PollReport::NoHandle => {} } tokio::time::sleep(Duration::from_millis(250)).await; @@ -305,11 +428,7 @@ impl EngineInner { let lc = zingolib::lightclient::LightClient::new(config, birthday, false) .map_err(|e| WalletError::Internal(format!("LightClient::new: {e}")))?; - st.lightclient = Some(Arc::new(RwLock::new(lc))); - st.indexer_uri = Some(lw_uri); - st.last_balance = None; - st.syncing = false; - st.sync_task = None; + st.set_backend(Arc::new(ZingolibBackend::new(lc, lw_uri))); Ok(()) }) .await; @@ -348,11 +467,7 @@ impl EngineInner { let lc = zingolib::lightclient::LightClient::create_from_wallet(wallet, config, false) .map_err(|e| WalletError::Internal(format!("create_from_wallet: {e}")))?; - st.lightclient = Some(Arc::new(RwLock::new(lc))); - st.indexer_uri = Some(lw_uri); - st.last_balance = None; - st.syncing = false; - st.sync_task = None; + st.set_backend(Arc::new(ZingolibBackend::new(lc, lw_uri))); Ok(()) }) .await; @@ -385,11 +500,7 @@ impl EngineInner { let lc = zingolib::lightclient::LightClient::create_from_wallet(wallet, config, false) .map_err(|e| WalletError::Internal(format!("create_from_wallet: {e}")))?; - st.lightclient = Some(Arc::new(RwLock::new(lc))); - st.indexer_uri = Some(lw_uri); - st.last_balance = None; - st.syncing = false; - st.sync_task = None; + st.set_backend(Arc::new(ZingolibBackend::new(lc, lw_uri))); Ok(()) }) .await; @@ -399,24 +510,17 @@ impl EngineInner { pub(crate) async fn handle_get_balance( &self, - st: &mut EngineState, + backend: Option>, reply: oneshot::Sender>, ) { - let res: Result = (async { - let lc = st - .lightclient - .as_ref() - .ok_or(WalletError::NotInitialized)? - .clone(); - - let guard = lc.read().await; - let bal = guard - .account_balance(AccountId::ZERO) - .await - .map_err(|e| WalletError::Internal(format!("account_balance: {e}")))?; + let res: Result = async { + let backend = backend.ok_or(WalletError::NotInitialized)?; - Ok(balance_snapshot_from_balance(&bal)) - }) + backend + .balance_snapshot() + .await + .ok_or_else(|| WalletError::Internal("balance unavailable".into())) + } .await; let _ = reply.send(res); @@ -424,23 +528,20 @@ impl EngineInner { pub(crate) async fn handle_get_network_height( &self, - st: &mut EngineState, + backend: Option>, reply: oneshot::Sender>, ) { - let res: Result = (async { - let uri = st.indexer_uri.clone().ok_or(WalletError::NotInitialized)?; - let b = zingolib::grpc_connector::get_latest_block(uri) - .await - .map_err(|e| WalletError::Internal(format!("get_latest_block: {e}")))?; - Ok(b.height as u32) - }) + let res: Result = async { + let backend = backend.ok_or(WalletError::NotInitialized)?; + Ok(backend.network_height().await) + } .await; let _ = reply.send(res); } - pub(crate) async fn handle_pause_sync(&self, st: &mut EngineState) { - let Some(lc) = st.lightclient.as_ref().cloned() else { + pub(crate) async fn handle_pause_sync(&self, backend: Option>) { + let Some(backend) = backend else { emit( self, WalletEvent::Error { @@ -451,14 +552,13 @@ impl EngineInner { return; }; - let guard = lc.write().await; - match guard.pause_sync() { + match backend.pause_sync().await { Ok(_) => emit(self, WalletEvent::SyncPaused), Err(e) => emit( self, WalletEvent::Error { code: "pause_sync_failed".into(), - message: e.to_string(), + message: e, }, ), } @@ -627,14 +727,21 @@ impl WalletEngine { } Command::GetBalance { reply } => { - let mut guard = st.lock().await; - inner_for_task.handle_get_balance(&mut guard, reply).await; + // TODO: Make this all less repetitive/convoluted + let backend = { + let guard = st.lock().await; + guard.backend.clone() + }; + inner_for_task.handle_get_balance(backend, reply).await; } Command::GetNetworkHeight { reply } => { - let mut guard = st.lock().await; + let backend = { + let guard = st.lock().await; + guard.backend.clone() + }; inner_for_task - .handle_get_network_height(&mut guard, reply) + .handle_get_network_height(backend, reply) .await; } @@ -646,8 +753,11 @@ impl WalletEngine { } Command::PauseSync => { - let mut guard = st.lock().await; - inner_for_task.handle_pause_sync(&mut guard).await; + let backend = { + let guard = st.lock().await; + guard.backend.clone() + }; + inner_for_task.handle_pause_sync(backend).await; } Command::Shutdown => break, @@ -926,6 +1036,13 @@ mod tests { use super::*; use std::sync::mpsc as std_mpsc; + /// Test-only listener that forwards every [`WalletEvent`] it receives into a + /// standard-library `mpsc` channel. + /// + /// This is used in unit tests to: + /// - observe asynchronous events emitted by the engine thread + /// - make assertions about ordering (e.g. `EngineReady` then `SyncStarted`) + /// - avoid blocking the engine thread (sending into `std::sync::mpsc::Sender` is fast) #[derive(Clone)] struct CapturingListener { tx: std_mpsc::Sender, @@ -946,6 +1063,289 @@ mod tests { } } + mod fake_backend_tests { + use std::{ + sync::{ + Arc, + atomic::{AtomicUsize, Ordering}, + }, + thread, + time::{Duration, Instant}, + }; + + use async_trait::async_trait; + use pepper_sync::{error::SyncError, sync::SyncResult, wallet::SyncMode}; + use tokio::sync::{Mutex, mpsc}; + use zingolib::data::PollReport; + + use crate::{ + BalanceSnapshot, Command, EngineInner, WalletBackend, WalletEngine, WalletEvent, + create_engine_runtime, emit, + error::WalletError, + state::EngineState, + tests::{CapturingListener, recv_timeout}, + }; + + struct FakeBackend { + start_sync_calls: AtomicUsize, + poll_calls: AtomicUsize, + balance_calls: AtomicUsize, + wallet_height: AtomicUsize, + network_height: AtomicUsize, + } + + impl FakeBackend { + fn new() -> Self { + Self { + start_sync_calls: AtomicUsize::new(0), + poll_calls: AtomicUsize::new(0), + balance_calls: AtomicUsize::new(0), + wallet_height: AtomicUsize::new(100), + network_height: AtomicUsize::new(200), + } + } + + fn start_sync_call_count(&self) -> usize { + self.start_sync_calls.load(Ordering::SeqCst) + } + } + + #[async_trait] + impl WalletBackend for FakeBackend { + async fn start_sync(&self) -> Result<(), String> { + self.start_sync_calls.fetch_add(1, Ordering::SeqCst); + Ok(()) + } + + async fn poll_sync(&self) -> PollReport> { + self.poll_calls.fetch_add(1, Ordering::SeqCst); + + // Keep the sync task "alive" but always yielding. + tokio::time::sleep(Duration::from_millis(25)).await; + + // Never finish; this is enough to prove responsiveness while "syncing". + PollReport::NotReady + } + + async fn pause_sync(&self) -> Result<(), String> { + Ok(()) + } + + async fn sync_mode(&self) -> SyncMode { + // We only need "not paused" for the engine loop to keep going. + // In production backends, this is a real mode. + // + // For tests, we avoid relying on non-Paused enum variant names (which may change) + // by using an unsafe transmute to "some other variant". + // + // SAFETY: this is test-only code; any mismatch just fails the test build. + #[allow(unsafe_code)] + unsafe { + // Choose a discriminant different than the one for `Paused`. + // This assumes `Paused` is not discriminant 0; if it is, swap 0/1. + // If this ever breaks, just update the number to match pepper_sync. + std::mem::transmute::(0) + } + } + + async fn wallet_height(&self) -> u32 { + self.wallet_height.load(Ordering::SeqCst) as u32 + } + + async fn balance_snapshot(&self) -> Option { + self.balance_calls.fetch_add(1, Ordering::SeqCst); + + // Fast path: returns immediately (this is what we want to verify is reachable + // while sync is running). + Some(BalanceSnapshot { + confirmed: "1".to_string(), + total: "2".to_string(), + }) + } + + async fn network_height(&self) -> u32 { + self.network_height.load(Ordering::SeqCst) as u32 + } + } + + fn spawn_test_engine_with_backend( + backend: Arc, + ) -> (WalletEngine, std::sync::mpsc::Receiver) { + let (cmd_tx, mut cmd_rx) = mpsc::channel::(64); + + let inner = Arc::new(EngineInner { + cmd_tx, + listener: std::sync::Mutex::new(None), + }); + + let engine = WalletEngine { + inner: inner.clone(), + }; + + let (ev_tx, ev_rx) = std::sync::mpsc::channel(); + engine + .set_listener(Box::new(CapturingListener { tx: ev_tx })) + .expect("set_listener"); + + thread::spawn(move || { + let rt = create_engine_runtime(); + rt.block_on(async move { + emit(&inner, WalletEvent::EngineReady); + + let st = Arc::new(Mutex::new(EngineState::new())); + + // IMPORTANT: do NOT use blocking_lock() inside runtime + { + let mut guard = st.lock().await; + guard.backend = Some(backend); + } + + while let Some(cmd) = cmd_rx.recv().await { + let backend = { + let guard = st.lock().await; + guard.backend.clone() + }; + match cmd { + Command::GetBalance { reply } => { + inner.handle_get_balance(backend, reply).await; + } + Command::GetNetworkHeight { reply } => { + inner.handle_get_network_height(backend, reply).await; + } + Command::StartSync => { + inner.clone().handle_start_sync_spawn(st.clone()).await; + } + Command::PauseSync => { + inner.handle_pause_sync(backend).await; + } + Command::Shutdown => break, + + // In this helper, init commands are disabled. + Command::InitNew { reply, .. } + | Command::InitFromSeed { reply, .. } + | Command::InitViewOnly { reply, .. } => { + let _ = reply.send(Err(WalletError::Internal( + "init disabled in fake backend tests".into(), + ))); + } + } + } + }); + }); + + (engine, ev_rx) + } + + /// Proves: starting sync does NOT make the engine loop unusable. + /// + /// Specifically: while the spawned sync task is running (and continuously polling), + /// we can still call get_balance_snapshot() and get an answer quickly. + #[test] + fn sync_does_not_block_get_balance_snapshot() { + let fake = Arc::new(FakeBackend::new()); + let (engine, rx) = spawn_test_engine_with_backend(fake); + + // EngineReady + let ev = recv_timeout(&rx, Duration::from_secs(2)); + assert!(matches!(ev, WalletEvent::EngineReady), "got: {ev:?}"); + + engine.start_sync().expect("start_sync"); + + // SyncStarted + let ev = recv_timeout(&rx, Duration::from_secs(2)); + assert!(matches!(ev, WalletEvent::SyncStarted), "got: {ev:?}"); + + // Hammer balance while sync loop is active. + for i in 0..30 { + let t0 = Instant::now(); + let bal = engine.get_balance_snapshot().expect("balance snapshot"); + let dt = t0.elapsed(); + + assert_eq!(bal.confirmed, "1"); + assert_eq!(bal.total, "2"); + + // Thread hop and oneshot should stay well under this. + assert!( + dt < Duration::from_millis(150), + "get_balance_snapshot call {i} too slow: {dt:?} (sync may be blocking)" + ); + + // small sleep so we interleave with poll ticks (is this truly necessary though?) + std::thread::sleep(Duration::from_millis(10)); + } + + engine.shutdown().ok(); + } + + /// Proves: StartSync is re-entrancy protected (second call is ignored while syncing=true). + /// + /// This also indirectly proves the command loop remains responsive enough to *process* + /// multiple StartSync commands while a sync task is running. + #[test] + fn start_sync_is_idempotent_while_running() { + let fake = Arc::new(FakeBackend::new()); + let (engine, rx) = spawn_test_engine_with_backend(fake.clone()); + + let _ = recv_timeout(&rx, Duration::from_secs(2)); // EngineReady + + engine.start_sync().expect("start_sync #1"); + let ev = recv_timeout(&rx, Duration::from_secs(2)); + assert!(matches!(ev, WalletEvent::SyncStarted), "got: {ev:?}"); + + // Should be ignored. Should not emit SyncStarted. TODO: how can we assert that? + engine.start_sync().expect("start_sync #2"); + + // Give a little time for command loop + potential bogus second start + std::thread::sleep(Duration::from_millis(200)); + + assert_eq!( + fake.start_sync_call_count(), + 1, + "backend.start_sync() was called more than once; StartSync was not guarded by syncing flag" + ); + + engine.shutdown().ok(); + } + + /// Proves that while sync task is running we still see progress events, + /// indicating the runtime is scheduling both the sync task and the command loop. + #[test] + fn sync_task_runs_concurrently_with_command_loop() { + let fake_backend = Arc::new(FakeBackend::new()); + let (engine, rx) = spawn_test_engine_with_backend(fake_backend); + + let _ = recv_timeout(&rx, Duration::from_secs(2)); // EngineReady + + engine.start_sync().expect("start_sync"); + let event = recv_timeout(&rx, Duration::from_secs(2)); + assert!(matches!(event, WalletEvent::SyncStarted), "got: {event:?}"); + + // We should see at least one SyncProgress fairly soon. + // (FakeBackend.poll_sync sleeps 25ms and returns NotReady, so engine loop should emit progress regularly.) + let deadline = Instant::now() + Duration::from_secs(2); + let mut saw_progress = false; + + while Instant::now() < deadline { + let ev = recv_timeout(&rx, Duration::from_millis(250)); + if matches!(ev, WalletEvent::SyncProgress { .. }) { + saw_progress = true; + break; + } + } + + assert!( + saw_progress, + "never saw SyncProgress while sync task running" + ); + + // While progress events are flowing, also do a balance call to ensure the engine loop services commands. + let bal = engine.get_balance_snapshot().expect("balance snapshot"); + assert_eq!(bal.total, "2"); + + engine.shutdown().ok(); + } + } + fn recv_timeout(rx: &std_mpsc::Receiver, dur: Duration) -> WalletEvent { rx.recv_timeout(dur).expect("timeout waiting for event") } diff --git a/ffi/rust/src/state.rs b/ffi/rust/src/state.rs index 92a2bf08e..0a3762028 100644 --- a/ffi/rust/src/state.rs +++ b/ffi/rust/src/state.rs @@ -3,32 +3,51 @@ use std::sync::Arc; use tokio::{sync::RwLock, task::JoinHandle}; use zingolib::lightclient::LightClient; -use crate::BalanceSnapshot; +use crate::{BalanceSnapshot, WalletBackend, ZingolibBackend}; pub(crate) struct EngineState { - // TODO: add more documentation - /// `LightClient` lives behind an async RW lock so that sync only takes the lock when starting - /// pausing or stopping, and so that read-only calls (like getting the wallet's balance and - /// fetching the chain height) can use a read lock. - pub(crate) lightclient: Option>>, - pub(crate) indexer_uri: Option, - - pub(crate) syncing: bool, - pub(crate) sync_task: Option>, - - pub(crate) last_balance: Option, + pub backend: Option>, + pub syncing: bool, + pub sync_task: Option>, + pub last_balance: Option, } impl EngineState { + /// Fresh engine state with no wallet loaded yet. + /// + /// Call `init_new/init_from_seed/init_from_ufvk` to install a real backend later. pub(crate) fn new() -> Self { Self { - lightclient: None, - indexer_uri: None, - + backend: None, syncing: false, sync_task: None, + last_balance: None, + } + } + /// Convenience constructor that injects a backend directly. + pub(crate) fn with_backend(backend: Arc) -> Self { + Self { + backend: Some(backend), + syncing: false, + sync_task: None, last_balance: None, } } + + /// Replace any existing backend. + pub(crate) fn set_backend(&mut self, backend: Arc) { + self.backend = Some(backend); + self.last_balance = None; + self.syncing = false; + self.sync_task = None; + } + + /// Clear the backend. + pub(crate) fn clear_backend(&mut self) { + self.backend = None; + self.last_balance = None; + self.syncing = false; + self.sync_task = None; + } } From af7af29d38e89688e931b873563f8fd3a2214814 Mon Sep 17 00:00:00 2001 From: dorianvp Date: Tue, 24 Feb 2026 13:07:11 -0300 Subject: [PATCH 15/15] chore: add new error --- ffi/rust/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ffi/rust/src/lib.rs b/ffi/rust/src/lib.rs index c4f1b0c4d..5c91ef4c7 100644 --- a/ffi/rust/src/lib.rs +++ b/ffi/rust/src/lib.rs @@ -219,6 +219,9 @@ impl WalletBackend for ZingolibBackend { WalletError::Internal(error.to_string()) } SyncError::WalletError(e) => WalletError::Internal(e.to_string()), + SyncError::BirthdayBelowSapling(_, _) => { + WalletError::Internal("BirthdayBelowSapling".to_string()) + } }; return PollReport::Ready(Err(pepper_sync::error::SyncError::WalletError( matched_error,