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

Issue:
RUSTSEC-2021-0139: ansi_term is Unmaintained

> ansi_term is Unmaintained

| Details             |                                                |
| ------------------- | ---------------------------------------------- |
| Status              | unmaintained                |
| Package             | `ansi_term`                      |
| Version             | `0.12.1`                   |
| URL                 | [https://github.com/ogham/rust-ansi-term/issues/72](https://github.com/ogham/rust-ansi-term/issues/72) |
| Date                | 2021-08-18                         |

The maintainer has adviced this crate is deprecated and will not
receive any maintenance.

The crate does not seem to have much dependencies and may or may not be ok to use as-is.

Last release seems to have been three years ago.

## Possible Alternative(s)

 The below list has not been vetted in any way and may or may not contain alternatives;

 - [anstyle](https://github.com/epage/anstyle)
 - [nu-ansi-term](https://crates.io/crates/nu-ansi-term)
 - [yansi](https://crates.io/crates/yansi)

See [advisory page](https://rustsec.org/advisories/RUSTSEC-2021-0139.html) for additional details.

Expose utility methods on the `Transaction` type
This issue is meant to open the discussion around exposing some utility functions defined in rust-bitcoin to the bindings.

After we merged the new [Transaction type](https://github.com/bitcoindevkit/bdk-ffi/pull/296) I started looking into what is available in it, and I think there might be value in bringing in at least 4 methods:
1. `weight()`
2. `size()`
3. `vsize()`
4. `is_absolute_timelock_satisfied()`



Discussion / hints:
This dependency comes from the `structopt` crate, which uses `clap` version `2.34.0`. From the structopt readme:
> As clap v3 is now out, and the structopt features are integrated into (almost as-is), structopt is now in maintenance mode: no new feature will be added.

I think the solution to this is to transition from `structopt` to `clap` (now on version `4.x`).


Fix patch:
diff --git a/.github/workflows/cont_integration.yml b/.github/workflows/cont_integration.yml
index f35a2bee..d9e47e6a 100644
--- a/.github/workflows/cont_integration.yml
+++ b/.github/workflows/cont_integration.yml
@@ -47,14 +47,14 @@ jobs:
         run: rustup update
 
       - name: Build
-        run: cargo build --features uniffi/cli
+        run: cargo build
 
       - name: Clippy
         if: ${{ matrix.rust.clippy }}
-        run: cargo clippy --all-targets --features "uniffi/bindgen-tests uniffi/cli" -- -D warnings
+        run: cargo clippy --all-targets --features "uniffi/bindgen-tests" -- -D warnings
 
       - name: Test
-        run: CLASSPATH=./tests/jna/jna-5.8.0.jar cargo test --features uniffi/bindgen-tests,uniffi/cli
+        run: CLASSPATH=./tests/jna/jna-5.8.0.jar cargo test --features uniffi/bindgen-tests
 
   fmt:
     name: Rust fmt
diff --git a/Cargo.lock b/Cargo.lock
index 7e603bef..07fbc818 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -19,15 +19,6 @@ dependencies = [
  "version_check",
 ]
 
-[[package]]
-name = "ansi_term"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
-dependencies = [
- "winapi",
-]
-
 [[package]]
 name = "anyhow"
 version = "1.0.69"
@@ -163,16 +154,6 @@ dependencies = [
  "uniffi",
 ]
 
-[[package]]
-name = "bdk-ffi-bindgen"
-version = "0.2.0"
-dependencies = [
- "anyhow",
- "camino",
- "structopt",
- "uniffi_bindgen 0.21.1",
-]
-
 [[package]]
 name = "bdk-macros"
 version = "0.6.0"
@@ -331,21 +312,6 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
-[[package]]
-name = "clap"
-version = "2.34.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
-dependencies = [
- "ansi_term",
- "atty",
- "bitflags",
- "strsim 0.8.0",
- "textwrap 0.11.0",
- "unicode-width",
- "vec_map",
-]
-
 [[package]]
 name = "clap"
 version = "3.2.23"
@@ -358,9 +324,9 @@ dependencies = [
  "clap_lex",
  "indexmap",
  "once_cell",
- "strsim 0.10.0",
+ "strsim",
  "termcolor",
- "textwrap 0.16.0",
+ "textwrap",
 ]
 
 [[package]]
@@ -369,7 +335,7 @@ version = "3.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
 dependencies = [
- "heck 0.4.1",
+ "heck",
  "proc-macro-error",
  "proc-macro2",
  "quote",
@@ -519,17 +485,6 @@ version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
 
-[[package]]
-name = "goblin"
-version = "0.5.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7666983ed0dd8d21a6f6576ee00053ca0926fb281a5522577a4dbd0f1b54143"
-dependencies = [
- "log",
- "plain",
- "scroll",
-]
-
 [[package]]
 name = "goblin"
 version = "0.6.1"
@@ -559,15 +514,6 @@ dependencies = [
  "hashbrown",
 ]
 
-[[package]]
-name = "heck"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
-dependencies = [
- "unicode-segmentation",
-]
-
 [[package]]
 name = "heck"
 version = "0.4.1"
@@ -640,12 +586,6 @@ dependencies = [
  "serde_json",
 ]
 
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
 [[package]]
 name = "libc"
 version = "0.2.139"
@@ -768,9 +708,9 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
 
 [[package]]
 name = "os_str_bytes"
-version = "6.4.1"
+version = "6.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
+checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267"
 
 [[package]]
 name = "parking_lot"
@@ -1124,42 +1064,12 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
 
-[[package]]
-name = "strsim"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
-
 [[package]]
 name = "strsim"
 version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
 
-[[package]]
-name = "structopt"
-version = "0.3.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10"
-dependencies = [
- "clap 2.34.0",
- "lazy_static",
- "structopt-derive",
-]
-
-[[package]]
-name = "structopt-derive"
-version = "0.4.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
-dependencies = [
- "heck 0.3.3",
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn",
-]
-
 [[package]]
 name = "syn"
 version = "1.0.107"
@@ -1180,15 +1090,6 @@ dependencies = [
  "winapi-util",
 ]
 
-[[package]]
-name = "textwrap"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
-dependencies = [
- "unicode-width",
-]
-
 [[package]]
 name = "textwrap"
 version = "0.16.0"
@@ -1197,18 +1098,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
 
 [[package]]
 name = "thiserror"
-version = "1.0.38"
+version = "1.0.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
+checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.38"
+version = "1.0.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
+checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1277,18 +1178,6 @@ dependencies = [
  "smallvec 0.6.14",
 ]
 
-[[package]]
-name = "unicode-segmentation"
-version = "1.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
-
-[[package]]
-name = "unicode-width"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
-
 [[package]]
 name = "uniffi"
 version = "0.23.0"
@@ -1296,35 +1185,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f71cc01459bc34cfe43fabf32b39f1228709bc6db1b3a664a92940af3d062376"
 dependencies = [
  "anyhow",
- "uniffi_bindgen 0.23.0",
+ "camino",
+ "clap",
+ "uniffi_bindgen",
  "uniffi_build",
  "uniffi_core",
  "uniffi_macros",
 ]
 
-[[package]]
-name = "uniffi_bindgen"
-version = "0.21.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d46080a4840abccf7c0cce21931dae53215cbd7dd969b5e63c486235ce91a2a"
-dependencies = [
- "anyhow",
- "askama",
- "bincode",
- "camino",
- "clap 3.2.23",
- "fs-err",
- "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"
@@ -1337,14 +1205,14 @@ dependencies = [
  "camino",
  "fs-err",
  "glob",
- "goblin 0.6.1",
- "heck 0.4.1",
+ "goblin",
+ "heck",
  "once_cell",
  "paste",
  "serde",
  "serde_json",
  "toml",
- "uniffi_meta 0.23.0",
+ "uniffi_meta",
  "uniffi_testing",
  "weedle2",
 ]
@@ -1357,17 +1225,7 @@ checksum = "0ee1a28368ff3d83717e3d3e2e15a66269c43488c3f036914131bb68892f29fb"
 dependencies = [
  "anyhow",
  "camino",
- "uniffi_bindgen 0.23.0",
-]
-
-[[package]]
-name = "uniffi_checksum_derive"
-version = "0.21.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78b6e16d46caf942016997af8bbdf4b163bf8ae3deb0b667d9643de7b7ffd4c9"
-dependencies = [
- "quote",
- "syn",
+ "uniffi_bindgen",
 ]
 
 [[package]]
@@ -1412,18 +1270,7 @@ dependencies = [
  "syn",
  "toml",
  "uniffi_build",
- "uniffi_meta 0.23.0",
-]
-
-[[package]]
-name = "uniffi_meta"
-version = "0.21.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "729835442da829c9b6f7c111c76cf87b2498e129101203bec94f0c39a3296a38"
-dependencies = [
- "serde",
- "siphasher",
- "uniffi_checksum_derive 0.21.1",
+ "uniffi_meta",
 ]
 
 [[package]]
@@ -1434,7 +1281,7 @@ checksum = "66fdab2c436aed7a6391bec64204ec33948bfed9b11b303235740771f85c4ea6"
 dependencies = [
  "serde",
  "siphasher",
- "uniffi_checksum_derive 0.23.0",
+ "uniffi_checksum_derive",
 ]
 
 [[package]]
@@ -1494,12 +1341,6 @@ version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
 
-[[package]]
-name = "vec_map"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
-
 [[package]]
 name = "version_check"
 version = "0.9.4"
diff --git a/Cargo.toml b/Cargo.toml
index b8d84b07..f36d6b82 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [workspace]
-members = ["bdk-ffi", "bdk-ffi-bindgen"]
-default-members = ["bdk-ffi", "bdk-ffi-bindgen"]
+members = ["bdk-ffi"]
+default-members = ["bdk-ffi"]
 exclude = ["api-docs", "bdk-android", "bdk-jvm", "bdk-python", "bdk-swift"]
 
 [profile.release-smaller]
@@ -9,4 +9,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 = true        # Strip symbols from binary*
\ No newline at end of file
+strip = true        # Strip symbols from binary*
diff --git a/api-docs/kotlin/src/main/kotlin/org/bitcoindevkit/bdk.kt b/api-docs/kotlin/src/main/kotlin/org/bitcoindevkit/bdk.kt
index 77ad251c..271d66cc 100644
--- a/api-docs/kotlin/src/main/kotlin/org/bitcoindevkit/bdk.kt
+++ b/api-docs/kotlin/src/main/kotlin/org/bitcoindevkit/bdk.kt
@@ -248,6 +248,7 @@ sealed class BlockchainConfig {
  * @property confirmationTime If the transaction is confirmed, [BlockTime] contains height and timestamp of the block containing the transaction. This property is null for unconfirmed transactions.
  */
 data class TransactionDetails (
+    var transaction?: Transaction,
     var fee: ULong?,
     var received: ULong,
     var sent: ULong,
@@ -288,8 +289,60 @@ class Blockchain(
  * @param transactionBytes The transaction bytes, bitcoin consensus encoded.
  */
 class Transaction(transactionBytes: List<UByte>) {
+    /** Computes the txid. */
+    fun txid(): String {}
+
+    /**
+     * Returns the "weight" of this transaction, as defined by BIP141.
+     *
+     * For transactions with an empty witness, this is simply the consensus-serialized size times four.
+     * For transactions with a witness, this is the non-witness consensus-serialized size multiplied by three
+     * plus the with-witness consensus-serialized size.
+     */
+    fun weight(): ULong {}
+
+    /** Returns the regular byte-wise consensus-serialized size of this transaction. */
+    fun size(): ULong {}
+
+    /**
+     * Returns the "virtual size" (vsize) of this transaction.
+     *
+     * Will be ceil(weight / 4.0). Note this implements the virtual size as per BIP141, which is different to
+     * what is implemented in Bitcoin Core. The computation should be the same for any remotely sane transaction.
+     */
+    fun vsize(): ULong {}
+
     /** Return the transaction bytes, bitcoin consensus encoded. */
     fun serialize(): List<UByte> {}
+
+    /** Is this a coin base transaction? */
+    fun isCoinBase(): Boolean {}
+
+    /**
+     * Returns true if the transaction itself opted in to be BIP-125-replaceable (RBF).
+     * This does not cover the case where a transaction becomes replaceable due to ancestors being RBF.
+     */
+    fun isExplicitlyRbf(): Boolean {}
+
+    /** Returns true if this transactions nLockTime is enabled (BIP-65). */
+    fun isLockTimeEnabled(): Boolean {}
+
+    /** The protocol version, is currently expected to be 1 or 2 (BIP 68). */
+    fun version(): Int {}
+
+    /**
+     * Block height or timestamp. Transaction cannot be included in a block until this height/time.
+     * Relevant BIPs
+     *     BIP-65 OP_CHECKLOCKTIMEVERIFY
+     *     BIP-113 Median time-past as endpoint for lock-time calculations
+     */
+    fun lockTime(): UInt {}
+
+    /** List of transaction inputs. */
+    fun input(): List<TxIn> {}
+
+    /** List of transaction outputs. */
+    fun output(): List<TxOut> {}
 }
 
 /**
@@ -331,11 +384,29 @@ data class OutPoint (
  * A transaction output, which defines new coins to be created from old ones.
  *
  * @property value The value of the output, in satoshis.
- * @property address The address of the output.
+ * @property scriptPubkey The script which must be satisfied for the output to be spent.
  */
 data class TxOut (
     var value: ULong,
-    var address: String
+    var scriptPubkey: Script
+)
+
+/**
+ * Bitcoin transaction input.
+ *
+ * It contains the location of the previous transaction’s output, that it spends and set of scripts that satisfy its spending conditions.
+ *
+ * @property previousOutput The reference to the previous output that is being used an an input.
+ * @property scriptSig The script which pushes values on the stack which will cause the referenced output’s script to be accepted.
+ * @property sequence The sequence number, which suggests to miners which of two conflicting transactions should be preferred, or 0xFFFFFFFF to ignore this feature. This is generally never used since the miner behaviour cannot be enforced.
+ * @property witness Witness data: an array of byte-arrays. Note that this field is not (de)serialized with the rest of the TxIn in Encodable/Decodable, as it is (de)serialized at the end of the full Transaction. It is (de)serialized with the rest of the TxIn in other (de)serialization routines.
+ *
+ */
+data class TxIn (
+    var previousOutput: OutPoint,
+    var scriptSig: Script,
+    var sequence: UInt,
+    var witness: List<List<UByte>>
 )
 
 /**
@@ -420,7 +491,7 @@ class Wallet(
     fun sign(psbt: PartiallySignedTransaction): Boolean {}
 
     /** Return the list of transactions made and received by the wallet. Note that this method only operate on the internal database, which first needs to be [Wallet.sync] manually. */
-    fun listTransactions(): List<TransactionDetails> {}
+    fun listTransactions(includeRaw: Boolean): List<TransactionDetails> {}
 
     /** Get the Bitcoin network the wallet is using. */
     fun network(): Network {}
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 7125126c..20200864 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,7 +21,7 @@ internal class UniFfiAndroidPlugin : Plugin<Project> {
         val buildAndroidAarch64Binary by tasks.register<Exec>("buildAndroidAarch64Binary") {
 
             workingDir("${projectDir}/../../bdk-ffi")
-            val cargoArgs: List<String> = listOf("build", "--features", "uniffi/cli", "--profile", "release-smaller", "--target", "aarch64-linux-android")
+            val cargoArgs: List<String> = listOf("build", "--profile", "release-smaller", "--target", "aarch64-linux-android")
 
             executable("cargo")
             args(cargoArgs)
@@ -36,7 +36,8 @@ 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("CFLAGS", "-D__ANDROID_API__=21"),
+                Pair("CFLAGS", "-D__ANDROID_MIN_SDK_VERSION__=21"),
+                Pair("AR", "llvm-ar"),
                 Pair("CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER", "aarch64-linux-android21-clang"),
                 Pair("CC", "aarch64-linux-android21-clang")
             )
@@ -50,7 +51,7 @@ internal class UniFfiAndroidPlugin : Plugin<Project> {
         val buildAndroidX86_64Binary by tasks.register<Exec>("buildAndroidX86_64Binary") {
 
             workingDir("${project.projectDir}/../../bdk-ffi")
-            val cargoArgs: List<String> = listOf("build", "--features", "uniffi/cli", "--profile", "release-smaller", "--target", "x86_64-linux-android")
+            val cargoArgs: List<String> = listOf("build", "--profile", "release-smaller", "--target", "x86_64-linux-android")
 
             executable("cargo")
             args(cargoArgs)
@@ -65,7 +66,8 @@ 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("CFLAGS", "-D__ANDROID_API__=21"),
+                Pair("CFLAGS", "-D__ANDROID_MIN_SDK_VERSION__=21"),
+                Pair("AR", "llvm-ar"),
                 Pair("CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER", "x86_64-linux-android21-clang"),
                 Pair("CC", "x86_64-linux-android21-clang")
             )
@@ -79,7 +81,7 @@ internal class UniFfiAndroidPlugin : Plugin<Project> {
         val buildAndroidArmv7Binary by tasks.register<Exec>("buildAndroidArmv7Binary") {
 
             workingDir("${project.projectDir}/../../bdk-ffi")
-            val cargoArgs: List<String> = listOf("build", "--features", "uniffi/cli", "--profile", "release-smaller", "--target", "armv7-linux-androideabi")
+            val cargoArgs: List<String> = listOf("build", "--profile", "release-smaller", "--target", "armv7-linux-androideabi")
 
             executable("cargo")
             args(cargoArgs)
@@ -94,7 +96,8 @@ 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("CFLAGS", "-D__ANDROID_API__=21"),
+                Pair("CFLAGS", "-D__ANDROID_MIN_SDK_VERSION__=21"),
+                Pair("AR", "llvm-ar"),
                 Pair("CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER", "armv7a-linux-androideabi21-clang"),
                 Pair("CC", "armv7a-linux-androideabi21-clang")
             )
@@ -135,7 +138,7 @@ 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")
+            val cargoArgs: List<String> = listOf("run", "--bin", "uniffi-bindgen", "generate", "src/bdk.udl", "--language", "kotlin", "--out-dir", "../bdk-android/lib/src/main/kotlin", "--no-format")
 
             executable("cargo")
             args(cargoArgs)
diff --git a/bdk-ffi-bindgen/Cargo.toml b/bdk-ffi-bindgen/Cargo.toml
deleted file mode 100644
index 87ee0bcc..00000000
--- a/bdk-ffi-bindgen/Cargo.toml
+++ /dev/null
@@ -1,10 +0,0 @@
-[package]
-name = "bdk-ffi-bindgen"
-version = "0.2.0"
-edition = "2021"
-
-[dependencies]
-anyhow = "1.0.45" # remove after upgrading to next version of uniffi
-structopt = "0.3"
-uniffi_bindgen = "0.21.0"
-camino = "1.0.9"
diff --git a/bdk-ffi-bindgen/src/main.rs b/bdk-ffi-bindgen/src/main.rs
deleted file mode 100644
index 8a87fc5a..00000000
--- a/bdk-ffi-bindgen/src/main.rs
+++ /dev/null
@@ -1,138 +0,0 @@
-use camino::Utf8Path;
-use std::fmt;
-use std::path::{Path, PathBuf};
-use std::str::FromStr;
-use structopt::StructOpt;
-
-#[derive(Debug, Eq, PartialEq)]
-pub enum Language {
-    Kotlin,
-    Python,
-    Swift,
-}
-
-impl fmt::Display for Language {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Language::Kotlin => write!(f, "kotlin"),
-            Language::Swift => write!(f, "swift"),
-            Language::Python => write!(f, "python"),
-        }
-    }
-}
-
-#[derive(Debug)]
-pub enum Error {
-    UnsupportedLanguage,
-}
-
-impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{:?}", self)
-    }
-}
-
-impl FromStr for Language {
-    type Err = Error;
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        match s {
-            "kotlin" => Ok(Language::Kotlin),
-            "python" => Ok(Language::Python),
-            "swift" => Ok(Language::Swift),
-            _ => Err(Error::UnsupportedLanguage),
-        }
-    }
-}
-
-fn generate_bindings(opt: &Opt) -> anyhow::Result<(), anyhow::Error> {
-    let path: &Utf8Path = Utf8Path::from_path(&opt.udl_file).unwrap();
-    let out_dir: &Utf8Path = Utf8Path::from_path(&opt.out_dir).unwrap();
-    uniffi_bindgen::generate_bindings(
-        path,
-        None,
-        vec![opt.language.to_string().as_str()],
-        Some(out_dir),
-        None,
-        false,
-    )?;
-
-    Ok(())
-}
-
-fn fixup_python_lib_path(
-    out_dir: &Path,
-    lib_name: &Path,
-) -> Result<(), Box<dyn std::error::Error>> {
-    use std::fs;
-    use std::io::Write;
-
-    const LOAD_INDIRECT_DEF: &str = "def loadIndirect():";
-
-    let bindings_file = out_dir.join("bdk.py");
-    let mut data = fs::read_to_string(&bindings_file)?;
-
-    let pos = data
-        .find(LOAD_INDIRECT_DEF)
-        .unwrap_or_else(|| panic!("loadIndirect not found in `{}`", bindings_file.display()));
-    let range = pos..pos + LOAD_INDIRECT_DEF.len();
-
-    let replacement = format!(
-        r#"
-def loadIndirect():
-    import glob
-    return getattr(ctypes.cdll, glob.glob(os.path.join(os.path.dirname(os.path.abspath(__file__)), '{}.*'))[0])
-
-def _loadIndirectOld():"#,
-        &lib_name.to_str().expect("lib name")
-    );
-    data.replace_range(range, &replacement);
-
-    let mut file = fs::OpenOptions::new()
-        .write(true)
-        .truncate(true)
-        .open(&bindings_file)?;
-    file.write_all(data.as_bytes())?;
-
-    Ok(())
-}
-
-#[derive(Debug, StructOpt)]
-#[structopt(
-    name = "bdk-ffi-bindgen",
-    about = "A tool to generate bdk-ffi language bindings"
-)]
-struct Opt {
-    /// UDL file
-    #[structopt(env = "BDKFFI_BINDGEN_UDL", short, long, default_value("src/bdk.udl"), parse(try_from_str = PathBuf::from_str))]
-    udl_file: PathBuf,
-
-    /// Language to generate bindings for
-    #[structopt(env = "BDKFFI_BINDGEN_LANGUAGE", short, long, possible_values(&["kotlin","swift","python"]), parse(try_from_str = Language::from_str))]
-    language: Language,
-
-    /// Output directory to put generated language bindings
-    #[structopt(env = "BDKFFI_BINDGEN_OUTPUT_DIR", short, long, parse(try_from_str = PathBuf::from_str))]
-    out_dir: PathBuf,
-
-    /// Python fix up lib path
-    #[structopt(env = "BDKFFI_BINDGEN_PYTHON_FIXUP_PATH", short, long, parse(try_from_str = PathBuf::from_str))]
-    python_fixup_path: Option<PathBuf>,
-}
-
-fn main() -> Result<(), Box<dyn std::error::Error>> {
-    let opt = Opt::from_args();
-
-    println!("Input UDL file is {:?}", opt.udl_file);
-    println!("Chosen language is {}", opt.language);
-    println!("Output directory is {:?}", opt.out_dir);
-
-    generate_bindings(&opt)?;
-
-    if opt.language == Language::Python {
-        if let Some(path) = opt.python_fixup_path {
-            println!("Fixing up python lib path, {:?}", &path);
-            fixup_python_lib_path(&opt.out_dir, &path)?;
-        }
-    }
-    Ok(())
-}
diff --git a/bdk-ffi/Cargo.toml b/bdk-ffi/Cargo.toml
index 78486688..45979f78 100644
--- a/bdk-ffi/Cargo.toml
+++ b/bdk-ffi/Cargo.toml
@@ -15,6 +15,9 @@ name = "bdkffi"
 name = "uniffi-bindgen"
 path = "uniffi-bindgen.rs"
 
+[features]
+default = ["uniffi/cli"]
+
 [dependencies]
 bdk = { version = "0.27.1", features = ["all-keys", "use-esplora-ureq", "sqlite-bundled", "rpc"] }
 uniffi = { version = "0.23.0" }
diff --git a/bdk-ffi/src/bdk.udl b/bdk-ffi/src/bdk.udl
index 9be878dc..da760972 100644
--- a/bdk-ffi/src/bdk.udl
+++ b/bdk-ffi/src/bdk.udl
@@ -94,6 +94,7 @@ interface DatabaseConfig {
 };
 
 dictionary TransactionDetails {
+  Transaction? transaction;
   u64? fee;
   u64 received;
   u64 sent;
@@ -186,9 +187,16 @@ dictionary OutPoint {
   u32 vout;
 };
 
+dictionary TxIn {
+  OutPoint previous_output;
+  Script script_sig;
+  u32 sequence;
+  sequence<sequence<u8>> witness;
+};
+
 dictionary TxOut {
   u64 value;
-  string address;
+  Script script_pubkey;
 };
 
 enum KeychainKind {
@@ -225,7 +233,7 @@ interface Wallet {
   boolean sign([ByRef] PartiallySignedTransaction psbt);
 
   [Throws=BdkError]
-  sequence<TransactionDetails> list_transactions();
+  sequence<TransactionDetails> list_transactions(boolean include_raw);
 
   Network network();
 
@@ -244,10 +252,32 @@ interface FeeRate {
 };
 
 interface Transaction {
-   [Throws=BdkError]
-   constructor(sequence<u8> transaction_bytes);
+  [Throws=BdkError]
+  constructor(sequence<u8> transaction_bytes);
+
+  string txid();
+
+  u64 weight();
+
+  u64 size();
+
+  u64 vsize();
+
+  sequence<u8> serialize();
+
+  boolean is_coin_base();
+
+  boolean is_explicitly_rbf();
+
+  boolean is_lock_time_enabled();
+
+  i32 version();
+
+  u32 lock_time();
+
+  sequence<TxIn> input();
 
-   sequence<u8> serialize();
+  sequence<TxOut> output();
 };
 
 interface PartiallySignedTransaction {
diff --git a/bdk-ffi/src/lib.rs b/bdk-ffi/src/lib.rs
index f82b6cb7..15838545 100644
--- a/bdk-ffi/src/lib.rs
+++ b/bdk-ffi/src/lib.rs
@@ -15,6 +15,8 @@ use crate::keys::{DescriptorPublicKey, DescriptorSecretKey, Mnemonic};
 use crate::psbt::PartiallySignedTransaction;
 use crate::wallet::{BumpFeeTxBuilder, TxBuilder, Wallet};
 use bdk::bitcoin::blockdata::script::Script as BdkScript;
+use bdk::bitcoin::blockdata::transaction::TxIn as BdkTxIn;
+use bdk::bitcoin::blockdata::transaction::TxOut as BdkTxOut;
 use bdk::bitcoin::consensus::Decodable;
 use bdk::bitcoin::psbt::serialize::Serialize;
 use bdk::bitcoin::{
@@ -25,6 +27,7 @@ use bdk::database::any::{SledDbConfiguration, SqliteDbConfiguration};
 use bdk::keys::bip39::WordCount;
 use bdk::wallet::AddressIndex as BdkAddressIndex;
 use bdk::wallet::AddressInfo as BdkAddressInfo;
+use bdk::LocalUtxo as BdkLocalUtxo;
 use bdk::{Balance as BdkBalance, BlockTime, Error as BdkError, FeeRate, KeychainKind};
 use std::convert::From;
 use std::fmt;
@@ -49,7 +52,7 @@ pub struct AddressInfo {
 }
 
 impl From<BdkAddressInfo> for AddressInfo {
-    fn from(x: bdk::wallet::AddressInfo) -> AddressInfo {
+    fn from(x: bdk::wallet::AddressInfo) -> Self {
         AddressInfo {
             index: x.index,
             address: x.address.to_string(),
@@ -79,13 +82,13 @@ pub enum AddressIndex {
     /// Use with caution, if an index is given that is less than the current descriptor index
     /// then the returned address and subsequent addresses returned by calls to `AddressIndex::New`
     /// and `AddressIndex::LastUsed` may have already been used. Also if the index is reset to a
-    /// value earlier than the [`crate::blockchain::Blockchain`] stop_gap (default is 20) then a
+    /// value earlier than the [`Blockchain`] stop_gap (default is 20) then a
     /// larger stop_gap should be used to monitor for all possibly used addresses.
     Reset { index: u32 },
 }
 
 impl From<AddressIndex> for BdkAddressIndex {
-    fn from(x: AddressIndex) -> BdkAddressIndex {
+    fn from(x: AddressIndex) -> Self {
         match x {
             AddressIndex::New => BdkAddressIndex::New,
             AddressIndex::LastUnused => BdkAddressIndex::LastUnused,
@@ -98,6 +101,7 @@ impl From<AddressIndex> for BdkAddressIndex {
 /// A wallet transaction
 #[derive(Debug, Clone, PartialEq, Eq, Default)]
 pub struct TransactionDetails {
+    pub transaction: Option<Arc<Transaction>>,
     /// Transaction id.
     pub txid: String,
     /// Received value (sats)
@@ -116,14 +120,18 @@ pub struct TransactionDetails {
     pub confirmation_time: Option<BlockTime>,
 }
 
-impl From<&bdk::TransactionDetails> for TransactionDetails {
-    fn from(x: &bdk::TransactionDetails) -> TransactionDetails {
+impl From<bdk::TransactionDetails> for TransactionDetails {
+    fn from(tx_details: bdk::TransactionDetails) -> Self {
+        let optional_tx: Option<Arc<Transaction>> =
+            tx_details.transaction.map(|tx| Arc::new(tx.into()));
+
         TransactionDetails {
-            fee: x.fee,
-            txid: x.txid.to_string(),
-            received: x.received,
-            sent: x.sent,
-            confirmation_time: x.confirmation_time.clone(),
+            transaction: optional_tx,
+            fee: tx_details.fee,
+            txid: tx_details.txid.to_string(),
+            received: tx_details.received,
+            sent: tx_details.sent,
+            confirmation_time: tx_details.confirmation_time,
         }
     }
 }
@@ -138,7 +146,7 @@ pub struct OutPoint {
 }
 
 impl From<&OutPoint> for BdkOutPoint {
-    fn from(x: &OutPoint) -> BdkOutPoint {
+    fn from(x: &OutPoint) -> Self {
         BdkOutPoint {
             txid: Txid::from_str(&x.txid).unwrap(),
             vout: x.vout,
@@ -175,11 +183,23 @@ impl From<BdkBalance> for Balance {
 }
 
 /// A transaction output, which defines new coins to be created from old ones.
+#[derive(Debug, Clone)]
 pub struct TxOut {
     /// The value of the output, in satoshis.
     value: u64,
     /// The address of the output.
-    address: String,
+    script_pubkey: Arc<Script>,
+}
+
+impl From<&BdkTxOut> for TxOut {
+    fn from(x: &BdkTxOut) -> Self {
+        TxOut {
+            value: x.value,
+            script_pubkey: Arc::new(Script {
+                script: x.script_pubkey.clone(),
+            }),
+        }
+    }
 }
 
 pub struct LocalUtxo {
@@ -189,27 +209,21 @@ pub struct LocalUtxo {
     is_spent: bool,
 }
 
-// This trait is used to convert the bdk TxOut type with field `script_pubkey: Script`
-// into the bdk-ffi TxOut type which has a field `address: String` instead
-trait NetworkLocalUtxo {
-    fn from_utxo(x: &bdk::LocalUtxo, network: Network) -> LocalUtxo;
-}
-
-impl NetworkLocalUtxo for LocalUtxo {
-    fn from_utxo(x: &bdk::LocalUtxo, network: Network) -> LocalUtxo {
+impl From<BdkLocalUtxo> for LocalUtxo {
+    fn from(local_utxo: BdkLocalUtxo) -> Self {
         LocalUtxo {
             outpoint: OutPoint {
-                txid: x.outpoint.txid.to_string(),
-                vout: x.outpoint.vout,
+                txid: local_utxo.outpoint.txid.to_string(),
+                vout: local_utxo.outpoint.vout,
             },
             txout: TxOut {
-                value: x.txout.value,
-                address: BdkAddress::from_script(&x.txout.script_pubkey, network)
-                    .unwrap()
-                    .to_string(),
+                value: local_utxo.txout.value,
+                script_pubkey: Arc::new(Script {
+                    script: local_utxo.txout.script_pubkey,
+                }),
             },
-            keychain: x.keychain,
-            is_spent: x.is_spent,
+            keychain: local_utxo.keychain,
+            is_spent: local_utxo.is_spent,
         }
     }
 }
@@ -238,8 +252,32 @@ impl fmt::Debug for ProgressHolder {
     }
 }
 
+#[derive(Debug, Clone)]
+pub struct TxIn {
+    pub previous_output: OutPoint,
+    pub script_sig: Arc<Script>,
+    pub sequence: u32,
+    pub witness: Vec<Vec<u8>>,
+}
+
+impl From<&BdkTxIn> for TxIn {
+    fn from(x: &BdkTxIn) -> Self {
+        TxIn {
+            previous_output: OutPoint {
+                txid: x.previous_output.txid.to_string(),
+                vout: x.previous_output.vout,
+            },
+            script_sig: Arc::new(Script {
+                script: x.script_sig.clone(),
+            }),
+            sequence: x.sequence.0,
+            witness: x.witness.to_vec(),
+        }
+    }
+}
+
 /// A Bitcoin transaction.
-#[derive(Debug)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Transaction {
     internal: BdkTransaction,
 }
@@ -251,9 +289,59 @@ impl Transaction {
         Ok(Transaction { internal: tx })
     }
 
+    fn txid(&self) -> String {
+        self.internal.txid().to_string()
+    }
+
+    fn weight(&self) -> u64 {
+        self.internal.weight() as u64
+    }
+
+    fn size(&self) -> u64 {
+        self.internal.size() as u64
+    }
+
+    fn vsize(&self) -> u64 {
+        self.internal.vsize() as u64
+    }
+
     fn serialize(&self) -> Vec<u8> {
         self.internal.serialize()
     }
+
+    fn is_coin_base(&self) -> bool {
+        self.internal.is_coin_base()
+    }
+
+    fn is_explicitly_rbf(&self) -> bool {
+        self.internal.is_explicitly_rbf()
+    }
+
+    fn is_lock_time_enabled(&self) -> bool {
+        self.internal.is_lock_time_enabled()
+    }
+
+    fn version(&self) -> i32 {
+        self.internal.version
+    }
+
+    fn lock_time(&self) -> u32 {
+        self.internal.lock_time.0
+    }
+
+    fn input(&self) -> Vec<TxIn> {
+        self.internal.input.iter().map(|x| x.into()).collect()
+    }
+
+    fn output(&self) -> Vec<TxOut> {
+        self.internal.output.iter().map(|x| x.into()).collect()
+    }
+}
+
+impl From<bdk::bitcoin::Transaction> for Transaction {
+    fn from(tx: bdk::bitcoin::Transaction) -> Self {
+        Transaction { internal: tx }
+    }
 }
 
 /// A Bitcoin address.
@@ -288,6 +376,12 @@ impl Script {
     }
 }
 
+impl From<BdkScript> for Script {
+    fn from(bdk_script: BdkScript) -> Self {
+        Script { script: bdk_script }
+    }
+}
+
 #[derive(Clone, Debug)]
 enum RbfValue {
     Default,
diff --git a/bdk-ffi/src/psbt.rs b/bdk-ffi/src/psbt.rs
index 80f36af8..8741e6e0 100644
--- a/bdk-ffi/src/psbt.rs
+++ b/bdk-ffi/src/psbt.rs
@@ -34,7 +34,7 @@ impl PartiallySignedTransaction {
     /// Return the transaction.
     pub(crate) fn extract_tx(&self) -> Arc<Transaction> {
         let tx = self.internal.lock().unwrap().clone().extract_tx();
-        Arc::new(Transaction { internal: tx })
+        Arc::new(tx.into())
     }
 
     /// Combines this PartiallySignedTransaction with other PSBT as described by BIP 174.
diff --git a/bdk-ffi/src/wallet.rs b/bdk-ffi/src/wallet.rs
index 2dfc1c28..1042f060 100644
--- a/bdk-ffi/src/wallet.rs
+++ b/bdk-ffi/src/wallet.rs
@@ -3,7 +3,10 @@ use bdk::bitcoin::{Address as BdkAddress, Network, OutPoint as BdkOutPoint, Sequ
 use bdk::database::any::AnyDatabase;
 use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase};
 use bdk::wallet::tx_builder::ChangeSpendPolicy;
-use bdk::{FeeRate, SignOptions, SyncOptions as BdkSyncOptions, Wallet as BdkWallet};
+use bdk::{
+    FeeRate, LocalUtxo as BdkLocalUtxo, SignOptions, SyncOptions as BdkSyncOptions,
+    Wallet as BdkWallet,
+};
 use std::collections::HashSet;
 use std::ops::Deref;
 use std::str::FromStr;
@@ -14,8 +17,8 @@ use crate::database::DatabaseConfig;
 use crate::descriptor::Descriptor;
 use crate::psbt::PartiallySignedTransaction;
 use crate::{
-    AddressIndex, AddressInfo, Balance, BdkError, LocalUtxo, NetworkLocalUtxo, OutPoint, Progress,
-    ProgressHolder, RbfValue, Script, ScriptAmount, TransactionDetails, TxBuilderResult,
+    AddressIndex, AddressInfo, Balance, BdkError, LocalUtxo, OutPoint, Progress, ProgressHolder,
+    RbfValue, Script, ScriptAmount, TransactionDetails, TxBuilderResult,
 };
 
 #[derive(Debug)]
@@ -117,10 +120,13 @@ impl Wallet {
     }
 
     /// Return the list of transactions made and received by the wallet. Note that this method only operate on the internal database, which first needs to be [Wallet.sync] manually.
-    pub(crate) fn list_transactions(&self) -> Result<Vec<TransactionDetails>, BdkError> {
-        let transaction_details = self.get_wallet().list_transactions(true)?;
+    pub(crate) fn list_transactions(
+        &self,
+        include_raw: bool,
+    ) -> Result<Vec<TransactionDetails>, BdkError> {
+        let transaction_details = self.get_wallet().list_transactions(include_raw)?;
         Ok(transaction_details
-            .iter()
+            .into_iter()
             .map(TransactionDetails::from)
             .collect())
     }
@@ -128,11 +134,8 @@ impl Wallet {
     /// Return the list of unspent outputs of this wallet. Note that this method only operates on the internal database,
     /// which first needs to be Wallet.sync manually.
     pub(crate) fn list_unspent(&self) -> Result<Vec<LocalUtxo>, BdkError> {
-        let unspents = self.get_wallet().list_unspent()?;
-        Ok(unspents
-            .iter()
-            .map(|u| LocalUtxo::from_utxo(u, self.network()))
-            .collect())
+        let unspents: Vec<BdkLocalUtxo> = self.get_wallet().list_unspent()?;
+        Ok(unspents.into_iter().map(LocalUtxo::from).collect())
     }
 }
 
@@ -373,7 +376,7 @@ impl TxBuilder {
                 psbt: Arc::new(PartiallySignedTransaction {
                     internal: Mutex::new(psbt),
                 }),
-                transaction_details: TransactionDetails::from(&tx_details),
+                transaction_details: TransactionDetails::from(tx_details),
             })
     }
 }
@@ -577,28 +580,19 @@ mod test {
 
         // new index still 0
         assert_eq!(
-            wallet
-                .get_address(crate::AddressIndex::New)
-                .unwrap()
-                .address,
+            wallet.get_address(AddressIndex::New).unwrap().address,
             "bcrt1qqjn9gky9mkrm3c28e5e87t5akd3twg6xezp0tv"
         );
 
         // new index now 1
         assert_eq!(
-            wallet
-                .get_address(crate::AddressIndex::New)
-                .unwrap()
-                .address,
+            wallet.get_address(AddressIndex::New).unwrap().address,
             "bcrt1q0xs7dau8af22rspp4klya4f7lhggcnqfun2y3a"
         );
 
         // new index now 2
         assert_eq!(
-            wallet
-                .get_address(crate::AddressIndex::New)
-                .unwrap()
-                .address,
+            wallet.get_address(AddressIndex::New).unwrap().address,
             "bcrt1q5g0mq6dkmwzvxscqwgc932jhgcxuqqkjv09tkj"
         );
 
@@ -646,24 +640,18 @@ mod test {
         .unwrap();
 
         assert_eq!(
-            wallet
-                .get_address(crate::AddressIndex::New)
-                .unwrap()
-                .address,
+            wallet.get_address(AddressIndex::New).unwrap().address,
             "bcrt1qqjn9gky9mkrm3c28e5e87t5akd3twg6xezp0tv"
         );
 
         assert_eq!(
-            wallet
-                .get_address(crate::AddressIndex::New)
-                .unwrap()
-                .address,
+            wallet.get_address(AddressIndex::New).unwrap().address,
             "bcrt1q0xs7dau8af22rspp4klya4f7lhggcnqfun2y3a"
         );
 
         assert_eq!(
             wallet
-                .get_address(crate::AddressIndex::LastUnused)
+                .get_address(AddressIndex::LastUnused)
                 .unwrap()
                 .address,
             "bcrt1q0xs7dau8af22rspp4klya4f7lhggcnqfun2y3a"
@@ -671,7 +659,7 @@ mod test {
 
         assert_eq!(
             wallet
-                .get_internal_address(crate::AddressIndex::New)
+                .get_internal_address(AddressIndex::New)
                 .unwrap()
                 .address,
             "bcrt1qpmz73cyx00r4a5dea469j40ax6d6kqyd67nnpj"
@@ -679,7 +667,7 @@ mod test {
 
         assert_eq!(
             wallet
-                .get_internal_address(crate::AddressIndex::New)
+                .get_internal_address(AddressIndex::New)
                 .unwrap()
                 .address,
             "bcrt1qaux734vuhykww9632v8cmdnk7z2mw5lsf74v6k"
@@ -687,7 +675,7 @@ mod test {
 
         assert_eq!(
             wallet
-                .get_internal_address(crate::AddressIndex::LastUnused)
+                .get_internal_address(AddressIndex::LastUnused)
                 .unwrap()
                 .address,
             "bcrt1qaux734vuhykww9632v8cmdnk7z2mw5lsf74v6k"
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 75217bac..71573ae1 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 --features uniffi/cli --release --target aarch64-apple-darwin
+        // cargo build --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", "--features", "uniffi/cli", "--profile", "release-smaller", "--target", "x86_64-apple-darwin")
+                    val cargoArgs: List<String> = listOf("build", "--profile", "release-smaller", "--target", "x86_64-apple-darwin")
                     args(cargoArgs)
                 }
                 exec {
                     workingDir("${project.projectDir}/../../bdk-ffi")
                     executable("cargo")
-                    val cargoArgs: List<String> = listOf("build", "--features", "uniffi/cli", "--profile", "release-smaller", "--target", "aarch64-apple-darwin")
+                    val cargoArgs: List<String> = listOf("build", "--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", "--features", "uniffi/cli", "--profile", "release-smaller", "--target", "x86_64-unknown-linux-gnu")
+                    val cargoArgs: List<String> = listOf("build", "--profile", "release-smaller", "--target", "x86_64-unknown-linux-gnu")
                     args(cargoArgs)
                 }
             }
@@ -90,7 +90,7 @@ 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")
+            val cargoArgs: List<String> = listOf("run", "--bin", "uniffi-bindgen", "generate", "src/bdk.udl", "--language", "kotlin", "--out-dir", "../bdk-jvm/lib/src/main/kotlin", "--no-format")
 
             executable("cargo")
             args(cargoArgs)
diff --git a/bdk-python/generate.sh b/bdk-python/generate.sh
index 90a5f659..19fb7ac8 100644
--- a/bdk-python/generate.sh
+++ b/bdk-python/generate.sh
@@ -5,10 +5,10 @@ OS=$(uname -s)
 
 echo "Generating bdk.py..."
 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
+cargo run --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
+cargo build --profile release-smaller
 case $OS in
   "Darwin")
     echo "Copying macOS libbdkffi.dylib..."
diff --git a/bdk-swift/build-local-swift.sh b/bdk-swift/build-local-swift.sh
index dac45672..ec5b09be 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 --features uniffi/cli --bin uniffi-bindgen generate src/bdk.udl --language swift --out-dir ../bdk-swift/Sources/BitcoinDevKit --no-format
+cargo run --bin uniffi-bindgen generate src/bdk.udl --language swift --out-dir ../bdk-swift/Sources/BitcoinDevKit --no-format
 popd
 
-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
+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
 
 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/test-android.yaml b/.github/workflows/test-android.yaml
index 9a961408..7591fd14 100644
--- a/.github/workflows/test-android.yaml
+++ b/.github/workflows/test-android.yaml
@@ -9,22 +9,10 @@ on:
       - "bdk-ffi/**"
       - "bdk-android/**"
 
-env:
-  ANDROID_NDK_ROOT: /usr/local/lib/android/sdk/ndk/21.4.7075529
-  # By default, the new ubuntu-20.04 images use the following ANDROID_NDK_ROOT
-  # ANDROID_NDK_ROOT: /usr/local/lib/android/sdk/ndk/25.0.8775105
-
 jobs:
   build:
     runs-on: ubuntu-20.04
     steps:
-      - name: "Install Android NDK 21.4.7075529"
-        run: |
-          ANDROID_ROOT=/usr/local/lib/android
-          ANDROID_SDK_ROOT=${ANDROID_ROOT}/sdk
-          SDKMANAGER=${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager
-          echo "y" | $SDKMANAGER "ndk;21.4.7075529"
-
       - name: "Check out PR branch"
         uses: actions/checkout@v2
 
diff --git a/.github/workflows/test-swift.yaml b/.github/workflows/test-swift.yaml
index 18cfed53..38c1d971 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 --features uniffi/cli --bin uniffi-bindgen generate src/bdk.udl --language swift --out-dir ../bdk-swift/Sources/BitcoinDevKit --no-format
+        run: cargo run --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 --package bdk-ffi --features uniffi/cli --profile release-smaller --target x86_64-apple-darwin
+        run: cargo build --package bdk-ffi --profile release-smaller --target x86_64-apple-darwin
 
       - name: Build bdk-ffi for aarch64-apple-darwin
-        run: cargo build --package bdk-ffi --features uniffi/cli --profile release-smaller --target aarch64-apple-darwin
+        run: cargo build --package bdk-ffi --profile release-smaller --target aarch64-apple-darwin
 
       - name: Create lipo-ios-sim and lipo-macos
         run: |