From c89c12654db70e44607cdc0fec29e09f9b3f4ee2 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 30 Oct 2026 10:39:00 -0400 Subject: [PATCH] fix(currency-math): pack the curve tables into the app again Moving :libs:currency-math onto the KMP android target in #1894 put the curve tables in src/androidMain/assets, but that target skips assets unless androidResources is enabled. Build 4969 shipped without discrete_pricing_table.bin and discrete_cumulative_table.bin, so the curve never initialized and every launch crashed on the first token balance with "DiscreteBondingCurve not initialized" (Bugsnag 6aadeebd). Enable androidResources for the module, and add a per-variant checkCurveAssets task that fails when either table is missing from the app's merged assets. flipcashTestDebug runs the debug check, and assembleRelease and bundleRelease depend on the release one, since the build itself succeeds without the tables. --- apps/flipcash/app/build.gradle.kts | 34 +++++++++++++++++++++++++++++ build.gradle.kts | 2 ++ libs/currency-math/build.gradle.kts | 3 +++ 3 files changed, 39 insertions(+) diff --git a/apps/flipcash/app/build.gradle.kts b/apps/flipcash/app/build.gradle.kts index d7ef61b2d2..fea7f6daa1 100644 --- a/apps/flipcash/app/build.gradle.kts +++ b/apps/flipcash/app/build.gradle.kts @@ -1,3 +1,4 @@ +import com.android.build.api.artifact.SingleArtifact import com.android.build.api.variant.BuildConfigField import com.bugsnag.gradle.dsl.debug import com.bugsnag.gradle.dsl.release @@ -194,6 +195,28 @@ kotlin { } } +// Fails when an asset the app can't start without is missing from the merged assets. A library on +// the KMP android target drops its assets unless it sets `androidResources { enable = true }`, and +// that build still succeeds: :libs:currency-math lost its curve tables that way in #1894, and every +// launch crashed (Bugsnag 6aadeebd). +abstract class CheckPackagedAssets : DefaultTask() { + @get:InputFiles + @get:PathSensitive(PathSensitivity.RELATIVE) + abstract val assetsDir: DirectoryProperty + + @get:Input + abstract val required: ListProperty + + @TaskAction + fun check() { + val dir = assetsDir.get().asFile + val missing = required.get().filterNot { dir.resolve(it).isFile } + if (missing.isNotEmpty()) { + throw GradleException("Merged assets in $dir are missing: ${missing.joinToString()}") + } + } +} + // Expose Compose testTags as resource-ids (for UiAutomator/Maestro/baseline-profile // generation) on every variant EXCEPT the shipping `release` — keeps internal ids like // `seed_input_field` out of the production wallet build. Read in App.kt as @@ -208,6 +231,17 @@ androidComponents { "testTags exposed as resource-ids; false only for shipping release", ), ) + + val checkCurveAssets = tasks.register( + "check${variant.name.replaceFirstChar { it.uppercase() }}CurveAssets", + ) { + assetsDir.set(variant.artifacts.get(SingleArtifact.ASSETS)) + required.set(listOf("discrete_pricing_table.bin", "discrete_cumulative_table.bin")) + } + if (variant.name == "release") { + tasks.matching { it.name == "bundleRelease" || it.name == "assembleRelease" } + .configureEach { dependsOn(checkCurveAssets) } + } } } diff --git a/build.gradle.kts b/build.gradle.kts index 1033c682a0..83acacc192 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -93,4 +93,6 @@ tasks.register("flipcashTestDebug") { dependsOn(gradle.includedBuild("build-logic").task(":convention:test")) // EVENTS.md is generated from events.toml but checked in; fail when someone edits one alone. dependsOn(":libs:analytics-events:checkAnalyticsEventsPage") + // The app's merged assets still carry the files it needs to start, such as the curve tables. + dependsOn(":apps:flipcash:app:checkDebugCurveAssets") } diff --git a/libs/currency-math/build.gradle.kts b/libs/currency-math/build.gradle.kts index 89c2dc44ea..a50969b4ee 100644 --- a/libs/currency-math/build.gradle.kts +++ b/libs/currency-math/build.gradle.kts @@ -5,6 +5,9 @@ plugins { kotlin { android { namespace = "${Gradle.codeNamespace}.libs.currency.math" + // The KMP android target skips res and assets unless this is on, and the curve tables + // ship as assets. Without it the app has no tables and crashes on the first token balance. + androidResources { enable = true } withDeviceTestBuilder {}.configure { instrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" }