diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..79ab70b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,51 @@ +name: CI + +on: + push: + branches: [ main, "**" ] + pull_request: + branches: [ main ] + +jobs: + build-and-test: + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Setup Dart + uses: dart-lang/setup-dart@v1 + + - name: Install lipo (macOS) + if: matrix.os == 'macos-latest' + run: | + which lipo || echo 'lipo available in Xcode toolchain' + + - name: Generate bindings and native library + run: | + chmod +x scripts/generate_bindings.sh + ./scripts/generate_bindings.sh + + - name: Ensure generated bindings exist + run: test -f lib/bdk.dart + + - name: Pub get + run: dart pub get + + - name: Format check + run: dart format --output=none --set-exit-if-changed . + + - name: Analyze + run: dart analyze --fatal-infos --fatal-warnings + + - name: Run tests + run: | + dart test diff --git a/.gitignore b/.gitignore index dc44a2e..cde80cf 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,10 @@ Cargo.lock Thumbs.db # Logs -*.log \ No newline at end of file +*.log + +# Native libs built locally +libbdkffi.* +test_output.txt +test output.txt +lib/bdk.dart diff --git a/.gitmodules b/.gitmodules index 5c6f24c..c582725 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "uniffi-dart"] - path = uniffi-dart - url = https://github.com/NiallBunting/uniffi-rs-dart.git [submodule "bdk-ffi"] path = bdk-ffi url = https://github.com/bitcoindevkit/bdk-ffi.git diff --git a/Cargo.toml b/Cargo.toml index e1243a9..021c3ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ license = "MIT OR Apache-2.0" [lib] crate-type = ["lib", "staticlib", "cdylib"] name = "bdkffi" +path = "bdk-ffi/bdk-ffi/src/lib.rs" [[bin]] name = "uniffi-bindgen" @@ -18,19 +19,21 @@ path = "uniffi-bindgen.rs" default = ["uniffi/cli"] [dependencies] -bdk_wallet = { version = "2.0.0", features = ["all-keys", "keys-bip39", "rusqlite"] } -bdk_esplora = { version = "0.22.0", default-features = false, features = ["std", "blocking", "blocking-https-rustls"] } -bdk_electrum = { version = "0.23.0", default-features = false, features = ["use-rustls-ring"] } -bdk_kyoto = { version = "0.13.1" } +bdk_wallet = { version = "2.2.0", features = ["all-keys", "keys-bip39", "rusqlite"] } +bdk_esplora = { version = "0.22.1", default-features = false, features = ["std", "blocking", "blocking-https-rustls"] } +bdk_electrum = { version = "0.23.2", default-features = false, features = ["use-rustls-ring"] } +bdk_kyoto = { version = "0.15.1" } -uniffi = { version = "=0.29.1" } -thiserror = "1.0.58" +uniffi = { version = "=0.29.4" } +uniffi-dart = { git = "https://github.com/Uniffi-Dart/uniffi-dart.git", rev = "946c5642c0521a184c4b52dcf0d203edb97f1ffc" } +thiserror = "1.0.65" [build-dependencies] -uniffi = { version = "=0.29.1", features = ["build"] } +uniffi = { version = "=0.29.4", features = ["build"] } +uniffi-dart = { git = "https://github.com/Uniffi-Dart/uniffi-dart.git", rev = "946c5642c0521a184c4b52dcf0d203edb97f1ffc", features = ["build"] } [dev-dependencies] -uniffi = { version = "=0.29.1", features = ["bindgen-tests"] } +uniffi = { version = "=0.29.4", features = ["bindgen-tests"] } assert_matches = "1.5.0" [profile.release-smaller] @@ -39,4 +42,4 @@ opt-level = 'z' # Optimize for size. lto = true # Enable Link Time Optimization codegen-units = 1 # Reduce number of codegen units to increase optimizations. panic = "abort" # Abort on panic -strip = "debuginfo" # Partially strip symbols from binary \ No newline at end of file +strip = "debuginfo" # Partially strip symbols from binary diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..9171dd2 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,4 @@ +analyzer: + exclude: + - lib/bdk.dart + diff --git a/bdk-ffi b/bdk-ffi index c8d08e9..2b5a6d7 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit c8d08e9061b50bae139016243706d880687d748b +Subproject commit 2b5a6d791de418b3827c6cab09314e7a34b8a99c diff --git a/build.rs b/build.rs deleted file mode 100644 index 4fc3442..0000000 --- a/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - uniffi::generate_scaffolding("./src/simple_bdk.udl").unwrap(); -} \ No newline at end of file diff --git a/dart_bindings/bdk.dart b/dart_bindings/bdk.dart deleted file mode 100644 index f4b6da0..0000000 --- a/dart_bindings/bdk.dart +++ /dev/null @@ -1,1581 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! -// -// Common helper code. -// -// Ideally this would live in a separate .dart file where it can be unittested etc -// in isolation, and perhaps even published as a re-useable package. -// -// However, it's important that the details of how this helper code works (e.g. the -// way that different builtin types are passed across the FFI) exactly match what's -// expected by the rust code on the other side of the interface. In practice right -// now that means coming from the exact some version of `uniffi` that was used to -// compile the rust component. The easiest way to ensure this is to bundle the Python -// helpers directly inline like we're doing here. - -import 'dart:ffi'; -import 'package:ffi/ffi.dart'; -import 'dart:io'; -import 'dart:async'; -import 'package:mutex/mutex.dart'; -import 'dart:typed_data'; - -// Used for default argument values -//_DEFAULT = object() - - -final class _UniffiRustBuffer extends Struct { - @Uint32() - external int capacity; - - @Uint32() - external int len; - - external Pointer data; - - _UniffiRustBufferBuilder get buffer => _UniffiRustBufferBuilder.fromStrData(data, len); -} - -//class _UniffiForeignBytes(ctypes.Structure): -// _fields_ = [ -// ("len", ctypes.c_int32), -// ("data", ctypes.POINTER(ctypes.c_char)), -// ] -// -// def __str__(self): -// return "_UniffiForeignBytes(len={}, data={})".format(self.len, self.data[0:self.len]) -// -// -//class _UniffiRustBufferStream { -// Pointer pointer; -// int length; -// -// _UniffiRustBufferStream(this.pointer, this.length); -// -//} -// """ -// Helper for structured reading of bytes from a _UniffiRustBuffer -// """ -// -// def __init__(self, data, len): -// self.data = data -// self.len = len -// self.offset = 0 -// -// @classmethod -// def from_rust_buffer(cls, buf): -// return cls(buf.data, buf.len) -// -// def remaining(self): -// return self.len - self.offset -// -// def _unpack_from(self, size, format): -// if self.offset + size > self.len: -// raise InternalError("read past end of rust buffer") -// value = struct.unpack(format, self.data[self.offset:self.offset+size])[0] -// self.offset += size -// return value -// -// def read(self, size): -// if self.offset + size > self.len: -// raise InternalError("read past end of rust buffer") -// data = self.data[self.offset:self.offset+size] -// self.offset += size -// return data -// -// def read_i8(self): -// return self._unpack_from(1, ">b") -// -// def read_u8(self): -// return self._unpack_from(1, ">B") -// -// def read_i16(self): -// return self._unpack_from(2, ">h") -// -// def read_u16(self): -// return self._unpack_from(2, ">H") -// -// def read_i32(self): -// return self._unpack_from(4, ">i") -// -// def read_u32(self): -// return self._unpack_from(4, ">I") -// -// def read_i64(self): -// return self._unpack_from(8, ">q") -// -// def read_u64(self): -// return self._unpack_from(8, ">Q") -// -// def read_float(self): -// v = self._unpack_from(4, ">f") -// return v -// -// def read_double(self): -// return self._unpack_from(8, ">d") -// -// def read_c_size_t(self): -// return self._unpack_from(ctypes.sizeof(ctypes.c_size_t) , "@N") -// -class _UniffiRustBufferBuilder { - - late ByteData buffer; - late int len; - int offset = 0; - - _UniffiRustBufferBuilder([int len = 16]) { - this.offset = 0; - this.buffer = ByteData(len); - this.len = len; - } - - _UniffiRustBufferBuilder.fromData(Pointer data, int len) { - this.offset = 0; - this.len = len; - this.buffer = data.asTypedList(len).buffer.asByteData(0); - } - - _UniffiRustBufferBuilder.fromStrData(Pointer data, int len) { - this.offset = 0; - this.len = len; - this.buffer = data.cast().asTypedList(len).buffer.asByteData(0); - } - - int get length => offset; - - Pointer toNativeUtf8() { - final uint8List = buffer.buffer.asUint8List(); - final result = calloc(this.offset); - - for (var i = 0; i < this.offset; ++i) { - result[i] = uint8List[i]; - } - - return result.cast(); - } - - String toDartString(int? size) { - int end = len; - if (size != null) { - end = offset + size; - if (end > len) { - throw "Longer than string"; - } - } - - var sublist = Uint8List.sublistView(buffer, offset, end); - - offset = end; - return String.fromCharCodes(sublist); - - } - - _unpack() { - - } - - read_u8() { - if (this.offset + 1 > this.len) { - throw "Not enough bytes."; - } - var retVal = buffer.getUint8(this.offset); - this.offset += 1; - return retVal; - } - - write_u8(value) { - if (this.offset + 1 > this.len) { - throw "Not enough bytes."; - } - buffer.setUint8(this.offset, value); - this.offset += 1; - } - - read_i32() { - if (this.offset + 4 > this.len) { - throw "Not enough bytes."; - } - var retVal = buffer.getInt32(this.offset, Endian.big); - this.offset += 4; - return retVal; - } - - write_i32(value) { - if (this.offset + 4 > this.len) { - throw "Not enough bytes."; - } - buffer.setInt32(this.offset, value, Endian.big); - this.offset += 4; - } - - read_u16() { - if (this.offset + 2 > this.len) { - throw "Not enough bytes."; - } - var retVal = buffer.getUint16(this.offset, Endian.big); - this.offset += 2; - return retVal; - } - - write_u16(value) { - if (this.offset + 2 > this.len) { - throw "Not enough bytes."; - } - buffer.setUint16(this.offset, value, Endian.big); - this.offset += 2; - } - - read_u32() { - if (this.offset + 4 > this.len) { - throw "Not enough bytes."; - } - var retVal = buffer.getUint32(this.offset, Endian.big); - this.offset += 4; - return retVal; - } - - read_u64() { - if (this.offset + 8 > this.len) { - throw "Not enough bytes."; - } - var retVal = buffer.getUint64(this.offset, Endian.big); - this.offset += 8; - return retVal; - } - - read_i64() { - if (this.offset + 8 > this.len) { - throw "Not enough bytes."; - } - var retVal = buffer.getInt64(this.offset, Endian.big); - this.offset += 8; - return retVal; - } - - read_double() { - if (this.offset + 8 > this.len) { - throw "Not enough bytes."; - } - var retVal = buffer.getFloat64(this.offset, Endian.big); - this.offset += 8; - return retVal; - } -} -// """ -// Helper for structured writing of bytes into a _UniffiRustBuffer. -// """ -// -// def __init__(self): -// self.rbuf = _UniffiRustBuffer.alloc(16) -// self.rbuf.len = 0 -// -// def finalize(self): -// rbuf = self.rbuf -// self.rbuf = None -// return rbuf -// -// def discard(self): -// if self.rbuf is not None: -// rbuf = self.finalize() -// rbuf.free() -// -// @contextlib.contextmanager -// def _reserve(self, num_bytes): -// if self.rbuf.len + num_bytes > self.rbuf.capacity: -// self.rbuf = _UniffiRustBuffer.reserve(self.rbuf, num_bytes) -// yield None -// self.rbuf.len += num_bytes -// -// def _pack_into(self, size, format, value): -// with self._reserve(size): -// # XXX TODO: I feel like I should be able to use `struct.pack_into` here but can't figure it out. -// for i, byte in enumerate(struct.pack(format, value)): -// self.rbuf.data[self.rbuf.len + i] = byte -// -// def write(self, value): -// with self._reserve(len(value)): -// for i, byte in enumerate(value): -// self.rbuf.data[self.rbuf.len + i] = byte -// -// def write_i8(self, v): -// self._pack_into(1, ">b", v) -// -// def write_u8(self, v): -// self._pack_into(1, ">B", v) -// -// def write_i16(self, v): -// self._pack_into(2, ">h", v) -// -// def write_u16(self, v): -// self._pack_into(2, ">H", v) -// -// def write_i32(self, v): -// self._pack_into(4, ">i", v) -// -// def write_u32(self, v): -// self._pack_into(4, ">I", v) -// -// def write_i64(self, v): -// self._pack_into(8, ">q", v) -// -// def write_u64(self, v): -// self._pack_into(8, ">Q", v) -// -// def write_float(self, v): -// self._pack_into(4, ">f", v) -// -// def write_double(self, v): -// self._pack_into(8, ">d", v) -// -// def write_c_size_t(self, v): -// self._pack_into(ctypes.sizeof(ctypes.c_size_t) , "@N", v) -// A handful of classes and functions to support the generated data structures. -// This would be a good candidate for isolating in its own ffi-support lib. - -final class _UniffiRustCallStatus extends Struct { - @Uint8() - external int code; - - external _UniffiRustBuffer error_buf; -} - - - -enum RUST_CALL_STATUS { CALL_SUCCESS, CALL_ERROR, CALL_PANIC } - - -// This is just a wrapper -_rustCall(fn, rustCallStatus) { - return _rustCallWithError(null, fn, rustCallStatus); -} - -// This is just a wrapper -_rustCallWithError(_UniffiWithError? error, fn, Pointer<_UniffiRustCallStatus> rustCallStatus) { - var fnResult = fn(); - - _rustCallCheckStatus(error, rustCallStatus); - - calloc.free(rustCallStatus); - return fnResult; -} - -void _rustCallCheckStatus(_UniffiWithError? error, Pointer<_UniffiRustCallStatus> rustCallStatus) { - if (rustCallStatus.ref.code == RUST_CALL_STATUS.CALL_SUCCESS.index) { - return; - } else if (rustCallStatus.ref.code == RUST_CALL_STATUS.CALL_ERROR.index) { - if(error == null) { - throw 'CALL_ERROR but error converter is null.'; - } else { - throw error.toError(rustCallStatus); - } - } else if (rustCallStatus.ref.code == RUST_CALL_STATUS.CALL_PANIC.index) { - throw 'Panic: Rust Panic: ${rustCallStatus.ref.error_buf.data.toDartString()}'; - } else { - throw 'PANIC: rustCallStatus.ref.code undefined value: ${rustCallStatus.ref.code}'; - } -} - -//class InternalError(Exception): -// pass -// -//class _UniffiRustCallStatus(ctypes.Structure): -// """ -// Error runtime. -// """ -// _fields_ = [ -// ("code", ctypes.c_int8), -// ("error_buf", _UniffiRustBuffer), -// ] -// -// # These match the values from the uniffi::rustcalls module -// CALL_SUCCESS = 0 -// CALL_ERROR = 1 -// CALL_PANIC = 2 -// -// def __str__(self): -// if self.code == _UniffiRustCallStatus.CALL_SUCCESS: -// return "_UniffiRustCallStatus(CALL_SUCCESS)" -// elif self.code == _UniffiRustCallStatus.CALL_ERROR: -// return "_UniffiRustCallStatus(CALL_ERROR)" -// elif self.code == _UniffiRustCallStatus.CALL_PANIC: -// return "_UniffiRustCallStatus(CALL_PANIC)" -// else: -// return "_UniffiRustCallStatus()" -// -//def _rust_call(fn, *args): -// # Call a rust function -// return _rust_call_with_error(None, fn, *args) -// -//def _rust_call_with_error(error_ffi_converter, fn, *args): -// # Call a rust function and handle any errors -// # -// # This function is used for rust calls that return Result<> and therefore can set the CALL_ERROR status code. -// # error_ffi_converter must be set to the _UniffiConverter for the error class that corresponds to the result. -// call_status = _UniffiRustCallStatus(code=_UniffiRustCallStatus.CALL_SUCCESS, error_buf=_UniffiRustBuffer(0, 0, None)) -// -// args_with_error = args + (ctypes.byref(call_status),) -// result = fn(*args_with_error) -// _uniffi_check_call_status(error_ffi_converter, call_status) -// return result -// -//def _uniffi_check_call_status(error_ffi_converter, call_status): -// if call_status.code == _UniffiRustCallStatus.CALL_SUCCESS: -// pass -// elif call_status.code == _UniffiRustCallStatus.CALL_ERROR: -// if error_ffi_converter is None: -// call_status.error_buf.free() -// raise InternalError("_rust_call_with_error: CALL_ERROR, but error_ffi_converter is None") -// else: -// raise error_ffi_converter.lift(call_status.error_buf) -// elif call_status.code == _UniffiRustCallStatus.CALL_PANIC: -// # When the rust code sees a panic, it tries to construct a _UniffiRustBuffer -// # with the message. But if that code panics, then it just sends back -// # an empty buffer. -// if call_status.error_buf.len > 0: -// msg = _UniffiConverterString.lift(call_status.error_buf) -// else: -// msg = "Unknown rust panic" -// raise InternalError(msg) -// else: -// raise InternalError("Invalid _UniffiRustCallStatus code: {}".format( -// call_status.code)) -// -//# A function pointer for a callback as defined by UniFFI. -//# Rust definition `fn(handle: u64, method: u32, args: _UniffiRustBuffer, buf_ptr: *mut _UniffiRustBuffer) -> int` -//_UNIFFI_FOREIGN_CALLBACK_T = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_ulonglong, ctypes.c_ulong, ctypes.POINTER(ctypes.c_char), ctypes.c_int, ctypes.POINTER(_UniffiRustBuffer)) -// -//# UniFFI future continuation -//_UNIFFI_FUTURE_CONTINUATION_T = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_int8) -// -// Types conforming to `_UniffiConverterPrimitive` pass themselves directly over the FFI. -class _UniffiConverterPrimitive { - static check(value) { - return true; - } - - lift(value) { - return value; - } - - lower(value) { - return value; - } -} - -class _UniffiConverterPrimitiveInt extends _UniffiConverterPrimitive { - //@classmethod - //def check(cls, value): - // try: - // value = value.__index__() - // except Exception: - // raise TypeError("'{}' object cannot be interpreted as an integer".format(type(value).__name__)) - // if not isinstance(value, int): - // raise TypeError("__index__ returned non-int (type {})".format(type(value).__name__)) - // if not cls.VALUE_MIN <= value < cls.VALUE_MAX: - // raise ValueError("{} requires {} <= value < {}".format(cls.CLASS_NAME, cls.VALUE_MIN, cls.VALUE_MAX)) - // return super().check(value) - - static write_unchecked(value, buf) { - return value; - } -} - -class _UniffiConverterPrimitiveFloat extends _UniffiConverterPrimitive { - //@classmethod - //def check(cls, value): - // try: - // value = value.__float__() - // except Exception: - // raise TypeError("must be real number, not {}".format(type(value).__name__)) - // if not isinstance(value, float): - // raise TypeError("__float__ returned non-float (type {})".format(type(value).__name__)) - // return super().check(value) - - static write_unchecked(value, buf) { - return value; - } -} - -// Helper class for wrapper types that will always go through a _UniffiRustBuffer. -// Classes should inherit from this and implement the `read` and `write` static methods. -abstract interface class _UniffiConverterRustBuffer { - - Pointer<_UniffiRustBuffer>? _rustBuffer; - - T lift(_UniffiRustBuffer buf) { - return read(buf.buffer); - } - - _UniffiRustBuffer lower(T value) { - - var bufferBuilder = _UniffiRustBufferBuilder(); - write(bufferBuilder, value); - - _rustBuffer = calloc<_UniffiRustBuffer >(); - _rustBuffer!.ref - ..capacity = bufferBuilder.length - ..len = bufferBuilder.length - ..data = bufferBuilder.toNativeUtf8(); - - return _rustBuffer!.ref; - } - - T read(_UniffiRustBufferBuilder buf); - - write(_UniffiRustBufferBuilder buf, T value); - - void dispose() { - if (_rustBuffer != null) { - calloc.free(this._rustBuffer!); - } - } -} - -class _UniffiWithError { - static _UniffiRustBuffer lift(Pointer<_UniffiRustCallStatus> val) { - return val.ref.error_buf; - } - - @override - liftNotStatic(Pointer<_UniffiRustCallStatus> buf) { - return lift(buf); - } - - toError(Pointer<_UniffiRustCallStatus> val) { - } - static read(_UniffiRustBuffer buf) { - return buf; - } -} - -// Contains loading, initialization code, and the FFI Function declarations. -//# Define some ctypes FFI types that we use in the library -// -//""" -//ctypes type for the foreign executor callback. This is a built-in interface for scheduling -//tasks -// -//Args: -// executor: opaque c_size_t value representing the eventloop -// delay: delay in ms -// task: function pointer to the task callback -// task_data: void pointer to the task callback data -// -//Normally we should call task(task_data) after the detail. -//However, when task is NULL this indicates that Rust has dropped the ForeignExecutor and we should -//decrease the EventLoop refcount. -//""" -//_UNIFFI_FOREIGN_EXECUTOR_CALLBACK_T = ctypes.CFUNCTYPE(ctypes.c_int8, ctypes.c_size_t, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_void_p) -// -//""" -//Function pointer for a Rust task, which a callback function that takes a opaque pointer -//""" -//_UNIFFI_RUST_TASK = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_int8) -// -//def _uniffi_future_callback_t(return_type): -// """ -// Factory function to create callback function types for async functions -// """ -// return ctypes.CFUNCTYPE(None, ctypes.c_size_t, return_type, _UniffiRustCallStatus) -// -//def _uniffi_load_indirect(): -// """ -// This is how we find and load the dynamic library provided by the component. -// For now we just look it up by name. -// """ -// if sys.platform == "darwin": -// libname = "lib{}.dylib" -// elif sys.platform.startswith("win"): -// # As of python3.8, ctypes does not seem to search $PATH when loading DLLs. -// # We could use `os.add_dll_directory` to configure the search path, but -// # it doesn't feel right to mess with application-wide settings. Let's -// # assume that the `.dll` is next to the `.py` file and load by full path. -// libname = os.path.join( -// os.path.dirname(__file__), -// "{}.dll", -// ) -// else: -// # Anything else must be an ELF platform - Linux, *BSD, Solaris/illumos -// libname = "lib{}.so" -// -// libname = libname.format("bdkffi") -// path = os.path.join(os.path.dirname(__file__), libname) -// lib = ctypes.cdll.LoadLibrary(path) -// return lib - -DynamicLibrary _uniffiLoadDynamicLibrary() { - - final path = Platform.isWindows ? "libbdkffi.dll" : "libbdkffi.so"; - var lib = Platform.isIOS - ? DynamicLibrary.process() - : Platform.isMacOS - ? DynamicLibrary.executable() - : DynamicLibrary.open(path); - - _uniffi_check_contract_api_version(lib); - - return lib; -} - -final _uniffiLib = _uniffiLoadDynamicLibrary(); -// -_uniffi_check_contract_api_version(DynamicLibrary lib) { - - _UniffiLib_ffi_bdkffi_uniffi_contract_version_d contractFunc = lib.lookup>('ffi_bdkffi_uniffi_contract_version').asFunction(); - - // Get the bindings contract version from our ComponentInterface - var bindings_contract_version = 24; - // Get the scaffolding contract version by calling the into the dylib - var scaffolding_contract_version = contractFunc(); - - if (bindings_contract_version != scaffolding_contract_version) { - throw "UniFFI contract version mismatch: try cleaning and rebuilding your project"; - } -} -// -//def _uniffi_check_api_checksums(lib): -// -// if lib.uniffi_bdkffi_checksum_method_networkexample_get_signet() != 574: -// raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") -// -// if lib.uniffi_bdkffi_checksum_method_networkexample_network_name() != 25154: -// raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") -// -// if lib.uniffi_bdkffi_checksum_constructor_networkexample_new() != 39466: -// raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") -// -// -//# A ctypes library to expose the extern-C FFI definitions. -//# This is an implementation detail which will be called internally by the public API. -// - -typedef _UniffiLib_uniffi_bdkffi_fn_free_networkexample_c = Void Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_uniffi_bdkffi_fn_free_networkexample_d = void Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_uniffi_bdkffi_fn_free_networkexample_d _UniffiLib_uniffi_bdkffi_fn_free_networkexample_func = _uniffiLib.lookup>('uniffi_bdkffi_fn_free_networkexample').asFunction(); - -typedef _UniffiLib_uniffi_bdkffi_fn_constructor_networkexample_new_c = Pointer Function( - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_uniffi_bdkffi_fn_constructor_networkexample_new_d = Pointer Function( - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_uniffi_bdkffi_fn_constructor_networkexample_new_d _UniffiLib_uniffi_bdkffi_fn_constructor_networkexample_new_func = _uniffiLib.lookup>('uniffi_bdkffi_fn_constructor_networkexample_new').asFunction(); - -typedef _UniffiLib_uniffi_bdkffi_fn_method_networkexample_get_signet_c = _UniffiRustBuffer Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_uniffi_bdkffi_fn_method_networkexample_get_signet_d = _UniffiRustBuffer Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_uniffi_bdkffi_fn_method_networkexample_get_signet_d _UniffiLib_uniffi_bdkffi_fn_method_networkexample_get_signet_func = _uniffiLib.lookup>('uniffi_bdkffi_fn_method_networkexample_get_signet').asFunction(); - -typedef _UniffiLib_uniffi_bdkffi_fn_method_networkexample_network_name_c = _UniffiRustBuffer Function( - Pointer, - _UniffiRustBuffer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_uniffi_bdkffi_fn_method_networkexample_network_name_d = _UniffiRustBuffer Function( - Pointer, - _UniffiRustBuffer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_uniffi_bdkffi_fn_method_networkexample_network_name_d _UniffiLib_uniffi_bdkffi_fn_method_networkexample_network_name_func = _uniffiLib.lookup>('uniffi_bdkffi_fn_method_networkexample_network_name').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rustbuffer_alloc_c = _UniffiRustBuffer Function( - Int32, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rustbuffer_alloc_d = _UniffiRustBuffer Function( - int, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rustbuffer_alloc_d _UniffiLib_ffi_bdkffi_rustbuffer_alloc_func = _uniffiLib.lookup>('ffi_bdkffi_rustbuffer_alloc').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rustbuffer_from_bytes_c = _UniffiRustBuffer Function( - Pointer<_UniffiRustCallStatus>, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rustbuffer_from_bytes_d = _UniffiRustBuffer Function( - Pointer<_UniffiRustCallStatus>, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rustbuffer_from_bytes_d _UniffiLib_ffi_bdkffi_rustbuffer_from_bytes_func = _uniffiLib.lookup>('ffi_bdkffi_rustbuffer_from_bytes').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rustbuffer_free_c = Void Function( - _UniffiRustBuffer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rustbuffer_free_d = void Function( - _UniffiRustBuffer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rustbuffer_free_d _UniffiLib_ffi_bdkffi_rustbuffer_free_func = _uniffiLib.lookup>('ffi_bdkffi_rustbuffer_free').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rustbuffer_reserve_c = _UniffiRustBuffer Function( - _UniffiRustBuffer, - Int32, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rustbuffer_reserve_d = _UniffiRustBuffer Function( - _UniffiRustBuffer, - int, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rustbuffer_reserve_d _UniffiLib_ffi_bdkffi_rustbuffer_reserve_func = _uniffiLib.lookup>('ffi_bdkffi_rustbuffer_reserve').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_continuation_callback_set_c = Void Function( - Pointer>, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_continuation_callback_set_d = void Function( - Pointer>, -); - -final _UniffiLib_ffi_bdkffi_rust_future_continuation_callback_set_d _UniffiLib_ffi_bdkffi_rust_future_continuation_callback_set_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_continuation_callback_set').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_u8_c = Void Function( - Pointer, - Size, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_u8_d = void Function( - Pointer, - int, -); - -final _UniffiLib_ffi_bdkffi_rust_future_poll_u8_d _UniffiLib_ffi_bdkffi_rust_future_poll_u8_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_poll_u8').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_u8_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_u8_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_cancel_u8_d _UniffiLib_ffi_bdkffi_rust_future_cancel_u8_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_cancel_u8').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_u8_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_u8_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_free_u8_d _UniffiLib_ffi_bdkffi_rust_future_free_u8_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_free_u8').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_u8_c = Uint8 Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_u8_d = int Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rust_future_complete_u8_d _UniffiLib_ffi_bdkffi_rust_future_complete_u8_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_complete_u8').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_i8_c = Void Function( - Pointer, - Size, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_i8_d = void Function( - Pointer, - int, -); - -final _UniffiLib_ffi_bdkffi_rust_future_poll_i8_d _UniffiLib_ffi_bdkffi_rust_future_poll_i8_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_poll_i8').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_i8_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_i8_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_cancel_i8_d _UniffiLib_ffi_bdkffi_rust_future_cancel_i8_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_cancel_i8').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_i8_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_i8_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_free_i8_d _UniffiLib_ffi_bdkffi_rust_future_free_i8_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_free_i8').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_i8_c = Int8 Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_i8_d = int Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rust_future_complete_i8_d _UniffiLib_ffi_bdkffi_rust_future_complete_i8_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_complete_i8').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_u16_c = Void Function( - Pointer, - Size, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_u16_d = void Function( - Pointer, - int, -); - -final _UniffiLib_ffi_bdkffi_rust_future_poll_u16_d _UniffiLib_ffi_bdkffi_rust_future_poll_u16_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_poll_u16').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_u16_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_u16_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_cancel_u16_d _UniffiLib_ffi_bdkffi_rust_future_cancel_u16_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_cancel_u16').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_u16_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_u16_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_free_u16_d _UniffiLib_ffi_bdkffi_rust_future_free_u16_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_free_u16').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_u16_c = Uint16 Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_u16_d = int Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rust_future_complete_u16_d _UniffiLib_ffi_bdkffi_rust_future_complete_u16_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_complete_u16').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_i16_c = Void Function( - Pointer, - Size, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_i16_d = void Function( - Pointer, - int, -); - -final _UniffiLib_ffi_bdkffi_rust_future_poll_i16_d _UniffiLib_ffi_bdkffi_rust_future_poll_i16_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_poll_i16').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_i16_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_i16_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_cancel_i16_d _UniffiLib_ffi_bdkffi_rust_future_cancel_i16_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_cancel_i16').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_i16_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_i16_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_free_i16_d _UniffiLib_ffi_bdkffi_rust_future_free_i16_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_free_i16').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_i16_c = Int16 Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_i16_d = int Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rust_future_complete_i16_d _UniffiLib_ffi_bdkffi_rust_future_complete_i16_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_complete_i16').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_u32_c = Void Function( - Pointer, - Size, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_u32_d = void Function( - Pointer, - int, -); - -final _UniffiLib_ffi_bdkffi_rust_future_poll_u32_d _UniffiLib_ffi_bdkffi_rust_future_poll_u32_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_poll_u32').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_u32_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_u32_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_cancel_u32_d _UniffiLib_ffi_bdkffi_rust_future_cancel_u32_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_cancel_u32').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_u32_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_u32_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_free_u32_d _UniffiLib_ffi_bdkffi_rust_future_free_u32_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_free_u32').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_u32_c = Uint32 Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_u32_d = int Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rust_future_complete_u32_d _UniffiLib_ffi_bdkffi_rust_future_complete_u32_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_complete_u32').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_i32_c = Void Function( - Pointer, - Size, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_i32_d = void Function( - Pointer, - int, -); - -final _UniffiLib_ffi_bdkffi_rust_future_poll_i32_d _UniffiLib_ffi_bdkffi_rust_future_poll_i32_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_poll_i32').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_i32_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_i32_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_cancel_i32_d _UniffiLib_ffi_bdkffi_rust_future_cancel_i32_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_cancel_i32').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_i32_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_i32_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_free_i32_d _UniffiLib_ffi_bdkffi_rust_future_free_i32_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_free_i32').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_i32_c = Int32 Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_i32_d = int Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rust_future_complete_i32_d _UniffiLib_ffi_bdkffi_rust_future_complete_i32_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_complete_i32').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_u64_c = Void Function( - Pointer, - Size, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_u64_d = void Function( - Pointer, - int, -); - -final _UniffiLib_ffi_bdkffi_rust_future_poll_u64_d _UniffiLib_ffi_bdkffi_rust_future_poll_u64_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_poll_u64').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_u64_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_u64_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_cancel_u64_d _UniffiLib_ffi_bdkffi_rust_future_cancel_u64_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_cancel_u64').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_u64_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_u64_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_free_u64_d _UniffiLib_ffi_bdkffi_rust_future_free_u64_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_free_u64').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_u64_c = Uint64 Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_u64_d = int Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rust_future_complete_u64_d _UniffiLib_ffi_bdkffi_rust_future_complete_u64_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_complete_u64').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_i64_c = Void Function( - Pointer, - Size, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_i64_d = void Function( - Pointer, - int, -); - -final _UniffiLib_ffi_bdkffi_rust_future_poll_i64_d _UniffiLib_ffi_bdkffi_rust_future_poll_i64_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_poll_i64').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_i64_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_i64_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_cancel_i64_d _UniffiLib_ffi_bdkffi_rust_future_cancel_i64_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_cancel_i64').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_i64_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_i64_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_free_i64_d _UniffiLib_ffi_bdkffi_rust_future_free_i64_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_free_i64').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_i64_c = Int64 Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_i64_d = int Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rust_future_complete_i64_d _UniffiLib_ffi_bdkffi_rust_future_complete_i64_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_complete_i64').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_f32_c = Void Function( - Pointer, - Size, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_f32_d = void Function( - Pointer, - int, -); - -final _UniffiLib_ffi_bdkffi_rust_future_poll_f32_d _UniffiLib_ffi_bdkffi_rust_future_poll_f32_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_poll_f32').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_f32_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_f32_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_cancel_f32_d _UniffiLib_ffi_bdkffi_rust_future_cancel_f32_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_cancel_f32').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_f32_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_f32_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_free_f32_d _UniffiLib_ffi_bdkffi_rust_future_free_f32_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_free_f32').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_f32_c = Float Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_f32_d = double Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rust_future_complete_f32_d _UniffiLib_ffi_bdkffi_rust_future_complete_f32_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_complete_f32').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_f64_c = Void Function( - Pointer, - Size, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_f64_d = void Function( - Pointer, - int, -); - -final _UniffiLib_ffi_bdkffi_rust_future_poll_f64_d _UniffiLib_ffi_bdkffi_rust_future_poll_f64_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_poll_f64').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_f64_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_f64_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_cancel_f64_d _UniffiLib_ffi_bdkffi_rust_future_cancel_f64_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_cancel_f64').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_f64_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_f64_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_free_f64_d _UniffiLib_ffi_bdkffi_rust_future_free_f64_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_free_f64').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_f64_c = Double Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_f64_d = double Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rust_future_complete_f64_d _UniffiLib_ffi_bdkffi_rust_future_complete_f64_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_complete_f64').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_pointer_c = Void Function( - Pointer, - Size, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_pointer_d = void Function( - Pointer, - int, -); - -final _UniffiLib_ffi_bdkffi_rust_future_poll_pointer_d _UniffiLib_ffi_bdkffi_rust_future_poll_pointer_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_poll_pointer').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_pointer_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_pointer_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_cancel_pointer_d _UniffiLib_ffi_bdkffi_rust_future_cancel_pointer_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_cancel_pointer').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_pointer_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_pointer_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_free_pointer_d _UniffiLib_ffi_bdkffi_rust_future_free_pointer_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_free_pointer').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_pointer_c = Pointer Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_pointer_d = Pointer Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rust_future_complete_pointer_d _UniffiLib_ffi_bdkffi_rust_future_complete_pointer_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_complete_pointer').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_rust_buffer_c = Void Function( - Pointer, - Size, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_rust_buffer_d = void Function( - Pointer, - int, -); - -final _UniffiLib_ffi_bdkffi_rust_future_poll_rust_buffer_d _UniffiLib_ffi_bdkffi_rust_future_poll_rust_buffer_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_poll_rust_buffer').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_rust_buffer_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_rust_buffer_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_cancel_rust_buffer_d _UniffiLib_ffi_bdkffi_rust_future_cancel_rust_buffer_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_cancel_rust_buffer').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_rust_buffer_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_rust_buffer_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_free_rust_buffer_d _UniffiLib_ffi_bdkffi_rust_future_free_rust_buffer_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_free_rust_buffer').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_rust_buffer_c = _UniffiRustBuffer Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_rust_buffer_d = _UniffiRustBuffer Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rust_future_complete_rust_buffer_d _UniffiLib_ffi_bdkffi_rust_future_complete_rust_buffer_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_complete_rust_buffer').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_void_c = Void Function( - Pointer, - Size, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_poll_void_d = void Function( - Pointer, - int, -); - -final _UniffiLib_ffi_bdkffi_rust_future_poll_void_d _UniffiLib_ffi_bdkffi_rust_future_poll_void_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_poll_void').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_void_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_cancel_void_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_cancel_void_d _UniffiLib_ffi_bdkffi_rust_future_cancel_void_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_cancel_void').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_void_c = Void Function( - Pointer, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_free_void_d = void Function( - Pointer, -); - -final _UniffiLib_ffi_bdkffi_rust_future_free_void_d _UniffiLib_ffi_bdkffi_rust_future_free_void_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_free_void').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_void_c = Void Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -typedef _UniffiLib_ffi_bdkffi_rust_future_complete_void_d = void Function( - Pointer, - Pointer<_UniffiRustCallStatus>, -); - -final _UniffiLib_ffi_bdkffi_rust_future_complete_void_d _UniffiLib_ffi_bdkffi_rust_future_complete_void_func = _uniffiLib.lookup>('ffi_bdkffi_rust_future_complete_void').asFunction(); - -typedef _UniffiLib_uniffi_bdkffi_checksum_method_networkexample_get_signet_c = Uint16 Function( -); - -typedef _UniffiLib_uniffi_bdkffi_checksum_method_networkexample_get_signet_d = int Function( -); - -final _UniffiLib_uniffi_bdkffi_checksum_method_networkexample_get_signet_d _UniffiLib_uniffi_bdkffi_checksum_method_networkexample_get_signet_func = _uniffiLib.lookup>('uniffi_bdkffi_checksum_method_networkexample_get_signet').asFunction(); - -typedef _UniffiLib_uniffi_bdkffi_checksum_method_networkexample_network_name_c = Uint16 Function( -); - -typedef _UniffiLib_uniffi_bdkffi_checksum_method_networkexample_network_name_d = int Function( -); - -final _UniffiLib_uniffi_bdkffi_checksum_method_networkexample_network_name_d _UniffiLib_uniffi_bdkffi_checksum_method_networkexample_network_name_func = _uniffiLib.lookup>('uniffi_bdkffi_checksum_method_networkexample_network_name').asFunction(); - -typedef _UniffiLib_uniffi_bdkffi_checksum_constructor_networkexample_new_c = Uint16 Function( -); - -typedef _UniffiLib_uniffi_bdkffi_checksum_constructor_networkexample_new_d = int Function( -); - -final _UniffiLib_uniffi_bdkffi_checksum_constructor_networkexample_new_d _UniffiLib_uniffi_bdkffi_checksum_constructor_networkexample_new_func = _uniffiLib.lookup>('uniffi_bdkffi_checksum_constructor_networkexample_new').asFunction(); - -typedef _UniffiLib_ffi_bdkffi_uniffi_contract_version_c = Uint32 Function( -); - -typedef _UniffiLib_ffi_bdkffi_uniffi_contract_version_d = int Function( -); - -final _UniffiLib_ffi_bdkffi_uniffi_contract_version_d _UniffiLib_ffi_bdkffi_uniffi_contract_version_func = _uniffiLib.lookup>('ffi_bdkffi_uniffi_contract_version').asFunction(); - -////_uniffi_check_contract_api_version(_UniffiLib) -//_uniffi_check_api_checksums(_UniffiLib) - -// Public interface members begin here. - - -class _UniffiConverterString { - - late Pointer<_UniffiRustBuffer> _pointer; - - static check(value) { - /*if not isinstance(value, str): - raise TypeError("argument must be str, not {}".format(type(value).__name__)) - return value*/ - } - - String lift(_UniffiRustBuffer buf) { - return buf.data.toDartString(); - } - - _UniffiRustBuffer lower(String value) { - - _pointer = calloc<_UniffiRustBuffer>(); - _pointer.ref - ..capacity = value.length - ..len = value.length - ..data = value.toNativeUtf8(); - - return _pointer.ref; - } - - - - @override - void dispose() { - if (_pointer != null) { - calloc.free(this._pointer); - } - } - - read(_UniffiRustBufferBuilder buf) { - var size = buf.read_i32(); - if (size < 0) { - throw "Negative string length"; - } - return buf.toDartString(size); - //return utf8_bytes.decode("utf-8") - } - - _UniffiRustBufferBuilder write(String value, _UniffiRustBufferBuilder buf) { - return buf; - } -} - - - -// Generated by Protocol -abstract class NetworkExampleProtocol { - get_signet() { - throw UnimplementedError('get_signet not implemented.'); - } - network_name(Network network) { - throw UnimplementedError('network_name not implemented.'); - } -} - -// Generated By: ObjectTemplate:1 -class NetworkExample { - //late NetworkExample _pointer; - late Pointer _pointer; - Pointer get pointer => _pointer; - NetworkExample () { -final Pointer<_UniffiRustCallStatus> _rustCallStatus = calloc<_UniffiRustCallStatus >(); - _pointer = _rustCall(() => _UniffiLib_uniffi_bdkffi_fn_constructor_networkexample_new_func( - _rustCallStatus), - _rustCallStatus -); - } - - NetworkExample.fromPointer(Pointer _pointer) { - this._pointer = _pointer; - } - - @override - void dispose() { - // In case of partial initialization of instances. - if (_pointer != null) { -final Pointer<_UniffiRustCallStatus> _rustCallStatus = calloc<_UniffiRustCallStatus >(); - _rustCall(() => _UniffiLib_uniffi_bdkffi_fn_free_networkexample_func(_pointer, _rustCallStatus), _rustCallStatus); - } - } - - // method: 2 - Network get_signet() { -final Pointer<_UniffiRustCallStatus> _rustCallStatus = calloc<_UniffiRustCallStatus >(); - return _UniffiConverterTypeNetwork().lift( - _rustCall(() => _UniffiLib_uniffi_bdkffi_fn_method_networkexample_get_signet_func(_pointer, - _rustCallStatus), - _rustCallStatus -) - ); - } - - - - - - // method: 2 - String network_name(Network network) { - -final Pointer<_UniffiRustCallStatus> _rustCallStatus = calloc<_UniffiRustCallStatus >(); - return _UniffiConverterString().lift( - _rustCall(() => _UniffiLib_uniffi_bdkffi_fn_method_networkexample_network_name_func(_pointer, - _UniffiConverterTypeNetwork().lower(network), - _rustCallStatus), - _rustCallStatus -) - ); - } - - - - -} - -// Generated By: ObjectTemplate:2 -class _UniffiConverterTypeNetworkExample { - - NetworkExample lift(Pointer _pointer) { - // TODO: Do something with value? - return NetworkExample.fromPointer(_pointer); - } - - Pointer lower(NetworkExample value) { - return value.pointer; - } - - /* - static NetworkExampleProtocol lower(NetworkExample value) { - //if not isinstance(value, NetworkExample): - // raise TypeError("Expected NetworkExample instance, {} found".format(type(value).__name__)) - //return value._pointer - return NetworkExampleProtocol(); - }*/ - - read(_UniffiRustBufferBuilder buf) { - var ptr = buf.read_i64(); - if (ptr == 0) { - throw 'Issue with pointer'; - } - return _UniffiConverterTypeNetworkExample().lift(Pointer.fromAddress(ptr)); - } - - _UniffiRustBufferBuilder write(_UniffiRustBufferBuilder buf, value) { - //buf.write_u64(cls.lower(value)) - Pointer<_UniffiRustBuffer> _rustBuffer = calloc<_UniffiRustBuffer >(); - return _rustBuffer.ref.buffer; - } -} - - - - - -// Enumtemplate: 1 -enum Network { - _, - BITCOIN, - TESTNET, - SIGNET, - REGTEST, - TESTNET4, - -} - - -// Generated By: EnumTemplate: 3 -class _UniffiConverterTypeNetwork extends _UniffiConverterRustBuffer { - read(_UniffiRustBufferBuilder buf) { - var variant = buf.read_i32(); - if (variant == 1) { - return Network.BITCOIN; - } - if (variant == 2) { - return Network.TESTNET; - } - if (variant == 3) { - return Network.SIGNET; - } - if (variant == 4) { - return Network.REGTEST; - } - if (variant == 5) { - return Network.TESTNET4; - } - throw "Raw enum value doesn't match any cases"; - } - - write(_UniffiRustBufferBuilder buf, Network value) { - if (value == Network.BITCOIN) { - buf.write_i32(1); - } - if (value == Network.TESTNET) { - buf.write_i32(2); - } - if (value == Network.SIGNET) { - buf.write_i32(3); - } - if (value == Network.REGTEST) { - buf.write_i32(4); - } - if (value == Network.TESTNET4) { - buf.write_i32(5); - } - } -} - - diff --git a/examples/network_example.dart b/examples/network_example.dart index 1e9028d..17d74dc 100644 --- a/examples/network_example.dart +++ b/examples/network_example.dart @@ -1,14 +1,71 @@ -import '../dart_bindings/bdk.dart'; +import 'dart:io'; +import 'package:bdk_dart/bdk.dart'; + +/// Run with: `dart run examples/network_example.dart` +/// +/// Prerequisites: +/// * Generated bindings (`scripts/generate_bindings.sh`) +/// * Native library (`libbdkffi.*`) discoverable by the Dart process void main() { - // Create a NetworkExample instance - final networkHelper = NetworkExample(); - - // Get the Signet network - final signetNetwork = networkHelper.get_signet(); - - // Convert it to string - should print "Signet" - final networkName = networkHelper.network_name(signetNetwork); - - print("Network: $networkName"); -} \ No newline at end of file + final network = Network.testnet; + + // 1. Create fresh seed material. + final mnemonic = Mnemonic(WordCount.words12); + stdout.writeln('Mnemonic: $mnemonic'); + + // 2. Turn the mnemonic into descriptor keys for external/change paths. + final rootKey = DescriptorSecretKey(network, mnemonic, null); + final externalDescriptor = + Descriptor.newBip84(rootKey, KeychainKind.external_, network); + final changeDescriptor = + Descriptor.newBip84(rootKey, KeychainKind.internal, network); + + stdout + ..writeln('\nExternal descriptor:\n $externalDescriptor') + ..writeln('Change descriptor:\n $changeDescriptor'); + + // 3. Spin up an in-memory wallet using the descriptors. + final persister = Persister.newInMemory(); + final wallet = + Wallet(externalDescriptor, changeDescriptor, network, persister, 25); + stdout.writeln('\nWallet ready on ${wallet.network()}'); + + // 4. Hand out the next receive address and persist the staged change. + final receive = wallet.revealNextAddress(KeychainKind.external_); + stdout.writeln( + 'Next receive address (#${receive.index}): ${receive.address.toString()}'); + final persisted = wallet.persist(persister); + stdout.writeln('Persisted staged wallet changes: $persisted'); + + // 5. Try a quick Electrum sync to fetch history/balances. + try { + stdout.writeln('\nSyncing via Electrum (blockstream.info)…'); + final client = + ElectrumClient('ssl://electrum.blockstream.info:60002', null); + final syncRequest = wallet.startSyncWithRevealedSpks().build(); + final update = client.sync_(syncRequest, 100, true); + + wallet.applyUpdate(update); + wallet.persist(persister); + + final balance = wallet.balance(); + stdout.writeln('Confirmed balance: ${balance.confirmed.toSat()} sats'); + stdout.writeln('Total balance: ${balance.total.toSat()} sats'); + + client.dispose(); + } catch (error) { + stdout.writeln( + 'Electrum sync failed: $error\n' + 'Ensure TLS-enabled Electrum access is available, or skip this step.', + ); + } + + // 6. Clean up FFI handles explicitly so long-lived examples don’t leak. + wallet.dispose(); + persister.dispose(); + externalDescriptor.dispose(); + changeDescriptor.dispose(); + rootKey.dispose(); + mnemonic.dispose(); +} diff --git a/lib/README.md b/lib/README.md new file mode 100644 index 0000000..f52b57c --- /dev/null +++ b/lib/README.md @@ -0,0 +1,8 @@ +# Generated bindings live here + +The Dart bindings are produced by UniFFI-Dart and are **not** checked into +source control. Run `scripts/generate_bindings.sh` to regenerate +`bdk.dart` before building or testing. + +This placeholder file keeps the `lib/` directory present in the +repository so that `dart` tooling can resolve the package structure. diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..1c3f618 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,12 @@ +name: bdk_dart +description: Dart bindings for bdk-ffi +version: 0.24.0 + +environment: + sdk: '^3.2.0' + +dependencies: + ffi: ^2.1.4 +dev_dependencies: + test: ^1.26.2 + http: ^1.4.0 \ No newline at end of file diff --git a/scripts/generate_bindings.sh b/scripts/generate_bindings.sh new file mode 100755 index 0000000..13e94f5 --- /dev/null +++ b/scripts/generate_bindings.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -euo pipefail + +OS=$(uname -s) +echo "Running on $OS" + +dart --version +dart pub get + +mkdir -p lib +rm -f lib/bdk.dart + +# Install Rust targets if on macOS +if [[ "$OS" == "Darwin" ]]; then + LIBNAME=libbdkffi.dylib +elif [[ "$OS" == "Linux" ]]; then + LIBNAME=libbdkffi.so +else + echo "Unsupported os: $OS" + exit 1 +fi + +# Run from the specific crate inside the embedded submodule +cd ./bdk-ffi/bdk-ffi/ +echo "Building bdk-ffi crate and generating Dart bindings..." +cargo build --profile dev -p bdk-ffi + +# Generate Dart bindings using local uniffi-bindgen wrapper +(cd ../../ && cargo run --profile dev --bin uniffi-bindgen -- --language dart --library bdk-ffi/bdk-ffi/target/debug/$LIBNAME --out-dir lib/) + +if [[ "$OS" == "Darwin" ]]; then + echo "Generating native binaries..." + rustup target add aarch64-apple-darwin x86_64-apple-darwin + # This is a test script the actual release should not include the test utils feature + cargo build --profile dev -p bdk-ffi --target aarch64-apple-darwin & + cargo build --profile dev -p bdk-ffi --target x86_64-apple-darwin & + wait + + echo "Building macOS fat library" + lipo -create -output ../../$LIBNAME \ + target/aarch64-apple-darwin/debug/$LIBNAME \ + target/x86_64-apple-darwin/debug/$LIBNAME +else + echo "Generating native binaries..." + rustup target add x86_64-unknown-linux-gnu + # This is a test script the actual release should not include the test utils feature + cargo build --profile dev -p bdk-ffi --target x86_64-unknown-linux-gnu + + echo "Copying bdk-ffi binary" + cp target/x86_64-unknown-linux-gnu/debug/$LIBNAME ../../$LIBNAME +fi + +echo "All done!" diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 51db227..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Simple implementation just for the Network enum -#[derive(Debug, Clone)] -pub enum Network { - Bitcoin, - Testnet, - Signet, - Regtest, - Testnet4, -} - -pub struct NetworkExample; - -impl NetworkExample { - pub fn new() -> Self { - Self - } - - pub fn get_signet(&self) -> Network { - Network::Signet - } - - pub fn network_name(&self, network: Network) -> String { - match network { - Network::Bitcoin => "Bitcoin".to_string(), - Network::Testnet => "Testnet".to_string(), - Network::Signet => "Signet".to_string(), - Network::Regtest => "Regtest".to_string(), - Network::Testnet4 => "Testnet4".to_string(), - } - } -} - -uniffi::include_scaffolding!("simple_bdk"); \ No newline at end of file diff --git a/src/minimal.rs b/src/minimal.rs deleted file mode 100644 index 4ada241..0000000 --- a/src/minimal.rs +++ /dev/null @@ -1,22 +0,0 @@ -#[derive(uniffi::Enum, Debug, Clone)] -pub enum Network { - Bitcoin, - Testnet, - Signet, - Regtest, -} - -#[uniffi::export] -pub fn get_signet_network() -> Network { - Network::Signet -} - -#[uniffi::export] -pub fn network_to_string(network: Network) -> String { - match network { - Network::Bitcoin => "Bitcoin".to_string(), - Network::Testnet => "Testnet".to_string(), - Network::Signet => "Signet".to_string(), - Network::Regtest => "Regtest".to_string(), - } -} \ No newline at end of file diff --git a/src/simple_bdk.udl b/src/simple_bdk.udl deleted file mode 100644 index dc0ed73..0000000 --- a/src/simple_bdk.udl +++ /dev/null @@ -1,15 +0,0 @@ -namespace bdk {}; - -enum Network { - "Bitcoin", - "Testnet", - "Signet", - "Regtest", - "Testnet4", -}; - -interface NetworkExample { - constructor(); - Network get_signet(); - string network_name(Network network); -}; \ No newline at end of file diff --git a/test/data/pre_existing_wallet_persistence_test.sqlite b/test/data/pre_existing_wallet_persistence_test.sqlite new file mode 100644 index 0000000..18b69e7 Binary files /dev/null and b/test/data/pre_existing_wallet_persistence_test.sqlite differ diff --git a/test/descriptor_test.dart b/test/descriptor_test.dart new file mode 100644 index 0000000..ff9768d --- /dev/null +++ b/test/descriptor_test.dart @@ -0,0 +1,102 @@ +import 'package:bdk_dart/bdk.dart'; +import 'package:test/test.dart'; + +import 'test_constants.dart'; + +void main() { + group('Descriptor construction', () { + test('creates extended WPKH descriptors across networks', () { + expect( + () => buildBip84Descriptor(Network.regtest), + returnsNormally, + ); + expect( + () => buildBip84Descriptor(Network.testnet), + returnsNormally, + ); + expect( + () => buildBip84Descriptor(Network.testnet4), + returnsNormally, + ); + expect( + () => buildBip84Descriptor(Network.signet), + returnsNormally, + ); + expect( + () => buildMainnetBip84Descriptor(), + returnsNormally, + ); + }); + + test('creates extended TR descriptors across networks', () { + expect( + () => buildBip86Descriptor(Network.regtest), + returnsNormally, + ); + expect( + () => buildBip86Descriptor(Network.testnet), + returnsNormally, + ); + expect( + () => buildBip86Descriptor(Network.testnet4), + returnsNormally, + ); + expect( + () => buildBip86Descriptor(Network.signet), + returnsNormally, + ); + expect( + () => buildMainnetBip86Descriptor(), + returnsNormally, + ); + }); + + test('creates non-extended descriptors for all networks', () { + expect( + () => Descriptor( + "tr($testExtendedPrivKey/$bip86TestReceivePath/0)", + Network.regtest, + ), + returnsNormally, + ); + expect( + () => Descriptor( + "tr($testExtendedPrivKey/$bip86TestReceivePath/0)", + Network.testnet, + ), + returnsNormally, + ); + expect( + () => Descriptor( + "tr($testExtendedPrivKey/$bip86TestReceivePath/0)", + Network.testnet4, + ), + returnsNormally, + ); + expect( + () => Descriptor( + "tr($testExtendedPrivKey/$bip86TestReceivePath/0)", + Network.signet, + ), + returnsNormally, + ); + expect( + () => Descriptor( + "tr($mainnetExtendedPrivKey/$bip86MainnetReceivePath/0)", + Network.bitcoin, + ), + returnsNormally, + ); + }); + + test('fails to create addr() descriptor', () { + expect( + () => Descriptor( + "addr(tb1qhjys9wxlfykmte7ftryptx975uqgd6kcm6a7z4)", + Network.testnet, + ), + throwsA(isA()), + ); + }); + }); +} diff --git a/test/mnemonic_test.dart b/test/mnemonic_test.dart new file mode 100644 index 0000000..7f69095 --- /dev/null +++ b/test/mnemonic_test.dart @@ -0,0 +1,29 @@ +import 'package:bdk_dart/bdk.dart'; +import 'package:test/test.dart'; + +void main() { + group('Mnemonic', () { + test('produces expected BIP86 descriptor', () { + final mnemonic = Mnemonic.fromString( + "space echo position wrist orient erupt relief museum myself grain wisdom tumble", + ); + final descriptorSecretKey = DescriptorSecretKey( + Network.testnet, + mnemonic, + null, + ); + final descriptor = Descriptor.newBip86( + descriptorSecretKey, + KeychainKind.external_, + Network.testnet, + ); + + expect( + descriptor.toString(), + equals( + "tr([be1eec8f/86'/1'/0']tpubDCTtszwSxPx3tATqDrsSyqScPNnUChwQAVAkanuDUCJQESGBbkt68nXXKRDifYSDbeMa2Xg2euKbXaU3YphvGWftDE7ozRKPriT6vAo3xsc/0/*)#m7puekcx", + ), + ); + }); + }); +} diff --git a/test/offline_persistence_test.dart b/test/offline_persistence_test.dart new file mode 100644 index 0000000..61790bd --- /dev/null +++ b/test/offline_persistence_test.dart @@ -0,0 +1,62 @@ +import 'dart:io'; + +import 'package:bdk_dart/bdk.dart'; +import 'package:test/test.dart'; + +import 'test_constants.dart'; + +const _fixtureName = 'pre_existing_wallet_persistence_test.sqlite'; + +String _copyFixtureToTempDir() { + final source = File('test/data/$_fixtureName'); + final tempDir = Directory.systemTemp.createTempSync('bdk_dart_persistence_'); + addTearDown(() => tempDir.delete(recursive: true)); + final destination = File('${tempDir.path}/$_fixtureName'); + destination.writeAsBytesSync(source.readAsBytesSync(), flush: true); + return destination.path; +} + +void main() { + group('Offline persistence', () { + test('loads sqlite wallet with private descriptors', () { + final dbPath = _copyFixtureToTempDir(); + final persister = Persister.newSqlite(dbPath); + final wallet = Wallet.load( + buildDescriptor(persistenceDescriptorString, Network.signet), + buildDescriptor(persistenceChangeDescriptorString, Network.signet), + persister, + defaultLookahead, + ); + + final addressInfo = wallet.revealNextAddress(KeychainKind.external_); + final expectedAddress = Address(expectedPersistedAddress, Network.signet); + + expect(addressInfo.index, equals(7)); + expect( + addressInfo.address.scriptPubkey().toBytes(), + orderedEquals(expectedAddress.scriptPubkey().toBytes()), + ); + }); + + test('loads sqlite wallet with public descriptors', () { + final dbPath = _copyFixtureToTempDir(); + final persister = Persister.newSqlite(dbPath); + final wallet = Wallet.load( + buildDescriptor(persistencePublicDescriptorString, Network.signet), + buildDescriptor( + persistencePublicChangeDescriptorString, Network.signet), + persister, + defaultLookahead, + ); + + final addressInfo = wallet.revealNextAddress(KeychainKind.external_); + + expect(addressInfo.index, equals(7)); + final expectedAddress = Address(expectedPersistedAddress, Network.signet); + expect( + addressInfo.address.scriptPubkey().toBytes(), + orderedEquals(expectedAddress.scriptPubkey().toBytes()), + ); + }); + }); +} diff --git a/test/offline_wallet_test.dart b/test/offline_wallet_test.dart new file mode 100644 index 0000000..420e478 --- /dev/null +++ b/test/offline_wallet_test.dart @@ -0,0 +1,53 @@ +import 'package:bdk_dart/bdk.dart'; +import 'package:test/test.dart'; + +import 'test_constants.dart'; + +void main() { + group('Offline wallet', () { + test('revealNextAddress yields expected address on multiple networks', () { + final descriptor = + buildDescriptor(offlineDescriptorString, Network.signet); + final changeDescriptor = + buildDescriptor(offlineChangeDescriptorString, Network.signet); + final persister = Persister.newInMemory(); + final wallet = Wallet( + descriptor, + changeDescriptor, + Network.signet, + persister, + defaultLookahead, + ); + + final addressInfo = wallet.revealNextAddress(KeychainKind.external_); + final expectedAddress = Address(expectedOfflineAddress, Network.signet); + + expect(addressInfo.address.isValidForNetwork(Network.testnet), isTrue); + expect(addressInfo.address.isValidForNetwork(Network.testnet4), isTrue); + expect(addressInfo.address.isValidForNetwork(Network.signet), isTrue); + expect(addressInfo.address.isValidForNetwork(Network.regtest), isFalse); + expect(addressInfo.address.isValidForNetwork(Network.bitcoin), isFalse); + expect( + addressInfo.address.scriptPubkey().toBytes(), + orderedEquals(expectedAddress.scriptPubkey().toBytes()), + ); + }); + + test('new wallet starts with zero balance', () { + final descriptor = + buildDescriptor(offlineDescriptorString, Network.signet); + final changeDescriptor = + buildDescriptor(offlineChangeDescriptorString, Network.signet); + final persister = Persister.newInMemory(); + final wallet = Wallet( + descriptor, + changeDescriptor, + Network.signet, + persister, + defaultLookahead, + ); + + expect(wallet.balance().total.toSat(), equals(0)); + }); + }); +} diff --git a/test/test_constants.dart b/test/test_constants.dart new file mode 100644 index 0000000..0c6028b --- /dev/null +++ b/test/test_constants.dart @@ -0,0 +1,75 @@ +import 'package:bdk_dart/bdk.dart'; + +const testExtendedPrivKey = + "tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B"; +const bip84TestReceivePath = "84h/1h/0h/0"; +const bip84TestChangePath = "84h/1h/0h/1"; +const bip86TestReceivePath = "86h/1h/0h/0"; +const bip86TestChangePath = "86h/1h/0h/1"; + +const mainnetExtendedPrivKey = + "xprv9s21ZrQH143K3LRcTnWpaCSYb75ic2rGuSgicmJhSVQSbfaKgPXfa8PhnYszgdcyWLoc8n1E2iHUnskjgGTAyCEpJYv7fqKxUcRNaVngA1V"; +const bip84MainnetReceivePath = "84h/0h/0h/1"; +const bip86MainnetReceivePath = "86h/0h/0h/1"; + +const offlineDescriptorString = + "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/1h/0/*)"; +const offlineChangeDescriptorString = + "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/1h/1/*)"; + +const persistenceDescriptorString = + "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)"; +const persistenceChangeDescriptorString = + "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/1/*)"; +const persistencePublicDescriptorString = + "wpkh([9122d9e0/84'/1'/0']tpubDCYVtmaSaDzTxcgvoP5AHZNbZKZzrvoNH9KARep88vESc6MxRqAp4LmePc2eeGX6XUxBcdhAmkthWTDqygPz2wLAyHWisD299Lkdrj5egY6/0/*)#zpaanzgu"; +const persistencePublicChangeDescriptorString = + "wpkh([9122d9e0/84'/1'/0']tpubDCYVtmaSaDzTxcgvoP5AHZNbZKZzrvoNH9KARep88vESc6MxRqAp4LmePc2eeGX6XUxBcdhAmkthWTDqygPz2wLAyHWisD299Lkdrj5egY6/1/*)#n4cuwhcy"; + +const multipathDescriptorString = + "wpkh([9a6a2580/84'/0'/0']xpub6DEzNop46vmxR49zYWFnMwmEfawSNmAMf6dLH5YKDY463twtvw1XD7ihwJRLPRGZJz799VPFzXHpZu6WdhT29WnaeuChS6aZHZPFmqczR5K/<0;1>/*)"; +const privateMultipathDescriptorString = + "tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/<0;1>/*)"; + +const expectedOfflineAddress = "tb1qhjys9wxlfykmte7ftryptx975uqgd6kcm6a7z4"; +const expectedPersistedAddress = "tb1qan3lldunh37ma6c0afeywgjyjgnyc8uz975zl2"; + +Descriptor buildDescriptor(String descriptor, Network network) => + Descriptor(descriptor, network); + +Descriptor buildBip84Descriptor(Network network) => Descriptor( + "wpkh($testExtendedPrivKey/$bip84TestReceivePath/*)", + network, + ); + +Descriptor buildBip84ChangeDescriptor(Network network) => Descriptor( + "wpkh($testExtendedPrivKey/$bip84TestChangePath/*)", + network, + ); + +Descriptor buildBip86Descriptor(Network network) => Descriptor( + "tr($testExtendedPrivKey/$bip86TestReceivePath/*)", + network, + ); + +Descriptor buildBip86ChangeDescriptor(Network network) => Descriptor( + "tr($testExtendedPrivKey/$bip86TestChangePath/*)", + network, + ); + +Descriptor buildMainnetBip84Descriptor() => Descriptor( + "wpkh($mainnetExtendedPrivKey/$bip84MainnetReceivePath/*)", + Network.bitcoin, + ); + +Descriptor buildMainnetBip86Descriptor() => Descriptor( + "tr($mainnetExtendedPrivKey/$bip86MainnetReceivePath/*)", + Network.bitcoin, + ); + +Descriptor buildNonExtendedDescriptor(int index) => Descriptor( + "wpkh($testExtendedPrivKey/$bip84TestReceivePath/$index)", + Network.testnet, + ); + +const defaultLookahead = 25; diff --git a/test/wallet_behavior_test.dart b/test/wallet_behavior_test.dart new file mode 100644 index 0000000..981c982 --- /dev/null +++ b/test/wallet_behavior_test.dart @@ -0,0 +1,55 @@ +import 'package:bdk_dart/bdk.dart'; +import 'package:test/test.dart'; + +import 'test_constants.dart'; + +Wallet _buildTestWallet() { + final persister = Persister.newInMemory(); + return Wallet( + buildBip84Descriptor(Network.testnet), + buildBip84ChangeDescriptor(Network.testnet), + Network.testnet, + persister, + defaultLookahead, + ); +} + +void main() { + group('Wallet behaviour', () { + test('produces addresses valid for expected networks', () { + final wallet = _buildTestWallet(); + final addressInfo = wallet.revealNextAddress(KeychainKind.external_); + + expect(addressInfo.address.isValidForNetwork(Network.testnet), isTrue); + expect(addressInfo.address.isValidForNetwork(Network.testnet4), isTrue); + expect(addressInfo.address.isValidForNetwork(Network.signet), isTrue); + expect(addressInfo.address.isValidForNetwork(Network.regtest), isFalse); + expect(addressInfo.address.isValidForNetwork(Network.bitcoin), isFalse); + }); + + test('starts with zero balance before sync', () { + final wallet = _buildTestWallet(); + expect(wallet.balance().total.toSat(), equals(0)); + }); + + test( + 'single-descriptor wallet returns identical external/internal addresses', + () { + final persister = Persister.newInMemory(); + final wallet = Wallet.createSingle( + buildBip84Descriptor(Network.testnet), + Network.testnet, + persister, + defaultLookahead, + ); + + final externalAddress = wallet.peekAddress(KeychainKind.external_, 0); + final internalAddress = wallet.peekAddress(KeychainKind.internal, 0); + + expect( + externalAddress.address.scriptPubkey().toBytes(), + orderedEquals(internalAddress.address.scriptPubkey().toBytes()), + ); + }); + }); +} diff --git a/test/wallet_creation_test.dart b/test/wallet_creation_test.dart new file mode 100644 index 0000000..de40f2a --- /dev/null +++ b/test/wallet_creation_test.dart @@ -0,0 +1,102 @@ +import 'package:bdk_dart/bdk.dart'; +import 'package:test/test.dart'; + +import 'test_constants.dart'; + +Wallet _createWallet( + Descriptor descriptor, + Descriptor changeDescriptor, +) { + final persister = Persister.newInMemory(); + return Wallet( + descriptor, + changeDescriptor, + Network.testnet, + persister, + defaultLookahead, + ); +} + +void main() { + group('Wallet construction', () { + test('creates WPKH wallet', () { + expect( + () => _createWallet( + buildBip84Descriptor(Network.testnet), + buildBip84ChangeDescriptor(Network.testnet), + ), + returnsNormally, + ); + }); + + test('creates TR wallet', () { + expect( + () => _createWallet( + buildBip86Descriptor(Network.testnet), + buildBip86ChangeDescriptor(Network.testnet), + ), + returnsNormally, + ); + }); + + test('creates wallet with non-extended descriptors', () { + expect( + () => _createWallet( + buildNonExtendedDescriptor(0), + buildNonExtendedDescriptor(1), + ), + returnsNormally, + ); + }); + + test('creates single-descriptor wallet', () { + final persister = Persister.newInMemory(); + expect( + () => Wallet.createSingle( + buildBip86Descriptor(Network.testnet), + Network.testnet, + persister, + defaultLookahead, + ), + returnsNormally, + ); + }); + + test('creates wallet from public multipath descriptor', () { + final persister = Persister.newInMemory(); + expect( + () => Wallet.createFromTwoPathDescriptor( + buildDescriptor(multipathDescriptorString, Network.bitcoin), + Network.bitcoin, + persister, + defaultLookahead, + ), + returnsNormally, + ); + }); + + test('fails for private multipath descriptor', () { + expect( + () => buildDescriptor( + privateMultipathDescriptorString, + Network.testnet, + ), + throwsA(isA()), + ); + }); + + test('fails when descriptors do not match network', () { + final persister = Persister.newInMemory(); + expect( + () => Wallet( + buildNonExtendedDescriptor(0), + buildNonExtendedDescriptor(1), + Network.bitcoin, + persister, + defaultLookahead, + ), + throwsA(isA()), + ); + }); + }); +} diff --git a/uniffi-bindgen.rs b/uniffi-bindgen.rs index d96eac7..d153d35 100644 --- a/uniffi-bindgen.rs +++ b/uniffi-bindgen.rs @@ -1,3 +1,34 @@ fn main() { - uniffi::uniffi_bindgen_main() -} \ No newline at end of file + // Minimal CLI that mirrors the custom behavior without modifying submodule + let args: Vec = std::env::args().collect(); + let language = args + .iter() + .position(|arg| arg == "--language") + .and_then(|idx| args.get(idx + 1)); + let is_dart = language.map(|lang| lang == "dart").unwrap_or(false); + + if is_dart { + let library_path = args + .iter() + .position(|arg| arg == "--library") + .and_then(|idx| args.get(idx + 1)) + .expect("specify the library path with --library"); + let output_dir = args + .iter() + .position(|arg| arg == "--out-dir") + .and_then(|idx| args.get(idx + 1)) + .expect("--out-dir is required when using --library"); + + uniffi_dart::gen::generate_dart_bindings( + "bdk-ffi/bdk-ffi/src/bdk.udl".into(), + None, + Some(output_dir.as_str().into()), + library_path.as_str().into(), + true, + ) + .expect("Failed to generate dart bindings"); + return; + } + + uniffi::uniffi_bindgen_main(); +} diff --git a/uniffi-dart b/uniffi-dart deleted file mode 160000 index f59dab4..0000000 --- a/uniffi-dart +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f59dab4cd9962c09b31969cc3c5f4f8b436369db