Repository: bitcoindevkit/bdk-ffi (language: python)

Issue:
Long-term solution exploration for generating correct Python wheels
As explained [here](https://github.com/mozilla/uniffi-rs/issues/1307), the Python scaffolding code does not currently find the native binaries on its own. We have a workaround, but don't think it's an optimal solution for the long run.

After some discussion with the team at Mozilla, I'm opening this issue to keep track of different approaches that could solve our issue.

1. The solution implemented by [Glean in their setup.py file](https://github.com/mozilla/glean/blob/main/glean-core/python/setup.py)
2. Leveraging [maturin](https://github.com/pyo3/maturin/).


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/cont_integration.yml b/.github/workflows/cont_integration.yml
index af447591..63c29b47 100644
--- a/.github/workflows/cont_integration.yml
+++ b/.github/workflows/cont_integration.yml
@@ -8,7 +8,6 @@ on:
       - "bdk-ffi/**"
 
 jobs:
-
   build-test:
     name: Build and test
     runs-on: ubuntu-latest
@@ -41,12 +40,12 @@ jobs:
       - name: Update toolchain
         run: rustup update
       - name: Build
-        run: cargo build
+        run: cargo build --features uniffi/cli
       - name: Clippy
         if: ${{ matrix.rust.clippy }}
-        run: cargo clippy --all-targets -- -D warnings
+        run: cargo clippy --all-targets --features "uniffi/bindgen-tests uniffi/cli" -- -D warnings
       - name: Test
-        run: CLASSPATH=./tests/jna/jna-5.8.0.jar cargo test
+        run: CLASSPATH=./tests/jna/jna-5.8.0.jar cargo test --features uniffi/bindgen-tests,uniffi/cli
 
   fmt:
     name: Rust fmt
diff --git a/.github/workflows/publish-python.yaml b/.github/workflows/publish-python.yaml
index b5b8a415..ba4d81ce 100644
--- a/.github/workflows/publish-python.yaml
+++ b/.github/workflows/publish-python.yaml
@@ -8,8 +8,8 @@ on: [workflow_dispatch]
 
 jobs:
   build-manylinux2014-x86_64-wheel:
-    name: 'Build Manylinux 2014 x86_64 wheel'
-    runs-on: ubuntu-latest
+    name: "Build Manylinux 2014 x86_64 wheel"
+    runs-on: ubuntu-22.04
     defaults:
       run:
         working-directory: bdk-python
@@ -17,7 +17,7 @@ jobs:
       image: quay.io/pypa/manylinux2014_x86_64
       env:
         PLAT: manylinux2014_x86_64
-        PYBIN: '/opt/python/${{ matrix.python }}/bin'
+        PYBIN: "/opt/python/${{ matrix.python }}/bin"
     strategy:
       matrix:
         python: # Update this list whenever the docker image is updated (check /opt/python/)
@@ -29,29 +29,31 @@ jobs:
           - pp37-pypy37_pp73
           - pp38-pypy38_pp73
     steps:
-      - name: checkout
+      - name: "Checkout"
         uses: actions/checkout@v2
         with:
           submodules: true
       - uses: actions-rs/toolchain@v1
         with:
           toolchain: stable
-      - name: install requirements
+
+      - name: "Install requirements"
         run: ${PYBIN}/pip install -r requirements.txt
-      - name: generate bindings
+
+      - name: "Generate bdk.py"
         run: bash generate.sh
-      - name: build wheel
-        run: ${PYBIN}/pip wheel . --no-deps -w /tmp/wheelhouse
-      - name: repair wheel
-        run: auditwheel repair /tmp/wheelhouse/* --plat "$PLAT" -w /tmp/wheelhouse-repaired
+
+      - name: "Build wheel"
+        run: ${PYBIN}/python setup.py bdist_wheel --verbose
+
       - uses: actions/upload-artifact@v2
         with:
           name: bdkpython-manylinux2014-x86_64-${{ matrix.python }}
-          path: /tmp/wheelhouse-repaired/*.whl
+          path: /home/runner/work/bdk-ffi/bdk-ffi/bdk-python/dist/*.whl
 
   build-macos-universal-wheel:
-    name: 'Build macOS universal wheel'
-    runs-on: macos-latest
+    name: "Build macOS universal wheel"
+    runs-on: macos-12
     defaults:
       run:
         working-directory: bdk-python
@@ -63,30 +65,34 @@ jobs:
           - '3.9'
           - '3.10'
     steps:
-      - name: checkout
+      - name: "Checkout"
         uses: actions/checkout@v2
         with:
           submodules: true
       - uses: actions/setup-python@v2
         with:
           python-version: ${{ matrix.python }}
-      - run: python3 --version
-      - run: rustup target add aarch64-apple-darwin
-      - run: pip3 install --user -r requirements.txt
-      - run: pip3 install --user wheel
-      - run: bash generate.sh
-      - name: build wheel
+
+      - name: "Generate bdk.py"
+        run: |
+          python3 --version
+          rustup target add aarch64-apple-darwin
+          pip3 install --user -r requirements.txt
+          bash generate.sh
+
+      - name: "Build wheel"
         env:
           ARCHFLAGS: "-arch x86_64 -arch arm64"
-        run: python3 setup.py -v bdist_wheel
+        run: python3 setup.py bdist_wheel --verbose
+
       - uses: actions/upload-artifact@v2
         with:
           name: bdkpython-macos-${{ matrix.python }}
           path: /Users/runner/work/bdk-ffi/bdk-ffi/bdk-python/dist/*.whl
 
   build-windows-wheel:
-    name: 'Build windows wheel'
-    runs-on: windows-latest
+    name: "Build windows wheel"
+    runs-on: windows-2022
     defaults:
       run:
         working-directory: bdk-python
@@ -98,45 +104,44 @@ jobs:
           - '3.9'
           - '3.10'
     steps:
-      - name: checkout
+      - name: "Checkout"
         uses: actions/checkout@v2
         with:
           submodules: true
       - uses: actions/setup-python@v2
         with:
           python-version: ${{ matrix.python }}
-      - run: python --version
-      - run: pip install --user -r requirements.txt
-      - run: bash generate.sh
-        shell: bash
-      - run: pip install --user wheel
-      - name: build wheel
-        run: python setup.py -v bdist_wheel
+
+      - name: "Generate bdk.py"
+        run: |
+          python --version
+          pip install --user -r requirements.txt
+          bash generate.sh
+
+      - name: "Build wheel"
+        run: python setup.py bdist_wheel --verbose
+
       - uses: actions/upload-artifact@v2
         with:
           name: bdkpython-win-${{ matrix.python }}
           path: D:\a\bdk-ffi\bdk-ffi\bdk-python\dist\*.whl
 
   publish-pypi:
-    name: 'Publish on PyPI'
-    runs-on: ubuntu-latest
+    name: "Publish on PyPI"
+    runs-on: ubuntu-22.04
     defaults:
       run:
         working-directory: bdk-python
     needs: [build-manylinux2014-x86_64-wheel, build-macos-universal-wheel, build-windows-wheel]
-    # needs: [build-macos-universal-wheel]
     steps:
-      - name: Checkout
+      - name: "Checkout"
         uses: actions/checkout@v2
 
-      - name: 'Download artifacts in dist/ directory'
+      - name: "Download artifacts in dist/ directory"
         uses: actions/download-artifact@v2
         with:
           path: dist/
 
-      # - name: Display structure of downloaded files
-      #   run: ls -R
-
       # - name: 'Publish on test PyPI'
       #   uses: pypa/gh-action-pypi-publish@release/v1
       #   with:
@@ -145,7 +150,7 @@ jobs:
       #     repository_url: https://test.pypi.org/legacy/
       #     packages_dir: dist/*/
 
-      - name: 'Publish on PyPI'
+      - name: "Publish on PyPI"
         uses: pypa/gh-action-pypi-publish@release/v1
         with:
           user: __token__
diff --git a/Cargo.lock b/Cargo.lock
index 4f8f533e..7e603bef 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -156,13 +156,11 @@ dependencies = [
 
 [[package]]
 name = "bdk-ffi"
-version = "0.27.0"
+version = "0.27.1"
 dependencies = [
  "assert_matches",
  "bdk",
  "uniffi",
- "uniffi_build",
- "uniffi_macros",
 ]
 
 [[package]]
@@ -172,7 +170,7 @@ dependencies = [
  "anyhow",
  "camino",
  "structopt",
- "uniffi_bindgen",
+ "uniffi_bindgen 0.21.1",
 ]
 
 [[package]]
@@ -309,15 +307,16 @@ dependencies = [
 
 [[package]]
 name = "cargo_metadata"
-version = "0.14.2"
+version = "0.15.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa"
+checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07"
 dependencies = [
  "camino",
  "cargo-platform",
  "semver",
  "serde",
  "serde_json",
+ "thiserror",
 ]
 
 [[package]]
@@ -514,6 +513,12 @@ dependencies = [
  "wasi",
 ]
 
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
 [[package]]
 name = "goblin"
 version = "0.5.4"
@@ -525,6 +530,17 @@ dependencies = [
  "scroll",
 ]
 
+[[package]]
+name = "goblin"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68"
+dependencies = [
+ "log",
+ "plain",
+ "scroll",
+]
+
 [[package]]
 name = "hashbrown"
 version = "0.12.3"
@@ -1179,6 +1195,26 @@ version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
 
+[[package]]
+name = "thiserror"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "tokio"
 version = "1.25.0"
@@ -1255,19 +1291,14 @@ checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
 
 [[package]]
 name = "uniffi"
-version = "0.21.1"
+version = "0.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b983553c0d1ad73547c65fa0c399aa800bee4a70ad330198e1c7a523212da5ee"
+checksum = "f71cc01459bc34cfe43fabf32b39f1228709bc6db1b3a664a92940af3d062376"
 dependencies = [
  "anyhow",
- "bytes",
- "camino",
- "cargo_metadata",
- "log",
- "once_cell",
- "paste",
- "static_assertions",
- "uniffi_bindgen",
+ "uniffi_bindgen 0.23.0",
+ "uniffi_build",
+ "uniffi_core",
  "uniffi_macros",
 ]
 
@@ -1283,26 +1314,50 @@ dependencies = [
  "camino",
  "clap 3.2.23",
  "fs-err",
- "goblin",
+ "goblin 0.5.4",
+ "heck 0.4.1",
+ "once_cell",
+ "paste",
+ "serde",
+ "serde_json",
+ "toml",
+ "uniffi_meta 0.21.1",
+ "weedle2",
+]
+
+[[package]]
+name = "uniffi_bindgen"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbbba5103051c18f10b22f80a74439ddf7100273f217a547005d2735b2498994"
+dependencies = [
+ "anyhow",
+ "askama",
+ "bincode",
+ "camino",
+ "fs-err",
+ "glob",
+ "goblin 0.6.1",
  "heck 0.4.1",
  "once_cell",
  "paste",
  "serde",
  "serde_json",
  "toml",
- "uniffi_meta",
+ "uniffi_meta 0.23.0",
+ "uniffi_testing",
  "weedle2",
 ]
 
 [[package]]
 name = "uniffi_build"
-version = "0.21.1"
+version = "0.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d035e50433ee3d52ab0dcdcf3b9b26f2cc2ec39294b3c07d95865a518709455f"
+checksum = "0ee1a28368ff3d83717e3d3e2e15a66269c43488c3f036914131bb68892f29fb"
 dependencies = [
  "anyhow",
  "camino",
- "uniffi_bindgen",
+ "uniffi_bindgen 0.23.0",
 ]
 
 [[package]]
@@ -1315,11 +1370,37 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "uniffi_checksum_derive"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03de61393a42b4ad4984a3763c0600594ac3e57e5aaa1d05cede933958987c03"
+dependencies = [
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "uniffi_core"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2b4852d638d74ca2d70e450475efb6d91fe6d54a7cd8d6bd80ad2ee6cd7daa"
+dependencies = [
+ "anyhow",
+ "bytes",
+ "camino",
+ "cargo_metadata",
+ "log",
+ "once_cell",
+ "paste",
+ "static_assertions",
+]
+
 [[package]]
 name = "uniffi_macros"
-version = "0.21.1"
+version = "0.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c96a574677566f83ea8458dac1dd7792fd63e7c3f9dbcd865f0e8d6f8057b127"
+checksum = "fa03394de21e759e0022f1ea8d992d2e39290d735b9ed52b1f74b20a684f794e"
 dependencies = [
  "bincode",
  "camino",
@@ -1331,7 +1412,7 @@ dependencies = [
  "syn",
  "toml",
  "uniffi_build",
- "uniffi_meta",
+ "uniffi_meta 0.23.0",
 ]
 
 [[package]]
@@ -1342,7 +1423,33 @@ checksum = "729835442da829c9b6f7c111c76cf87b2498e129101203bec94f0c39a3296a38"
 dependencies = [
  "serde",
  "siphasher",
- "uniffi_checksum_derive",
+ "uniffi_checksum_derive 0.21.1",
+]
+
+[[package]]
+name = "uniffi_meta"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "66fdab2c436aed7a6391bec64204ec33948bfed9b11b303235740771f85c4ea6"
+dependencies = [
+ "serde",
+ "siphasher",
+ "uniffi_checksum_derive 0.23.0",
+]
+
+[[package]]
+name = "uniffi_testing"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92b0570953ec41d97ce23e3b92161ac18231670a1f97523258a6d2ab76d7f76c"
+dependencies = [
+ "anyhow",
+ "camino",
+ "cargo_metadata",
+ "fs-err",
+ "once_cell",
+ "serde",
+ "serde_json",
 ]
 
 [[package]]
diff --git a/bdk-android/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiAndroidPlugin.kt b/bdk-android/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiAndroidPlugin.kt
index 4d2b16d9..7125126c 100644
--- a/bdk-android/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiAndroidPlugin.kt
+++ b/bdk-android/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiAndroidPlugin.kt
@@ -21,8 +21,7 @@ internal class UniFfiAndroidPlugin : Plugin<Project> {
         val buildAndroidAarch64Binary by tasks.register<Exec>("buildAndroidAarch64Binary") {
 
             workingDir("${projectDir}/../../bdk-ffi")
-            val cargoArgs: MutableList<String> =
-                mutableListOf("build", "--profile", "release-smaller", "--target", "aarch64-linux-android")
+            val cargoArgs: List<String> = listOf("build", "--features", "uniffi/cli", "--profile", "release-smaller", "--target", "aarch64-linux-android")
 
             executable("cargo")
             args(cargoArgs)
@@ -36,9 +35,7 @@ internal class UniFfiAndroidPlugin : Plugin<Project> {
 
             environment(
                 // add build toolchain to PATH
-                Pair("PATH",
-                    "${System.getenv("PATH")}:${System.getenv("ANDROID_NDK_ROOT")}/toolchains/llvm/prebuilt/$llvmArchPath/bin"),
-
+                Pair("PATH", "${System.getenv("PATH")}:${System.getenv("ANDROID_NDK_ROOT")}/toolchains/llvm/prebuilt/$llvmArchPath/bin"),
                 Pair("CFLAGS", "-D__ANDROID_API__=21"),
                 Pair("CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER", "aarch64-linux-android21-clang"),
                 Pair("CC", "aarch64-linux-android21-clang")
@@ -53,8 +50,7 @@ internal class UniFfiAndroidPlugin : Plugin<Project> {
         val buildAndroidX86_64Binary by tasks.register<Exec>("buildAndroidX86_64Binary") {
 
             workingDir("${project.projectDir}/../../bdk-ffi")
-            val cargoArgs: MutableList<String> =
-                mutableListOf("build", "--profile", "release-smaller", "--target", "x86_64-linux-android")
+            val cargoArgs: List<String> = listOf("build", "--features", "uniffi/cli", "--profile", "release-smaller", "--target", "x86_64-linux-android")
 
             executable("cargo")
             args(cargoArgs)
@@ -68,9 +64,7 @@ internal class UniFfiAndroidPlugin : Plugin<Project> {
 
             environment(
                 // add build toolchain to PATH
-                Pair("PATH",
-                    "${System.getenv("PATH")}:${System.getenv("ANDROID_NDK_ROOT")}/toolchains/llvm/prebuilt/$llvmArchPath/bin"),
-
+                Pair("PATH", "${System.getenv("PATH")}:${System.getenv("ANDROID_NDK_ROOT")}/toolchains/llvm/prebuilt/$llvmArchPath/bin"),
                 Pair("CFLAGS", "-D__ANDROID_API__=21"),
                 Pair("CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER", "x86_64-linux-android21-clang"),
                 Pair("CC", "x86_64-linux-android21-clang")
@@ -85,8 +79,7 @@ internal class UniFfiAndroidPlugin : Plugin<Project> {
         val buildAndroidArmv7Binary by tasks.register<Exec>("buildAndroidArmv7Binary") {
 
             workingDir("${project.projectDir}/../../bdk-ffi")
-            val cargoArgs: MutableList<String> =
-                mutableListOf("build", "--profile", "release-smaller", "--target", "armv7-linux-androideabi")
+            val cargoArgs: List<String> = listOf("build", "--features", "uniffi/cli", "--profile", "release-smaller", "--target", "armv7-linux-androideabi")
 
             executable("cargo")
             args(cargoArgs)
@@ -100,12 +93,9 @@ internal class UniFfiAndroidPlugin : Plugin<Project> {
 
             environment(
                 // add build toolchain to PATH
-                Pair("PATH",
-                    "${System.getenv("PATH")}:${System.getenv("ANDROID_NDK_ROOT")}/toolchains/llvm/prebuilt/$llvmArchPath/bin"),
-
+                Pair("PATH", "${System.getenv("PATH")}:${System.getenv("ANDROID_NDK_ROOT")}/toolchains/llvm/prebuilt/$llvmArchPath/bin"),
                 Pair("CFLAGS", "-D__ANDROID_API__=21"),
-                Pair("CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER",
-                    "armv7a-linux-androideabi21-clang"),
+                Pair("CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER", "armv7a-linux-androideabi21-clang"),
                 Pair("CC", "armv7a-linux-androideabi21-clang")
             )
 
@@ -145,17 +135,10 @@ internal class UniFfiAndroidPlugin : Plugin<Project> {
             dependsOn(moveNativeAndroidLibs)
 
             workingDir("${project.projectDir}/../../bdk-ffi")
+            val cargoArgs: List<String> = listOf("run", "--features", "uniffi/cli", "--bin", "uniffi-bindgen", "generate", "src/bdk.udl", "--language", "kotlin", "--out-dir", "../bdk-android/lib/src/main/kotlin", "--no-format")
+
             executable("cargo")
-            args(
-                "run",
-                "--package",
-                "bdk-ffi-bindgen",
-                "--",
-                "--language",
-                "kotlin",
-                "--out-dir",
-                "../bdk-android/lib/src/main/kotlin"
-            )
+            args(cargoArgs)
 
             doLast {
                 println("Android bindings file successfully created")
diff --git a/bdk-ffi/Cargo.toml b/bdk-ffi/Cargo.toml
index 07ad364d..78486688 100644
--- a/bdk-ffi/Cargo.toml
+++ b/bdk-ffi/Cargo.toml
@@ -1,21 +1,27 @@
 [package]
 name = "bdk-ffi"
-version = "0.27.0"
+version = "0.27.1"
 authors = ["Steve Myers <steve@notmandatory.org>", "Sudarsan Balaji <sudarsan.balaji@artfuldev.com>"]
 edition = "2018"
 license = "MIT OR Apache-2.0"
 
 [lib]
-crate-type = ["staticlib", "cdylib"]
+crate-type = ["lib", "staticlib", "cdylib"]
+#crate-type = ["staticlib", "cdylib"]
+#crate-type = ["cdylib"]
 name = "bdkffi"
 
+[[bin]]
+name = "uniffi-bindgen"
+path = "uniffi-bindgen.rs"
+
 [dependencies]
 bdk = { version = "0.27.1", features = ["all-keys", "use-esplora-ureq", "sqlite-bundled", "rpc"] }
-uniffi_macros = { version = "0.21.0", features = ["builtin-bindgen"] }
-uniffi = { version = "0.21.0", features = ["builtin-bindgen"] }
+uniffi = { version = "0.23.0" }
 
 [build-dependencies]
-uniffi_build = { version = "0.21.0", features = ["builtin-bindgen"] }
+uniffi = { version = "0.23.0", features = ["build"] }
 
 [dev-dependencies]
+uniffi = { version = "0.23.0", features = ["bindgen-tests"] }
 assert_matches = "1.5.0"
diff --git a/bdk-ffi/build.rs b/bdk-ffi/build.rs
index 153077fa..e1207e65 100644
--- a/bdk-ffi/build.rs
+++ b/bdk-ffi/build.rs
@@ -1,3 +1,3 @@
 fn main() {
-    uniffi_build::generate_scaffolding("src/bdk.udl").unwrap();
+    uniffi::generate_scaffolding("./src/bdk.udl").unwrap();
 }
diff --git a/bdk-ffi/src/lib.rs b/bdk-ffi/src/lib.rs
index 81dadb33..f82b6cb7 100644
--- a/bdk-ffi/src/lib.rs
+++ b/bdk-ffi/src/lib.rs
@@ -32,7 +32,7 @@ use std::io::Cursor;
 use std::str::FromStr;
 use std::sync::Arc;
 
-uniffi_macros::include_scaffolding!("bdk");
+uniffi::include_scaffolding!("bdk");
 
 /// A output script and an amount of satoshis.
 pub struct ScriptAmount {
diff --git a/bdk-ffi/uniffi-bindgen.rs b/bdk-ffi/uniffi-bindgen.rs
new file mode 100644
index 00000000..f6cff6cf
--- /dev/null
+++ b/bdk-ffi/uniffi-bindgen.rs
@@ -0,0 +1,3 @@
+fn main() {
+    uniffi::uniffi_bindgen_main()
+}
diff --git a/bdk-jvm/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiJvmPlugin.kt b/bdk-jvm/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiJvmPlugin.kt
index 3bad1859..75217bac 100644
--- a/bdk-jvm/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiJvmPlugin.kt
+++ b/bdk-jvm/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiJvmPlugin.kt
@@ -12,26 +12,26 @@ internal class UniFfiJvmPlugin : Plugin<Project> {
     override fun apply(target: Project): Unit = target.run {
 
         // register a task called buildJvmBinaries which will run something like
-        // cargo build --release --target aarch64-apple-darwin
+        // cargo build --features uniffi/cli --release --target aarch64-apple-darwin
         val buildJvmBinaries by tasks.register<DefaultTask>("buildJvmBinaries") {
             if (operatingSystem == OS.MAC) {
                 exec {
                     workingDir("${project.projectDir}/../../bdk-ffi")
                     executable("cargo")
-                    val cargoArgs: List<String> = listOf("build", "--profile", "release-smaller", "--target", "x86_64-apple-darwin")
+                    val cargoArgs: List<String> = listOf("build", "--features", "uniffi/cli", "--profile", "release-smaller", "--target", "x86_64-apple-darwin")
                     args(cargoArgs)
                 }
                 exec {
                     workingDir("${project.projectDir}/../../bdk-ffi")
                     executable("cargo")
-                    val cargoArgs: List<String> = listOf("build", "--profile", "release-smaller", "--target", "aarch64-apple-darwin")
+                    val cargoArgs: List<String> = listOf("build", "--features", "uniffi/cli", "--profile", "release-smaller", "--target", "aarch64-apple-darwin")
                     args(cargoArgs)
                 }
             } else if(operatingSystem == OS.LINUX) {
                 exec {
                     workingDir("${project.projectDir}/../../bdk-ffi")
                     executable("cargo")
-                    val cargoArgs: List<String> = listOf("build", "--profile", "release-smaller", "--target", "x86_64-unknown-linux-gnu")
+                    val cargoArgs: List<String> = listOf("build", "--features", "uniffi/cli", "--profile", "release-smaller", "--target", "x86_64-unknown-linux-gnu")
                     args(cargoArgs)
                 }
             }
@@ -90,17 +90,10 @@ internal class UniFfiJvmPlugin : Plugin<Project> {
             dependsOn(moveNativeJvmLibs)
 
             workingDir("${project.projectDir}/../../bdk-ffi")
+            val cargoArgs: List<String> = listOf("run", "--features", "uniffi/cli", "--bin", "uniffi-bindgen", "generate", "src/bdk.udl", "--language", "kotlin", "--out-dir", "../bdk-jvm/lib/src/main/kotlin", "--no-format")
+
             executable("cargo")
-            args(
-                "run",
-                "--package",
-                "bdk-ffi-bindgen",
-                "--",
-                "--language",
-                "kotlin",
-                "--out-dir",
-                "../bdk-jvm/lib/src/main/kotlin"
-            )
+            args(cargoArgs)
 
             doLast {
                 println("JVM bindings file successfully created")
diff --git a/bdk-python/MANIFEST.in b/bdk-python/MANIFEST.in
new file mode 100644
index 00000000..b3702f71
--- /dev/null
+++ b/bdk-python/MANIFEST.in
@@ -0,0 +1,2 @@
+include ./src/bdkpython/libbdkffi.dylib
+include ./src/bdkpython/libbdkffi.so
diff --git a/bdk-python/README.md b/bdk-python/README.md
index 4cc8ed99..45cf3c6a 100644
--- a/bdk-python/README.md
+++ b/bdk-python/README.md
@@ -11,10 +11,10 @@ pip install bdkpython
 
 ## Run the tests
 ```shell
-pip3 install --requirement requirements.txt
+pip install --requirement requirements.txt
 bash ./generate.sh
-python3 setup.py --verbose bdist_wheel
-pip3 install ./dist/bdkpython-<yourversion>-py3-none-any.whl
+python setup.py bdist_wheel --verbose
+pip install ./dist/bdkpython-<yourversion>-py3-none-any.whl --force-reinstall
 python -m unittest --verbose tests/test_bdk.py
 ```
 
@@ -23,11 +23,11 @@ python -m unittest --verbose tests/test_bdk.py
 # Install dependencies
 pip install --requirement requirements.txt
 
-# Generate the bindings first
+# Generate the bindings
 bash generate.sh
 
 # Build the wheel
-python3 setup.py --verbose bdist_wheel
+python setup.py --verbose bdist_wheel
 ```
 
 ## Run tox to build and test locally
@@ -35,7 +35,7 @@ python3 setup.py --verbose bdist_wheel
 # install dev requirements
 pip install --requirement requirements-dev.txt
 
-# build bindings glue code (located at .bdk-python/src/bdkpython/bdk.py)
+# build bindings glue code (located at ./src/bdkpython/bdk.py)
 source ./generate.sh
 
 # build and test
diff --git a/bdk-python/generate.sh b/bdk-python/generate.sh
index a53a5ff7..90a5f659 100644
--- a/bdk-python/generate.sh
+++ b/bdk-python/generate.sh
@@ -1,11 +1,24 @@
 #!/usr/bin/env bash
 
 set -euo pipefail
-
-SCRIPT_DIR=$(dirname "$(realpath $0)")
-PY_SRC="${SCRIPT_DIR}/src/bdkpython/"
+OS=$(uname -s)
 
 echo "Generating bdk.py..."
-# GENERATE_PYTHON_BINDINGS_OUT="$PY_SRC" GENERATE_PYTHON_BINDINGS_FIXUP_LIB_PATH=bdkffi cargo run --manifest-path ./bdk-ffi/Cargo.toml --release --bin generate --features generate-python
-# BDKFFI_BINDGEN_PYTHON_FIXUP_PATH=bdkffi cargo run --manifest-path ./bdk-ffi/Cargo.toml --package bdk-ffi-bindgen -- --language python --udl-file ./bdk-ffi/src/bdk.udl --out-dir ./src/bdkpython/
-BDKFFI_BINDGEN_OUTPUT_DIR="$PY_SRC" BDKFFI_BINDGEN_PYTHON_FIXUP_PATH=bdkffi cargo run --manifest-path ../bdk-ffi/Cargo.toml --package bdk-ffi-bindgen -- --language python --udl-file ../bdk-ffi/src/bdk.udl
+cd ../bdk-ffi/
+cargo run --features uniffi/cli --bin uniffi-bindgen generate src/bdk.udl --language python --out-dir ../bdk-python/src/bdkpython/ --no-format
+
+echo "Generating native binaries..."
+cargo build --features uniffi/cli --profile release-smaller
+case $OS in
+  "Darwin")
+    echo "Copying macOS libbdkffi.dylib..."
+    cp ../target/release-smaller/libbdkffi.dylib ../bdk-python/src/bdkpython/libbdkffi.dylib
+    ;;
+  "Linux")
+    echo "Copying linux libbdkffi.so..."
+    cp ../target/release-smaller/libbdkffi.so ../bdk-python/src/bdkpython/libbdkffi.so
+    ;;
+esac
+cd ../bdk-python/
+
+echo "All done!"
diff --git a/bdk-python/requirements.txt b/bdk-python/requirements.txt
index d6ba728f..959ed447 100644
--- a/bdk-python/requirements.txt
+++ b/bdk-python/requirements.txt
@@ -1,3 +1,4 @@
 semantic-version==2.9.0
-setuptools-rust==1.1.2
 typing_extensions==4.0.1
+setuptools==67.4.0
+wheel==0.38.4
diff --git a/bdk-python/setup.py b/bdk-python/setup.py
index 84555d23..8a1720b4 100644
--- a/bdk-python/setup.py
+++ b/bdk-python/setup.py
@@ -1,9 +1,6 @@
 #!/usr/bin/env python
 
-import os
-
 from setuptools import setup
-from setuptools_rust import Binding, RustExtension
 
 LONG_DESCRIPTION = """# bdkpython
 The Python language bindings for the [Bitcoin Dev Kit](https://github.com/bitcoindevkit).
@@ -52,22 +49,16 @@
 print(f"Wallet balance is: {balance.total}")
 """
 
-rust_ext = RustExtension(
-    target="bdkpython.bdkffi",
-    path="../bdk-ffi/Cargo.toml",
-    binding=Binding.NoBinding,
-)
-
 setup(
-    name='bdkpython',
-    version='0.28.0.dev0',
+    name="bdkpython",
+    version="0.28.0.dev0",
     description="The Python language bindings for the Bitcoin Development Kit",
     long_description=LONG_DESCRIPTION,
-    long_description_content_type='text/markdown',
-    rust_extensions=[rust_ext],
+    long_description_content_type="text/markdown",
+    include_package_data = True,
     zip_safe=False,
-    packages=['bdkpython'],
-    package_dir={'bdkpython': './src/bdkpython'},
+    packages=["bdkpython"],
+    package_dir={"bdkpython": "./src/bdkpython"},
     url="https://github.com/bitcoindevkit/bdk-ffi",
     author="Alekos Filini <alekos.filini@gmail.com>, Steve Myers <steve@notmandatory.org>",
     license="MIT or Apache 2.0",
diff --git a/bdk-python/src/bdkpython/__init__.py b/bdk-python/src/bdkpython/__init__.py
index 0b0ba051..67de00c8 100644
--- a/bdk-python/src/bdkpython/__init__.py
+++ b/bdk-python/src/bdkpython/__init__.py
@@ -1,1 +1,1 @@
-from bdkpython.bdk import *
+from bdkpython.bdk import *
\ No newline at end of file
diff --git a/bdk-python/tox.ini b/bdk-python/tox.ini
index c01a149f..32ced941 100644
--- a/bdk-python/tox.ini
+++ b/bdk-python/tox.ini
@@ -10,7 +10,7 @@ deps =
     -rrequirements.txt
     -rrequirements-dev.txt
 commands = 
-    python3 setup.py -v build
-    python3 setup.py -v install
+    python3 setup.py build --verbose
+    python3 setup.py install --verbose
     pytest --verbose --override-ini console_output_style=count
-    python3 setup.py --verbose bdist_wheel
+    python3 setup.py bdist_wheel --verbose
diff --git a/bdk-swift/build-local-swift.sh b/bdk-swift/build-local-swift.sh
index 1fdb3ff1..dac45672 100755
--- a/bdk-swift/build-local-swift.sh
+++ b/bdk-swift/build-local-swift.sh
@@ -13,14 +13,14 @@ rustup target add aarch64-apple-darwin x86_64-apple-darwin
 
 pushd bdk-ffi
 mkdir -p Sources/BitcoinDevKit
-cargo run --package bdk-ffi-bindgen -- --language swift --out-dir ../bdk-swift/Sources/BitcoinDevKit
+cargo run --features uniffi/cli --bin uniffi-bindgen generate src/bdk.udl --language swift --out-dir ../bdk-swift/Sources/BitcoinDevKit --no-format
 popd
 
-cargo build --package bdk-ffi --profile release-smaller --target x86_64-apple-darwin
-cargo build --package bdk-ffi --profile release-smaller --target aarch64-apple-darwin
-cargo build --package bdk-ffi --profile release-smaller --target x86_64-apple-ios
-cargo build --package bdk-ffi --profile release-smaller --target aarch64-apple-ios
-cargo +nightly build --package bdk-ffi --release -Z build-std --target aarch64-apple-ios-sim
+cargo build --package bdk-ffi --features uniffi/cli --profile release-smaller --target x86_64-apple-darwin
+cargo build --package bdk-ffi --features uniffi/cli --profile release-smaller --target aarch64-apple-darwin
+cargo build --package bdk-ffi --features uniffi/cli --profile release-smaller --target x86_64-apple-ios
+cargo build --package bdk-ffi --features uniffi/cli --profile release-smaller --target aarch64-apple-ios
+cargo +nightly build --package bdk-ffi --features uniffi/cli --release -Z build-std --target aarch64-apple-ios-sim
 
 mkdir -p target/lipo-ios-sim/release-smaller
 lipo target/aarch64-apple-ios-sim/release/libbdkffi.a target/x86_64-apple-ios/release-smaller/libbdkffi.a -create -output target/lipo-ios-sim/release-smaller/libbdkffi.a


Test patch:
diff --git a/.github/workflows/build-python-wheels.yaml b/.github/workflows/test-python.yaml
similarity index 50%
rename from .github/workflows/build-python-wheels.yaml
rename to .github/workflows/test-python.yaml
index 75a15aab..c048be6c 100644
--- a/.github/workflows/build-python-wheels.yaml
+++ b/.github/workflows/test-python.yaml
@@ -1,4 +1,4 @@
-name: Build Python wheels
+name: Test Python
 on:
   push:
     paths:
@@ -16,8 +16,8 @@ on:
 
 jobs:
   build-manylinux2014-x86_64-wheel:
-    name: 'Build Manylinux 2014 x86_64 wheel'
-    runs-on: ubuntu-latest
+    name: "Build and test Manylinux 2014 x86_64 wheels"
+    runs-on: ubuntu-22.04
     defaults:
       run:
         working-directory: bdk-python
@@ -25,41 +25,48 @@ jobs:
       image: quay.io/pypa/manylinux2014_x86_64
       env:
         PLAT: manylinux2014_x86_64
-        PYBIN: '/opt/python/${{ matrix.python }}/bin'
+        PYBIN: "/opt/python/${{ matrix.python }}/bin"
     strategy:
       matrix:
-        python: # Update this list whenever the docker image is updated (check /opt/python/)
+        python:
           # - cp36-cp36m
           # - cp37-cp37m
           # - cp38-cp38
           # - cp39-cp39
           - cp310-cp310
-          # - pp37-pypy37_pp73
-          # - pp38-pypy38_pp73
     steps:
-      - name: checkout
+      - name: "Checkout"
         uses: actions/checkout@v2
         with:
           submodules: true
       - uses: actions-rs/toolchain@v1
         with:
           toolchain: stable
-      - name: install requirements
+
+      - name: "Install requirements"
         run: ${PYBIN}/pip install -r requirements.txt
-      - name: generate bindings
+
+      - name: "Generate bdk.py"
         run: bash generate.sh
-      - name: build wheel
-        run: ${PYBIN}/pip wheel . --no-deps -w /tmp/wheelhouse
-      - name: repair wheel
-        run: auditwheel repair /tmp/wheelhouse/* --plat "$PLAT" -w /tmp/wheelhouse-repaired
-      - uses: actions/upload-artifact@v2
+
+      - name: "Build wheel"
+        run: ${PYBIN}/python setup.py bdist_wheel --verbose
+
+      - name: Install wheel
+        run: ${PYBIN}/pip install ./dist/*.whl
+
+      - name: Run tests
+        run: ${PYBIN}/python -m unittest tests/test_bdk.py --verbose
+
+      - name: Upload artifact test
+        uses: actions/upload-artifact@v2
         with:
           name: bdkpython-manylinux2014-x86_64-${{ matrix.python }}
-          path: /tmp/wheelhouse-repaired/*.whl
+          path: /home/runner/work/bdk-ffi/bdk-ffi/bdk-python/dist/*.whl
 
   build-macos-universal-wheel:
-    name: 'Build macOS universal wheel'
-    runs-on: macos-latest
+    name: "Build and test macOS wheels"
+    runs-on: macos-12
     defaults:
       run:
         working-directory: bdk-python
@@ -71,30 +78,35 @@ jobs:
           # - '3.9'
           - '3.10'
     steps:
-      - name: checkout
+      - name: Checkout
         uses: actions/checkout@v2
         with:
           submodules: true
       - uses: actions/setup-python@v2
         with:
           python-version: ${{ matrix.python }}
-      - run: python3 --version
-      - run: rustup target add aarch64-apple-darwin
-      - run: pip3 install --user -r requirements.txt
-      - run: pip3 install --user wheel
-      - run: bash generate.sh
-      - name: build wheel
+
+      - name: "Generate bdk.py"
+        run: | 
+          python3 --version
+          rustup target add aarch64-apple-darwin
+          pip3 install --user -r requirements.txt
+          bash generate.sh
+
+      - name: "Build wheel"
         env:
           ARCHFLAGS: "-arch x86_64 -arch arm64"
-        run: python3 setup.py -v bdist_wheel
-      - uses: actions/upload-artifact@v2
-        with:
-          name: bdkpython-macos-${{ matrix.python }}
-          path: /Users/runner/work/bdk-ffi/bdk-ffi/bdk-python/dist/*.whl
+        run: python3 setup.py bdist_wheel --verbose
+
+      - name: Install wheel
+        run: pip3 install ./dist/*.whl
+
+      - name: Run tests
+        run: python3 -m unittest tests/test_bdk.py --verbose
 
   build-windows-wheel:
-    name: 'Build windows wheel'
-    runs-on: windows-latest
+    name: "Build and test Windows wheels"
+    runs-on: windows-2022
     defaults:
       run:
         working-directory: bdk-python
@@ -106,21 +118,30 @@ jobs:
           # - '3.9'
           - '3.10'
     steps:
-      - name: checkout
+      - name: "Checkout"
         uses: actions/checkout@v2
         with:
           submodules: true
       - uses: actions/setup-python@v2
         with:
           python-version: ${{ matrix.python }}
-      - run: python --version
-      - run: pip install --user -r requirements.txt
-      - run: bash generate.sh
-        shell: bash
-      - run: pip install --user wheel
-      - name: build wheel
-        run: python setup.py -v bdist_wheel
-      - uses: actions/upload-artifact@v2
-        with:
-          name: bdkpython-win-${{ matrix.python }}
-          path: D:\a\bdk-ffi\bdk-ffi\bdk-python\dist\*.whl
+
+      - name: "Generate bdk.py"
+        run: |
+          python --version
+          pip install --user -r requirements.txt
+          bash generate.sh
+
+      - name: "Build wheel"
+        run: python setup.py bdist_wheel --verbose
+
+      # TODO: On Windows the pip install ./dist/*.whl step fails with the following error:
+      # Run pip install ./dist/*.whl
+      # WARNING: Requirement './dist/*.whl' looks like a filename, but the file does not exist
+      # ERROR: *.whl is not a valid wheel filename.*.whl is not a valid wheel name
+      # So we skip the installing and the tests and simply test that the wheel builds
+
+      # - name: Install wheel
+      #   run: pip install ./dist/*.whl
+      # - name: Run tests
+      #   run: python -m unittest tests/test_bdk.py --verbose
diff --git a/.github/workflows/test-swift.yaml b/.github/workflows/test-swift.yaml
index 9aec8a21..784e8af2 100644
--- a/.github/workflows/test-swift.yaml
+++ b/.github/workflows/test-swift.yaml
@@ -24,13 +24,13 @@ jobs:
 
       - name: Run bdk-ffi-bindgen
         working-directory: bdk-ffi
-        run: cargo run --package bdk-ffi-bindgen -- --language swift --out-dir ../bdk-swift/Sources/BitcoinDevKit
+        run: cargo run --features uniffi/cli --bin uniffi-bindgen generate src/bdk.udl --language swift --out-dir ../bdk-swift/Sources/BitcoinDevKit --no-format
 
       - name: Build bdk-ffi for x86_64-apple-darwin
-        run: cargo build --profile release-smaller --target x86_64-apple-darwin
+        run: cargo build --package bdk-ffi --features uniffi/cli --profile release-smaller --target x86_64-apple-darwin
 
       - name: Build bdk-ffi for aarch64-apple-darwin
-        run: cargo build --profile release-smaller --target aarch64-apple-darwin
+        run: cargo build --package bdk-ffi --features uniffi/cli --profile release-smaller --target aarch64-apple-darwin
 
       - name: Create lipo-ios-sim and lipo-macos
         run: |
diff --git a/bdk-ffi/tests/test_generated_bindings.rs b/bdk-ffi/tests/test_generated_bindings.rs
index 943c2772..0f334db8 100644
--- a/bdk-ffi/tests/test_generated_bindings.rs
+++ b/bdk-ffi/tests/test_generated_bindings.rs
@@ -1,8 +1,5 @@
-uniffi_macros::build_foreign_language_testcases!(
-    ["src/bdk.udl",],
-    [
-        "tests/bindings/test.kts",
-        "tests/bindings/test.swift",
-        "tests/bindings/test.py"
-    ]
+uniffi::build_foreign_language_testcases!(
+    "tests/bindings/test.kts",
+    "tests/bindings/test.swift",
+    "tests/bindings/test.py",
 );