diff --git a/.gitignore b/.gitignore index 9a259ac..3263384 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ target/ +__pycache__/ +*.pyc bindings/android/native-debug-symbols.zip # The xcframework's static libraries exceed GitHub's 100 MB file limit. They are # already shipped, compressed, inside BitkitCore.xcframework.zip, which is what diff --git a/CHANGELOG.md b/CHANGELOG.md index 9691fbc..3c87184 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- The Android AAR now ships targeted R8 consumer keep rules for the UniFFI/JNA FFI surface, so consuming apps can enable R8 full mode without extra keep rules for this library. - Add a generic hardware-wallet catalog with Foundation Passport support, multipart UR QR encoding and decoding, Passport single-signature account export parsing, and signed PSBT finalization across the UniFFI bindings. - Swap status updates now reconcile against Boltz's REST status whenever a swap is (re)subscribed, both on `boltz_start_swap_updates` and when `boltz_create_reverse_swap` adds a swap to a running stream. A confirmed reverse-swap lockup is therefore caught up and auto-claimed even when its live WebSocket event was missed (for example because the updates stream was down while the lockup confirmed), instead of the swap silently stalling until a manual claim. No FFI signature change. - `onchain_broadcast_raw_tx` now returns the transaction's canonical txid, computed locally in Rust, and treats Electrum "already known / already in mempool / already in block chain" responses as success (returning that same txid). This lets native apps complete Blocktank funding bookkeeping when they retry a broadcast after an ambiguous network failure, without relying on a signer-provided txid. Genuine connectivity failures and unrelated broadcast rejections remain typed `BroadcastError`s, and there is no FFI signature change. diff --git a/Cargo.lock b/Cargo.lock index 5ce3eb2..90b8f93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -589,7 +589,7 @@ dependencies = [ [[package]] name = "bitkitcore" -version = "0.5.8" +version = "0.5.9" dependencies = [ "android_logger", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 533988d..5e665f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bitkitcore" -version = "0.5.8" +version = "0.5.9" edition = "2021" [lib] diff --git a/Package.swift b/Package.swift index 051d3ba..c1bf2fa 100644 --- a/Package.swift +++ b/Package.swift @@ -3,8 +3,8 @@ import PackageDescription -let tag = "v0.5.8" -let checksum = "a29cedc9c42c8af43d1f158595d71a672102568d08da631ab6b12779ecee28e3" +let tag = "v0.5.9" +let checksum = "31a298c85a783224d4b4050746c283b57e321585c979368f20bb3d5757f8ea04" let url = "https://github.com/synonymdev/bitkit-core/releases/download/\(tag)/BitkitCore.xcframework.zip" let package = Package( diff --git a/bindings/android/gradle.properties b/bindings/android/gradle.properties index 1211383..d923351 100644 --- a/bindings/android/gradle.properties +++ b/bindings/android/gradle.properties @@ -3,4 +3,4 @@ android.useAndroidX=true android.enableJetifier=true kotlin.code.style=official group=com.synonym -version=0.5.8 +version=0.5.9 diff --git a/bindings/android/lib/build.gradle.kts b/bindings/android/lib/build.gradle.kts index d8c7d4c..2e33fc7 100644 --- a/bindings/android/lib/build.gradle.kts +++ b/bindings/android/lib/build.gradle.kts @@ -1,5 +1,6 @@ import java.io.ByteArrayOutputStream import java.io.File +import java.util.zip.ZipFile plugins { id("com.android.library") @@ -158,8 +159,51 @@ val validateReleaseNativeLibraries by tasks.registering { } } +val validateConsumerKeepRules by tasks.registering { + group = "verification" + description = "Validates Android consumer keep rules exist for R8." + + val consumerRules = layout.projectDirectory.file("consumer-rules.pro") + inputs.file(consumerRules) + + doLast { + val file = consumerRules.asFile + if (!file.isFile || file.readText().isBlank()) { + throw GradleException("Android consumer keep rules missing at '${file.path}'") + } + } +} + tasks.matching { it.name == "bundleReleaseAar" || it.name.startsWith("publish") }.configureEach { - dependsOn(validateReleaseNativeLibraries) + dependsOn(validateReleaseNativeLibraries, validateConsumerKeepRules) +} + +tasks.matching { it.name == "bundleReleaseAar" }.configureEach { + doLast { + val aars = layout.buildDirectory.dir("outputs/aar").get().asFile + .listFiles() + ?.filter { it.isFile && it.name.endsWith(".aar") && it.name.contains("release") } + .orEmpty() + + if (aars.isEmpty()) { + throw GradleException("Release AAR missing after bundleReleaseAar") + } + + aars.forEach { aar -> + ZipFile(aar).use { zip -> + val entry = zip.getEntry("proguard.txt") + ?: throw GradleException( + "Release AAR is missing consumer keep rules (proguard.txt): '${aar.path}'" + ) + val text = zip.getInputStream(entry).bufferedReader().readText() + if (text.isBlank()) { + throw GradleException( + "Release AAR consumer keep rules are empty: '${aar.path}'" + ) + } + } + } + } } afterEvaluate { diff --git a/bindings/android/lib/consumer-rules.pro b/bindings/android/lib/consumer-rules.pro new file mode 100644 index 0000000..fe5adc7 --- /dev/null +++ b/bindings/android/lib/consumer-rules.pro @@ -0,0 +1,31 @@ +# Consumer keep rules for bitkit-core Android bindings. +# Packaged into the AAR and applied automatically when a consuming app enables R8. + +# JNA reads @Structure.FieldOrder and public fields by name, and constructs +# Structure, Structure$ByValue, and Structure$ByReference types reflectively. +-keepclassmembers class com.synonym.bitkitcore.** extends com.sun.jna.Structure { + ; + (...); +} + +# JNA looks up Callback methods by name when building native function pointers. +-keepclassmembers class com.synonym.bitkitcore.** implements com.sun.jna.Callback { + ; +} + +# Native.register maps remaining native methods by exact C symbol name. +-keepclasseswithmembers,allowshrinking,includedescriptorclasses class com.synonym.bitkitcore.UniffiLib { + native ; +} +-keepclasseswithmembers,allowshrinking,includedescriptorclasses class com.synonym.bitkitcore.IntegrityCheckingUniffiLib { + native ; +} + +# @Structure.FieldOrder is read at runtime. +-keepattributes RuntimeVisibleAnnotations + +# JNA's AAR references desktop AWT types that are absent on Android. +-dontwarn java.awt.Component +-dontwarn java.awt.GraphicsEnvironment +-dontwarn java.awt.HeadlessException +-dontwarn java.awt.Window diff --git a/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so index 61d279c..0fd3fcf 100755 Binary files a/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so differ diff --git a/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so index d6af281..9291d38 100755 Binary files a/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so differ diff --git a/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so index e2f4b7c..cfcfb48 100755 Binary files a/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so differ diff --git a/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so index 929c7ee..e60893a 100755 Binary files a/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so differ diff --git a/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.android.kt b/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.android.kt index bc83f30..b2df344 100644 --- a/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.android.kt +++ b/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.android.kt @@ -18069,4 +18069,4 @@ internal object uniffiRustFutureContinuationCallbackCallback: UniffiRustFutureCo override fun callback(data: Long, pollResult: Byte) { uniffiContinuationHandleMap.remove(data).resume(pollResult) } -} +} \ No newline at end of file diff --git a/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.common.kt b/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.common.kt index 4e4e1b0..ac23f33 100644 --- a/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.common.kt +++ b/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.common.kt @@ -5247,6 +5247,8 @@ public enum class WordCount { + + diff --git a/bindings/ios/BitkitCore.xcframework.zip b/bindings/ios/BitkitCore.xcframework.zip index 7d8e67e..e04bbad 100644 Binary files a/bindings/ios/BitkitCore.xcframework.zip and b/bindings/ios/BitkitCore.xcframework.zip differ diff --git a/bindings/ios/bitkitcore.swift b/bindings/ios/bitkitcore.swift index c06f7f9..f6cae7c 100644 --- a/bindings/ios/bitkitcore.swift +++ b/bindings/ios/bitkitcore.swift @@ -25923,4 +25923,4 @@ public func uniffiEnsureBitkitcoreInitialized() { } } -// swiftlint:enable all +// swiftlint:enable all \ No newline at end of file diff --git a/bindings/python/bitkitcore/bitkitcore.py b/bindings/python/bitkitcore/bitkitcore.py index 396cdef..debae06 100644 --- a/bindings/python/bitkitcore/bitkitcore.py +++ b/bindings/python/bitkitcore/bitkitcore.py @@ -25018,3 +25018,4 @@ def wipe_all_transaction_details() -> None: "TrezorUiCallback", "UrDecoder", ] + diff --git a/bindings/python/bitkitcore/libbitkitcore.dylib b/bindings/python/bitkitcore/libbitkitcore.dylib index 7d7482c..eeb5251 100755 Binary files a/bindings/python/bitkitcore/libbitkitcore.dylib and b/bindings/python/bitkitcore/libbitkitcore.dylib differ diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 10a0ab2..ef2600e 100644 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -2,7 +2,7 @@ setup( name="bitkitcore", - version="0.5.8", + version="0.5.9", packages=find_packages(), package_data={ "bitkitcore": ["*.so", "*.dylib", "*.dll"],