From af4a59e22876133ab27d4694a45edbac659efb20 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 16 Mar 2026 14:43:54 +0100 Subject: [PATCH 001/118] fix(scripts): make sed commands portable for GNU and BSD variants --- scripts/app_config/configure_stack_wallet.sh | 17 +++++++---------- .../platforms/macos/platform_config.sh | 18 +++++++++++++----- scripts/app_config/shared/update_version.sh | 14 ++++++-------- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/scripts/app_config/configure_stack_wallet.sh b/scripts/app_config/configure_stack_wallet.sh index c68de3f3e..2d83715d1 100755 --- a/scripts/app_config/configure_stack_wallet.sh +++ b/scripts/app_config/configure_stack_wallet.sh @@ -13,15 +13,12 @@ export NEW_BASIC_NAME="stack_wallet" NEW_PUBSPEC_NAME="stackwallet" PUBSPEC_FILE="${APP_PROJECT_ROOT_DIR}/pubspec.yaml" -# String replacements. -if [[ "$(uname)" == 'Darwin' ]]; then - # macos specific sed - sed -i '' "s/name: PLACEHOLDER/name: ${NEW_PUBSPEC_NAME}/g" "${PUBSPEC_FILE}" - sed -i '' "s/description: PLACEHOLDER/description: ${NEW_NAME}/g" "${PUBSPEC_FILE}" -else - sed -i "s/name: PLACEHOLDER/name: ${NEW_PUBSPEC_NAME}/g" "${PUBSPEC_FILE}" - sed -i "s/description: PLACEHOLDER/description: ${NEW_NAME}/g" "${PUBSPEC_FILE}" -fi +# ========================================== +# FIX: Cross-Platform sed (macOS, Linux, Nix) +# ========================================== +sed -i.bak "s/name: PLACEHOLDER/name: ${NEW_PUBSPEC_NAME}/g" "${PUBSPEC_FILE}" +sed -i.bak "s/description: PLACEHOLDER/description: ${NEW_NAME}/g" "${PUBSPEC_FILE}" +rm -f "${PUBSPEC_FILE}.bak" dart "${APP_PROJECT_ROOT_DIR}/tool/process_pubspec_deps.dart" \ "${PUBSPEC_FILE}" \ @@ -146,4 +143,4 @@ _swapDefaults = ( toFuzzyNet: "xmr", ); -EOF \ No newline at end of file +EOF diff --git a/scripts/app_config/platforms/macos/platform_config.sh b/scripts/app_config/platforms/macos/platform_config.sh index c54ba32a6..e7aeebf78 100755 --- a/scripts/app_config/platforms/macos/platform_config.sh +++ b/scripts/app_config/platforms/macos/platform_config.sh @@ -12,9 +12,17 @@ for (( i=0; i<=2; i++ )); do fi done +# ========================================== +# FIX: Cross-Platform sed (macOS, Linux, Nix) +# ========================================== # Configure macOS for Duo. -sed -i '' "s/${APP_ID_PLACEHOLDER_CAMEL}/${NEW_APP_ID_CAMEL}/g" "${APP_PROJECT_ROOT_DIR}/${MAC_TF_0}" -sed -i '' "s/${APP_NAME_PLACEHOLDER}/${NEW_NAME}/g" "${APP_PROJECT_ROOT_DIR}/${MAC_TF_0}" -sed -i '' "s/${APP_NAME_PLACEHOLDER}/${NEW_NAME}/g" "${APP_PROJECT_ROOT_DIR}/${MAC_TF_1}" -sed -i '' "s/${APP_NAME_PLACEHOLDER}/${NEW_NAME}/g" "${APP_PROJECT_ROOT_DIR}/${MAC_TF_2}" -sed -i '' "s/${APP_ID_PLACEHOLDER_SNAKE}/${NEW_APP_ID_SNAKE}/g" "${APP_PROJECT_ROOT_DIR}/${MAC_TF_2}" +sed -i.bak "s/${APP_ID_PLACEHOLDER_CAMEL}/${NEW_APP_ID_CAMEL}/g" "${APP_PROJECT_ROOT_DIR}/${MAC_TF_0}" +sed -i.bak "s/${APP_NAME_PLACEHOLDER}/${NEW_NAME}/g" "${APP_PROJECT_ROOT_DIR}/${MAC_TF_0}" +sed -i.bak "s/${APP_NAME_PLACEHOLDER}/${NEW_NAME}/g" "${APP_PROJECT_ROOT_DIR}/${MAC_TF_1}" +sed -i.bak "s/${APP_NAME_PLACEHOLDER}/${NEW_NAME}/g" "${APP_PROJECT_ROOT_DIR}/${MAC_TF_2}" +sed -i.bak "s/${APP_ID_PLACEHOLDER_SNAKE}/${NEW_APP_ID_SNAKE}/g" "${APP_PROJECT_ROOT_DIR}/${MAC_TF_2}" + +# Clean up backup files +rm -f "${APP_PROJECT_ROOT_DIR}/${MAC_TF_0}.bak" +rm -f "${APP_PROJECT_ROOT_DIR}/${MAC_TF_1}.bak" +rm -f "${APP_PROJECT_ROOT_DIR}/${MAC_TF_2}.bak" diff --git a/scripts/app_config/shared/update_version.sh b/scripts/app_config/shared/update_version.sh index d056b9b73..c0dafa38c 100755 --- a/scripts/app_config/shared/update_version.sh +++ b/scripts/app_config/shared/update_version.sh @@ -34,13 +34,11 @@ if [ ! -f "$PUBSPEC_FILE" ]; then exit 1 fi -if [[ "$(uname)" == 'Darwin' ]]; then - # macos specific sed - sed -i '' "s/PLACEHOLDER_V/$VERSION/g" "${PUBSPEC_FILE}" - sed -i '' "s/PLACEHOLDER_B/$BUILD_NUMBER/g" "${PUBSPEC_FILE}" -else - sed -i "s/PLACEHOLDER_V/$VERSION/g" "${PUBSPEC_FILE}" - sed -i "s/PLACEHOLDER_B/$BUILD_NUMBER/g" "${PUBSPEC_FILE}" -fi +# ========================================== +# FIX: Cross-Platform sed (macOS, Linux, Nix) +# ========================================== +sed -i.bak "s/PLACEHOLDER_V/$VERSION/g" "${PUBSPEC_FILE}" +sed -i.bak "s/PLACEHOLDER_B/$BUILD_NUMBER/g" "${PUBSPEC_FILE}" +rm -f "${PUBSPEC_FILE}.bak" echo "Updated $PUBSPEC_FILE with version: $VERSION and build number: $BUILD_NUMBER" From 2cbb5aabdf85ac830fa4dad1bd6eccd9489c550d Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 16 Mar 2026 14:45:07 +0100 Subject: [PATCH 002/118] fix(scripts): use 'flutter pub run' instead of 'dart run' for launcher icons Co-authored-by: sneurlax --- scripts/app_config/shared/asset_generators.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/scripts/app_config/shared/asset_generators.sh b/scripts/app_config/shared/asset_generators.sh index a2d948758..54ebd5462 100755 --- a/scripts/app_config/shared/asset_generators.sh +++ b/scripts/app_config/shared/asset_generators.sh @@ -12,6 +12,7 @@ APP_BUILD_PLATFORM=$1 # run icon and image generators pushd "${APP_PROJECT_ROOT_DIR}" YAML_FILE="${APP_PROJECT_ROOT_DIR}/scripts/app_config/platforms/${APP_BUILD_PLATFORM}/flutter_launcher_icons.yaml" + if [[ "${APP_BUILD_PLATFORM}" = 'windows' ]]; then cmd.exe /c flutter pub get if command -v cygpath >/dev/null 2>&1; then @@ -19,15 +20,18 @@ if [[ "${APP_BUILD_PLATFORM}" = 'windows' ]]; then else WIN_PATH_VERSION=$(wslpath -w "${YAML_FILE}") fi - cmd.exe /c dart run flutter_launcher_icons -f "${WIN_PATH_VERSION}" + # FIX: Changed dart run to flutter pub run + cmd.exe /c flutter pub run flutter_launcher_icons -f "${WIN_PATH_VERSION}" # not needed in windows -# cmd.exe /c dart run flutter_native_splash:create +# cmd.exe /c flutter pub run flutter_native_splash:create else flutter pub get - dart run flutter_launcher_icons -f "${YAML_FILE}" + # FIX: Changed dart run to flutter pub run + flutter pub run flutter_launcher_icons -f "${YAML_FILE}" if [[ "${APP_BUILD_PLATFORM}" = 'ios' || "${APP_BUILD_PLATFORM}" = 'android' ]]; then - dart run flutter_native_splash:create + # FIX: Changed dart run to flutter pub run + flutter pub run flutter_native_splash:create fi fi -popd \ No newline at end of file +popd From 81f427d0218679209851733e6027645ab2259a68 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 16 Mar 2026 14:48:46 +0100 Subject: [PATCH 003/118] feat(nix): introduce flake-based dev shell for guaranteed reproducibility --- flake.nix | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 flake.nix diff --git a/flake.nix b/flake.nix new file mode 100644 index 000000000..aa65f776f --- /dev/null +++ b/flake.nix @@ -0,0 +1,87 @@ + + description = "Stack Wallet Build Environment"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; }; + lib = pkgs.lib; + + commonPackages = with pkgs; [ + flutter + dart + rustup + cmake + meson + ninja + pkg-config + gnumake + gnused + (python3.withPackages (ps: with ps; [ + pip toml tomli jinja2 markdown markupsafe pygments typogrify + ])) + ]; + + linuxPackages = lib.optionals pkgs.stdenv.isLinux (with pkgs; [ + gtk3 glib openssl xz clang + ]); + + macPackages = lib.optionals pkgs.stdenv.isDarwin (with pkgs; [ + cocoapods + libiconv + ]); + + in + { + devShells.default = pkgs.mkShell { + buildInputs = commonPackages ++ linuxPackages ++ macPackages; + + shellHook = '' + echo "===================================================" + echo "Stack Wallet Dev-Environment activated!" + echo "Target System: ${system}" + echo "===================================================" + + export PATH="$HOME/.cargo/bin:$PATH" + + # ========================================== + # RUST TOOLCHAIN AUTOMATION + # ========================================== + if ! rustup toolchain list | grep -q "1.89.0"; then + echo "Initializing Rust toolchains (this happens only once)..." + rustup install 1.89.0 1.85.1 1.81.0 + rustup default 1.89.0 + + if [[ "${system}" == *"darwin"* ]]; then + rustup target add aarch64-apple-darwin aarch64-apple-ios + fi + fi + + if ! command -v cbindgen >/dev/null 2>&1 || ! command -v cargo-lipo >/dev/null 2>&1; then + echo "Installing required Cargo tools..." + cargo install cargo-ndk cbindgen cargo-lipo + fi + + # ========================================== + # MACOS XCODE SANDBOX ESCAPE + # ========================================== + # Enables cargo-lipo to access the host's native Apple build tools + ${lib.optionalString pkgs.stdenv.isDarwin '' + export CPATH="$(xcrun --show-sdk-path)/usr/include:$CPATH" + + mkdir -p .nix-bin + ln -sf /usr/bin/xcodebuild .nix-bin/xcodebuild + ln -sf /usr/bin/xcrun .nix-bin/xcrun + ln -sf /usr/bin/lipo .nix-bin/lipo + export PATH="$PWD/.nix-bin:$PATH" + ''} + ''; + }; + } + ); +} From e6be04e2782b7034ab74a5ec275ce19147acb13f Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 16 Mar 2026 14:49:57 +0100 Subject: [PATCH 004/118] feat(makefile): build management --- Makefile | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..15ebc53bc --- /dev/null +++ b/Makefile @@ -0,0 +1,123 @@ +# ============================================================================== +# Stack Wallet Universal Build Makefile +# Override variables if needed: make build-linux VERSION=3.0.0 BUILD_NUM=300 +# ============================================================================== + +APP_NAME ?= stack_wallet +VERSION ?= 2.1.0 +BUILD_NUM ?= 210 +FLUTTER ?= flutter +DART ?= dart + +.PHONY: help check-reqs check-reqs-windows check-macos-sdk init clean prebuild-unix prebuild-windows deps-linux build-linux build-macos build-ios build-android build-windows + +help: ## Shows all available make commands + @echo "Available targets:" + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' + +# --- PREREQUISITES CHECK --- + +check-reqs: ## Checks if essential build tools (Flutter, Rust, CMake, etc.) are installed + @echo "Checking core prerequisites..." + @command -v $(FLUTTER) >/dev/null 2>&1 || { echo >&2 "❌ Flutter is not installed. Aborting."; exit 1; } + @command -v $(DART) >/dev/null 2>&1 || { echo >&2 "❌ Dart is not installed. Aborting."; exit 1; } + @command -v cargo >/dev/null 2>&1 || { echo >&2 "❌ Rust (cargo) is not installed. Aborting."; exit 1; } + @command -v rustup >/dev/null 2>&1 || { echo >&2 "❌ rustup is not installed. Aborting."; exit 1; } + @command -v cmake >/dev/null 2>&1 || { echo >&2 "❌ CMake is not installed. Aborting."; exit 1; } + @command -v meson >/dev/null 2>&1 || { echo >&2 "❌ Meson is not installed. Aborting."; exit 1; } + @command -v pkg-config >/dev/null 2>&1 || { echo >&2 "❌ pkg-config is not installed. Aborting."; exit 1; } + @echo "✅ All core CLI requirements found!" + +check-macos-sdk: ## NEW: Specifically checks for full Xcode installation on macOS +ifeq ($(shell uname), Darwin) + @echo "Checking macOS SDK requirements..." + @xcode-select -p | grep -q "Xcode.app" || ( \ + echo "❌ ERROR: Full Xcode installation not detected!"; \ + echo " The build requires the full Xcode app, not just Command Line Tools."; \ + echo " Path should be: /Applications/Xcode.app/Contents/Developer"; \ + exit 1) + @echo "✅ Xcode SDK path looks good." +endif + +check-reqs-windows: ## Specific checks for Windows/WSL environments + @echo "Checking Windows specific prerequisites..." + @command -v wsl >/dev/null 2>&1 || { echo >&2 "❌ WSL is not installed. Aborting."; exit 1; } + @echo "✅ Windows/WSL requirements found!" + +# --- COMMON SETUP STEPS --- + +init: ## Clones the repository and initializes all submodules + git submodule update --init --recursive + +clean: ## Cleans all Flutter, Dart, and Rust build artifacts + $(FLUTTER) clean + cargo clean + +prebuild-unix: ## Executes the prebuild script (keys/parameters) for Unix systems + cd scripts && ./prebuild.sh + +prebuild-windows: ## Executes the prebuild script for Windows (via PowerShell) + cd scripts && powershell.exe -ExecutionPolicy Bypass -File prebuild.ps1 + +# --- LINUX --- + +deps-linux: ## Builds Linux-specific secure storage dependencies + cd scripts/linux && ./build_secure_storage_deps.sh + +build-linux: check-reqs init prebuild-unix deps-linux ## Complete release build for Linux + @echo "1. Generating pubspec.yaml and building native crypto plugins..." + cd scripts && ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f + @echo "2. Fetching Dart dependencies..." + $(FLUTTER) pub get + @echo "3. Building secp256k1 (coinlib)..." + $(DART) run coinlib:build_linux + @echo "4. Compiling Flutter App..." + $(FLUTTER) build linux --release + +# --- MACOS --- + +build-macos: check-reqs check-macos-sdk init prebuild-unix ## Complete release build for macOS + @echo "1. Generating pubspec.yaml and building native crypto plugins..." + # Added -f to bypass prompts + cd scripts && ./build_app.sh -a $(APP_NAME) -p macos -v $(VERSION) -b $(BUILD_NUM) -f + @echo "2. Fetching Dart dependencies..." + $(FLUTTER) pub get + @echo "3. Building secp256k1 (coinlib)..." + # coinlib:build_macos uses lipo internally + $(DART) run coinlib:build_macos + @echo "4. Compiling Flutter App..." + $(FLUTTER) build macos --release + +# --- IOS --- + +build-ios: check-reqs check-macos-sdk init prebuild-unix ## Complete release build for iOS + @echo "1. Generating pubspec.yaml and building native crypto plugins..." + cd scripts && ./build_app.sh -a $(APP_NAME) -p ios -v $(VERSION) -b $(BUILD_NUM) -f + @echo "2. Fetching Dart dependencies..." + $(FLUTTER) pub get + @echo "3. Compiling Flutter App..." + $(FLUTTER) build ios --release --no-codesign + +# --- ANDROID --- + +build-android: check-reqs init prebuild-unix ## Complete release build for Android (APK) + @echo "1. Generating pubspec.yaml and building native crypto plugins..." + cd scripts && ./build_app.sh -a $(APP_NAME) -p android -v $(VERSION) -b $(BUILD_NUM) -f + @echo "2. Fetching Dart dependencies..." + $(FLUTTER) pub get + @echo "3. Compiling Flutter App..." + $(FLUTTER) build apk --release + +# --- WINDOWS --- + +build-windows: check-reqs check-reqs-windows init prebuild-windows ## Complete release build for Windows + @echo "1. Generating pubspec.yaml and building native plugins in WSL..." + wsl bash -c "cd scripts && ./build_app.sh -a $(APP_NAME) -p windows -v $(VERSION) -b $(BUILD_NUM) -f" + @echo "2. Fetching Dart dependencies natively..." + $(FLUTTER) pub get + @echo "3. Building secp256k1 natively..." + $(DART) run coinlib:build_windows + @echo "4. Building frostdart natively..." + cd crypto_plugins/frostdart && build_all.bat + @echo "5. Compiling Flutter App..." + $(FLUTTER) build windows --release From 010eadd912ff56e87b83db508ea1d6460069bd8f Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 16 Mar 2026 14:58:06 +0100 Subject: [PATCH 005/118] fixing flake --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index aa65f776f..28b8cad20 100644 --- a/flake.nix +++ b/flake.nix @@ -1,4 +1,4 @@ - +{ description = "Stack Wallet Build Environment"; inputs = { From 5f9a8ced37b50f79d43746544f9f29d6aec8238d Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 16 Mar 2026 15:46:53 +0100 Subject: [PATCH 006/118] submodules fix and macOs specific nix fixes --- Makefile | 19 ++++++++++++------- flake.nix | 20 +++++++++++++++++++- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 15ebc53bc..d6f5bee9d 100644 --- a/Makefile +++ b/Makefile @@ -59,6 +59,11 @@ prebuild-unix: ## Executes the prebuild script (keys/parameters) for Unix system prebuild-windows: ## Executes the prebuild script for Windows (via PowerShell) cd scripts && powershell.exe -ExecutionPolicy Bypass -File prebuild.ps1 +patch-submodules: ## Patches non-portable sed calls in submodules + @echo "Patching submodules for portability..." + @find crypto_plugins -name "build_all.sh" -exec sed -i.bak 's|/\$${OS}_VERSION/c\\.*|s\|/\\\*\$${OSX}_VERSION\\\*/.*\|/\\\*\$${OSX}_VERSION\\\*/ const \$${OSX}_VERSION = \\"$$COMMIT\\";\|g|g' {} \; + @find crypto_plugins -name "*.bak" -delete + # --- LINUX --- deps-linux: ## Builds Linux-specific secure storage dependencies @@ -76,16 +81,16 @@ build-linux: check-reqs init prebuild-unix deps-linux ## Complete release build # --- MACOS --- -build-macos: check-reqs check-macos-sdk init prebuild-unix ## Complete release build for macOS - @echo "1. Generating pubspec.yaml and building native crypto plugins..." - # Added -f to bypass prompts - cd scripts && ./build_app.sh -a $(APP_NAME) -p macos -v $(VERSION) -b $(BUILD_NUM) -f +build-macos: check-reqs check-macos-sdk init patch-submodules prebuild-unix ## Complete release build for macOS + @echo "1. Patching version placeholders..." + ./scripts/app_config/shared/update_version.sh -v $(VERSION) -b $(BUILD_NUM) @echo "2. Fetching Dart dependencies..." $(FLUTTER) pub get - @echo "3. Building secp256k1 (coinlib)..." - # coinlib:build_macos uses lipo internally + @echo "3. Generating app config and building native crypto plugins..." + cd scripts && yes yes | BUILD_ISAR_FROM_SOURCE=0 ./build_app.sh -a $(APP_NAME) -p macos -v $(VERSION) -b $(BUILD_NUM) - + @echo "4. Building secp256k1 (coinlib)..." $(DART) run coinlib:build_macos - @echo "4. Compiling Flutter App..." + @echo "5. Compiling Flutter App..." $(FLUTTER) build macos --release # --- IOS --- diff --git a/flake.nix b/flake.nix index 28b8cad20..94b797aee 100644 --- a/flake.nix +++ b/flake.nix @@ -46,7 +46,20 @@ echo "Stack Wallet Dev-Environment activated!" echo "Target System: ${system}" echo "===================================================" - + + export APP_PROJECT_ROOT_DIR=$(pwd) + export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer" + export SDKROOT=$(xcrun --sdk macosx --show-sdk-path) + export PATH="$HOME/.cargo/bin:$PWD/.nix-bin:$PATH" + unset CPATH + export CPATH="$SDKROOT/usr/include" + export LIBRARY_PATH="$SDKROOT/usr/lib" + export CXXFLAGS="-isysroot $SDKROOT -I$SDKROOT/usr/include/c++/v1" + export CFLAGS="-isysroot $SDKROOT" + export LDFLAGS="-isysroot $SDKROOT" + + + export PATH="$HOME/.cargo/bin:$PATH" # ========================================== @@ -67,6 +80,8 @@ cargo install cargo-ndk cbindgen cargo-lipo fi + export BINDGEN_EXTRA_CLANG_ARGS="-isysroot $SDKROOT" + # ========================================== # MACOS XCODE SANDBOX ESCAPE # ========================================== @@ -78,6 +93,9 @@ ln -sf /usr/bin/xcodebuild .nix-bin/xcodebuild ln -sf /usr/bin/xcrun .nix-bin/xcrun ln -sf /usr/bin/lipo .nix-bin/lipo + ln -sf /usr/bin/clang .nix-bin/clang + ln -sf /usr/bin/clang++ .nix-bin/clang++ + export PATH="$PWD/.nix-bin:$PATH" ''} ''; From 4454920c136f37b452e351e657a6b49c2760000a Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 16 Mar 2026 16:11:27 +0100 Subject: [PATCH 007/118] adding changes for successful macOs run --- Makefile | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index d6f5bee9d..adfd5018e 100644 --- a/Makefile +++ b/Makefile @@ -59,10 +59,14 @@ prebuild-unix: ## Executes the prebuild script (keys/parameters) for Unix system prebuild-windows: ## Executes the prebuild script for Windows (via PowerShell) cd scripts && powershell.exe -ExecutionPolicy Bypass -File prebuild.ps1 -patch-submodules: ## Patches non-portable sed calls in submodules - @echo "Patching submodules for portability..." +patch-submodules: ## Patches non-portable sed calls and version logic in submodules + @echo "Cleaning up old build artifacts..." + @rm -rf crypto_plugins/*/scripts/macos/build + @echo "Patching submodules for portability (Bash & Dart)..." @find crypto_plugins -name "build_all.sh" -exec sed -i.bak 's|/\$${OS}_VERSION/c\\.*|s\|/\\\*\$${OSX}_VERSION\\\*/.*\|/\\\*\$${OSX}_VERSION\\\*/ const \$${OSX}_VERSION = \\"$$COMMIT\\";\|g|g' {} \; + @find crypto_plugins/frostdart -name "build_macos.dart" -type f -exec sed -i.bak 's/\["-i", ".bak",/\["-i.bak",/g' {} + @find crypto_plugins -name "*.bak" -delete + @echo "All submodules patched and ready." # --- LINUX --- @@ -89,7 +93,7 @@ build-macos: check-reqs check-macos-sdk init patch-submodules prebuild-unix ## C @echo "3. Generating app config and building native crypto plugins..." cd scripts && yes yes | BUILD_ISAR_FROM_SOURCE=0 ./build_app.sh -a $(APP_NAME) -p macos -v $(VERSION) -b $(BUILD_NUM) - @echo "4. Building secp256k1 (coinlib)..." - $(DART) run coinlib:build_macos + $(FLUTTER) pub run coinlib:build_macos @echo "5. Compiling Flutter App..." $(FLUTTER) build macos --release From 6ce520ace458638536a60701dcddc0ad90f2f98e Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 16 Mar 2026 16:51:18 +0100 Subject: [PATCH 008/118] fixing part in last build step (dropping flags) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index adfd5018e..897b22ff5 100644 --- a/Makefile +++ b/Makefile @@ -95,7 +95,7 @@ build-macos: check-reqs check-macos-sdk init patch-submodules prebuild-unix ## C @echo "4. Building secp256k1 (coinlib)..." $(FLUTTER) pub run coinlib:build_macos @echo "5. Compiling Flutter App..." - $(FLUTTER) build macos --release + env -u CXXFLAGS -u CFLAGS -u LDFLAGS -u CPATH -u LIBRARY_PATH $(FLUTTER) build macos --release # --- IOS --- From 1d486412b9928ba036dadf22a6971735236d57f9 Mon Sep 17 00:00:00 2001 From: Parasew L14 Date: Mon, 16 Mar 2026 16:52:41 +0100 Subject: [PATCH 009/118] adding linux parts Co-authored-by: sneurlax --- flake.nix | 43 ++++++++++++---------- scripts/linux/build_secure_storage_deps.sh | 4 +- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/flake.nix b/flake.nix index 94b797aee..f99c18ef7 100644 --- a/flake.nix +++ b/flake.nix @@ -15,6 +15,7 @@ commonPackages = with pkgs; [ flutter dart + go rustup cmake meson @@ -28,7 +29,7 @@ ]; linuxPackages = lib.optionals pkgs.stdenv.isLinux (with pkgs; [ - gtk3 glib openssl xz clang + gtk3 glib openssl xz clang libgcrypt gobject-introspection ]); macPackages = lib.optionals pkgs.stdenv.isDarwin (with pkgs; [ @@ -47,19 +48,7 @@ echo "Target System: ${system}" echo "===================================================" - export APP_PROJECT_ROOT_DIR=$(pwd) - export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer" - export SDKROOT=$(xcrun --sdk macosx --show-sdk-path) - export PATH="$HOME/.cargo/bin:$PWD/.nix-bin:$PATH" - unset CPATH - export CPATH="$SDKROOT/usr/include" - export LIBRARY_PATH="$SDKROOT/usr/lib" - export CXXFLAGS="-isysroot $SDKROOT -I$SDKROOT/usr/include/c++/v1" - export CFLAGS="-isysroot $SDKROOT" - export LDFLAGS="-isysroot $SDKROOT" - - - + export APP_PROJECT_ROOT_DIR=$(pwd) export PATH="$HOME/.cargo/bin:$PATH" # ========================================== @@ -80,22 +69,36 @@ cargo install cargo-ndk cbindgen cargo-lipo fi - export BINDGEN_EXTRA_CLANG_ARGS="-isysroot $SDKROOT" + # ========================================== + # LINUX (NixOS) SPECIFICS + # ========================================== + ${lib.optionalString pkgs.stdenv.isLinux '' + echo "🐧 Linux detected: Patching shebangs for NixOS..." + patchShebangs scripts/ crypto_plugins/ > /dev/null 2>&1 || true + ''} # ========================================== # MACOS XCODE SANDBOX ESCAPE # ========================================== - # Enables cargo-lipo to access the host's native Apple build tools ${lib.optionalString pkgs.stdenv.isDarwin '' - export CPATH="$(xcrun --show-sdk-path)/usr/include:$CPATH" + export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer" + export SDKROOT=$(xcrun --sdk macosx --show-sdk-path) + + unset CPATH + export CPATH="$SDKROOT/usr/include" + export LIBRARY_PATH="$SDKROOT/usr/lib" + export CXXFLAGS="-isysroot $SDKROOT -I$SDKROOT/usr/include/c++/v1" + export CFLAGS="-isysroot $SDKROOT" + export LDFLAGS="-isysroot $SDKROOT" + export BINDGEN_EXTRA_CLANG_ARGS="-isysroot $SDKROOT" mkdir -p .nix-bin ln -sf /usr/bin/xcodebuild .nix-bin/xcodebuild ln -sf /usr/bin/xcrun .nix-bin/xcrun ln -sf /usr/bin/lipo .nix-bin/lipo - ln -sf /usr/bin/clang .nix-bin/clang - ln -sf /usr/bin/clang++ .nix-bin/clang++ - + ln -sf /usr/bin/clang .nix-bin/clang + ln -sf /usr/bin/clang++ .nix-bin/clang++ + export PATH="$PWD/.nix-bin:$PATH" ''} ''; diff --git a/scripts/linux/build_secure_storage_deps.sh b/scripts/linux/build_secure_storage_deps.sh index e84572bca..145b34718 100755 --- a/scripts/linux/build_secure_storage_deps.sh +++ b/scripts/linux/build_secure_storage_deps.sh @@ -21,7 +21,7 @@ cd jsoncpp || exit 1 git checkout $JSONCPP_TAG mkdir -p build cd build || exit 1 -cmake -DCMAKE_BUILD_TYPE=release -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=ON -DARCHIVE_INSTALL_DIR=. -G "Unix Makefiles" .. +cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_BUILD_TYPE=release -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=ON -DARCHIVE_INSTALL_DIR=. -G "Unix Makefiles" .. make -j"$(nproc)" cd "$LINUX_DIRECTORY" || exit 1 @@ -38,7 +38,7 @@ if ! [ -x "$(command -v meson)" ]; then echo 'Error: meson is not installed.' >&2 exit 1 fi -meson _build -Dmanpage=false -Dgtk_doc=false +meson _build -Dvapi=false -Dmanpage=false -Dgtk_doc=false if ! [ -x "$(command -v ninja)" ]; then echo 'Error: ninja is not installed.' >&2 exit 1 From 7759828aa120ebfba537ae49d9c7828d940d7392 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 16 Mar 2026 17:21:00 +0100 Subject: [PATCH 010/118] removing overrides --- flake.nix | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.nix b/flake.nix index f99c18ef7..fee16ba83 100644 --- a/flake.nix +++ b/flake.nix @@ -84,12 +84,12 @@ export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer" export SDKROOT=$(xcrun --sdk macosx --show-sdk-path) - unset CPATH - export CPATH="$SDKROOT/usr/include" - export LIBRARY_PATH="$SDKROOT/usr/lib" - export CXXFLAGS="-isysroot $SDKROOT -I$SDKROOT/usr/include/c++/v1" - export CFLAGS="-isysroot $SDKROOT" - export LDFLAGS="-isysroot $SDKROOT" + #unset CPATH + #export CPATH="$SDKROOT/usr/include" + #export LIBRARY_PATH="$SDKROOT/usr/lib" + #export CXXFLAGS="-isysroot $SDKROOT -I$SDKROOT/usr/include/c++/v1" + #export CFLAGS="-isysroot $SDKROOT" + #export LDFLAGS="-isysroot $SDKROOT" export BINDGEN_EXTRA_CLANG_ARGS="-isysroot $SDKROOT" mkdir -p .nix-bin From f2045117e5b23c0d21533ae87e0d1656ff3bb81d Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 16 Mar 2026 18:20:57 +0100 Subject: [PATCH 011/118] adding better clean --- Makefile | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 897b22ff5..d92e0e69a 100644 --- a/Makefile +++ b/Makefile @@ -49,9 +49,21 @@ check-reqs-windows: ## Specific checks for Windows/WSL environments init: ## Clones the repository and initializes all submodules git submodule update --init --recursive -clean: ## Cleans all Flutter, Dart, and Rust build artifacts +clean: ## Cleans all Flutter, Dart, Rust, and flaky dependency artifacts + @echo "1. Cleaning local Flutter and Rust artifacts..." $(FLUTTER) clean - cargo clean + @if [ -f "Cargo.toml" ]; then cargo clean; fi + + @echo "2. Cleaning local platform specific artifacts..." + rm -rf macos/Pods macos/Podfile.lock + rm -rf ios/Pods ios/Podfile.lock + rm -rf build/ + + @echo "3. Cleaning flaky external dependency residues (Pub-Cache)..." + @chmod -R u+w $(HOME)/.pub-cache/git/ 2>/dev/null || true + @find $(HOME)/.pub-cache/git/ -type d \( -name "build" -o -name "target" \) \ + -path "*flutter_lib*" -exec rm -rf {} + 2>/dev/null || true + @echo "All clean. You can now run build-macos or build-linux starting from a fresh state." prebuild-unix: ## Executes the prebuild script (keys/parameters) for Unix systems cd scripts && ./prebuild.sh From e62c261bd6f02746a8a93c9756069acdeb7d17ba Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 16 Mar 2026 18:33:22 +0100 Subject: [PATCH 012/118] macos makefile fixes --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index d92e0e69a..53054cd21 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,7 @@ init: ## Clones the repository and initializes all submodules clean: ## Cleans all Flutter, Dart, Rust, and flaky dependency artifacts @echo "1. Cleaning local Flutter and Rust artifacts..." + @chmod -R u+w crypto_plugins/ 2>/dev/null || true $(FLUTTER) clean @if [ -f "Cargo.toml" ]; then cargo clean; fi @@ -73,6 +74,7 @@ prebuild-windows: ## Executes the prebuild script for Windows (via PowerShell) patch-submodules: ## Patches non-portable sed calls and version logic in submodules @echo "Cleaning up old build artifacts..." + @chmod -R u+w crypto_plugins/ 2>/dev/null || true @rm -rf crypto_plugins/*/scripts/macos/build @echo "Patching submodules for portability (Bash & Dart)..." @find crypto_plugins -name "build_all.sh" -exec sed -i.bak 's|/\$${OS}_VERSION/c\\.*|s\|/\\\*\$${OSX}_VERSION\\\*/.*\|/\\\*\$${OSX}_VERSION\\\*/ const \$${OSX}_VERSION = \\"$$COMMIT\\";\|g|g' {} \; From 6ba1741c55f43e73539380982ecc1ac108bbcaf9 Mon Sep 17 00:00:00 2001 From: Parasew L14 Date: Mon, 16 Mar 2026 18:27:23 +0100 Subject: [PATCH 013/118] up --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 53054cd21..b703a45c5 100644 --- a/Makefile +++ b/Makefile @@ -87,13 +87,13 @@ patch-submodules: ## Patches non-portable sed calls and version logic in submodu deps-linux: ## Builds Linux-specific secure storage dependencies cd scripts/linux && ./build_secure_storage_deps.sh -build-linux: check-reqs init prebuild-unix deps-linux ## Complete release build for Linux +build-linux: check-reqs init patch-submodules prebuild-unix deps-linux @echo "1. Generating pubspec.yaml and building native crypto plugins..." - cd scripts && ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f + cd scripts && yes "yes" | BUILD_ISAR_FROM_SOURCE=0 ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f @echo "2. Fetching Dart dependencies..." $(FLUTTER) pub get @echo "3. Building secp256k1 (coinlib)..." - $(DART) run coinlib:build_linux + $(FLUTTER) pub run coinlib:build_linux @echo "4. Compiling Flutter App..." $(FLUTTER) build linux --release From 5c4304557387435dc10d5ed5ce3dde28ddb4f2a2 Mon Sep 17 00:00:00 2001 From: Parasew L14 Date: Mon, 16 Mar 2026 18:30:29 +0100 Subject: [PATCH 014/118] nixos fixes --- flake.nix | 10 ++++++++-- scripts/app_config/shared/update_version.sh | 3 +-- .../app_config/templates/configure_template_files.sh | 8 ++++---- scripts/app_config/templates/isar_build.sh | 4 ++-- scripts/linux/build_all.sh | 3 +-- scripts/prebuild.sh | 2 +- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/flake.nix b/flake.nix index fee16ba83..c2fcb8913 100644 --- a/flake.nix +++ b/flake.nix @@ -30,6 +30,9 @@ linuxPackages = lib.optionals pkgs.stdenv.isLinux (with pkgs; [ gtk3 glib openssl xz clang libgcrypt gobject-introspection + llvmPackages.libclang + llvmPackages.clang + protobuf ]); macPackages = lib.optionals pkgs.stdenv.isDarwin (with pkgs; [ @@ -73,8 +76,11 @@ # LINUX (NixOS) SPECIFICS # ========================================== ${lib.optionalString pkgs.stdenv.isLinux '' - echo "🐧 Linux detected: Patching shebangs for NixOS..." - patchShebangs scripts/ crypto_plugins/ > /dev/null 2>&1 || true + # echo "🐧 Linux detected: Patching shebangs for NixOS..." + # patchShebangs scripts/ crypto_plugins/ > /dev/null 2>&1 || true + export LIBCLANG_PATH="${pkgs.llvmPackages.libclang.lib}/lib" + export BINDGEN_EXTRA_CLANG_ARGS="-isystem ${pkgs.llvmPackages.libclang.lib}/lib/clang/${pkgs.llvmPackages.clang.version}/include" + export PROTOC="${pkgs.protobuf}/bin/protoc" ''} # ========================================== diff --git a/scripts/app_config/shared/update_version.sh b/scripts/app_config/shared/update_version.sh index c0dafa38c..5346ec159 100755 --- a/scripts/app_config/shared/update_version.sh +++ b/scripts/app_config/shared/update_version.sh @@ -1,5 +1,4 @@ -#!/bin/bash - +#!/usr/bin/env bash set -x -e # Function to display usage. diff --git a/scripts/app_config/templates/configure_template_files.sh b/scripts/app_config/templates/configure_template_files.sh index 24a4195cf..e56d56de0 100755 --- a/scripts/app_config/templates/configure_template_files.sh +++ b/scripts/app_config/templates/configure_template_files.sh @@ -67,7 +67,7 @@ for TF in "${TEMPLATE_FILES[@]}"; do cp -rp "${TEMPLATES_DIR}/${TF}" "${FILE}" done -if [ "$BUILD_ISAR_FROM_SOURCE" -eq 1 ]; then - source "${APP_PROJECT_ROOT_DIR}/scripts/app_config/templates/isar_build.sh" - build_isar_source -fi +#if [ "$BUILD_ISAR_FROM_SOURCE" -eq 1 ]; then +# source "${APP_PROJECT_ROOT_DIR}/scripts/app_config/templates/isar_build.sh" +# build_isar_source +#fi diff --git a/scripts/app_config/templates/isar_build.sh b/scripts/app_config/templates/isar_build.sh index d1d53d7f9..79cdf187e 100644 --- a/scripts/app_config/templates/isar_build.sh +++ b/scripts/app_config/templates/isar_build.sh @@ -1,8 +1,8 @@ -#!/bin/bash +#!/usr/bin/env bash find_isar_core_lib() { local isar_core_path - isar_core_path=$(find "${HOME}/.pub-cache/git" -type d -path "*/isar_core_ffi" -print -quit 2>/dev/null) + isar_core_path=$(find "${HOME}/.pub-cache" -type d -path "*/isar_core_ffi" -print -quit 2>/dev/null) [[ -z "${isar_core_path}" ]] && return 1 echo "${isar_core_path}" } diff --git a/scripts/linux/build_all.sh b/scripts/linux/build_all.sh index 374b2d462..34bb553c6 100755 --- a/scripts/linux/build_all.sh +++ b/scripts/linux/build_all.sh @@ -1,5 +1,4 @@ -#!/bin/bash - +#!/usr/bin/env bash set -x -e # for arm diff --git a/scripts/prebuild.sh b/scripts/prebuild.sh index 0aa13ea22..30388e347 100755 --- a/scripts/prebuild.sh +++ b/scripts/prebuild.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Create template lib/external_api_keys.dart file if it doesn't already exist KEYS=../lib/external_api_keys.dart From b2a90e7d45e1f23d2d8b9404a864a2f4078ec584 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 16 Mar 2026 18:53:09 +0100 Subject: [PATCH 015/118] Makefile fixes --- Makefile | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index b703a45c5..a6711dc92 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,8 @@ BUILD_NUM ?= 210 FLUTTER ?= flutter DART ?= dart +export PROTOC = $(shell which protoc 2>/dev/null) + .PHONY: help check-reqs check-reqs-windows check-macos-sdk init clean prebuild-unix prebuild-windows deps-linux build-linux build-macos build-ios build-android build-windows help: ## Shows all available make commands @@ -89,7 +91,8 @@ deps-linux: ## Builds Linux-specific secure storage dependencies build-linux: check-reqs init patch-submodules prebuild-unix deps-linux @echo "1. Generating pubspec.yaml and building native crypto plugins..." - cd scripts && yes "yes" | BUILD_ISAR_FROM_SOURCE=0 ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f + #cd scripts && yes "yes" | BUILD_ISAR_FROM_SOURCE=0 ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f + cd scripts && PROTOC=$(shell which protoc) BUILD_ISAR_FROM_SOURCE=0 ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f @echo "2. Fetching Dart dependencies..." $(FLUTTER) pub get @echo "3. Building secp256k1 (coinlib)..." @@ -100,17 +103,29 @@ build-linux: check-reqs init patch-submodules prebuild-unix deps-linux # --- MACOS --- build-macos: check-reqs check-macos-sdk init patch-submodules prebuild-unix ## Complete release build for macOS + @echo "0. Repairing permissions and healing korrupt Xcode project..." + @chmod -R u+w $(HOME)/.pub-cache/git/ 2>/dev/null || true + @chmod -R u+w macos/ 2>/dev/null || true + rm -rf macos/Runner.xcodeproj macos/Runner.xcworkspace + $(FLUTTER) create --platforms=macos . + @echo "1. Patching version placeholders..." ./scripts/app_config/shared/update_version.sh -v $(VERSION) -b $(BUILD_NUM) + @echo "2. Fetching Dart dependencies..." $(FLUTTER) pub get + @echo "3. Generating app config and building native crypto plugins..." - cd scripts && yes yes | BUILD_ISAR_FROM_SOURCE=0 ./build_app.sh -a $(APP_NAME) -p macos -v $(VERSION) -b $(BUILD_NUM) - + cd scripts && yes yes | BUILD_ISAR_FROM_SOURCE=0 \ + bash -c 'rustup() { echo "1.89.0 stable installed"; return 0; }; export -f rustup; ./build_app.sh -a $(APP_NAME) -p macos -v $(VERSION) -b $(BUILD_NUM) -f' + @echo "4. Building secp256k1 (coinlib)..." $(FLUTTER) pub run coinlib:build_macos + @echo "5. Compiling Flutter App..." env -u CXXFLAGS -u CFLAGS -u LDFLAGS -u CPATH -u LIBRARY_PATH $(FLUTTER) build macos --release + # --- IOS --- build-ios: check-reqs check-macos-sdk init prebuild-unix ## Complete release build for iOS From 90c08b825f68019515d13bc7d62f017024bb8dd4 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 16 Mar 2026 19:05:24 +0100 Subject: [PATCH 016/118] makefile fixes --- Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a6711dc92..33ecfb414 100644 --- a/Makefile +++ b/Makefile @@ -92,7 +92,7 @@ deps-linux: ## Builds Linux-specific secure storage dependencies build-linux: check-reqs init patch-submodules prebuild-unix deps-linux @echo "1. Generating pubspec.yaml and building native crypto plugins..." #cd scripts && yes "yes" | BUILD_ISAR_FROM_SOURCE=0 ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f - cd scripts && PROTOC=$(shell which protoc) BUILD_ISAR_FROM_SOURCE=0 ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f + bash -c 'rustup() { echo "1.89.0-stable"; echo "1.85.1-stable"; return 0; }; export -f rustup; ./build_app.sh -a $(APP_NAME) -p macos -v $(VERSION) -b $(BUILD_NUM) -f' @echo "2. Fetching Dart dependencies..." $(FLUTTER) pub get @echo "3. Building secp256k1 (coinlib)..." @@ -117,8 +117,7 @@ build-macos: check-reqs check-macos-sdk init patch-submodules prebuild-unix ## C @echo "3. Generating app config and building native crypto plugins..." cd scripts && yes yes | BUILD_ISAR_FROM_SOURCE=0 \ - bash -c 'rustup() { echo "1.89.0 stable installed"; return 0; }; export -f rustup; ./build_app.sh -a $(APP_NAME) -p macos -v $(VERSION) -b $(BUILD_NUM) -f' - + bash -c 'rustup() { echo "1.89.0-stable"; echo "1.85.1-stable"; return 0; }; export -f rustup; ./build_app.sh -a $(APP_NAME) -p macos -v $(VERSION) -b $(BUILD_NUM) -f' @echo "4. Building secp256k1 (coinlib)..." $(FLUTTER) pub run coinlib:build_macos From 9768ea53e67aaf79ab062c03f79ae8f62ba3254f Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 16 Mar 2026 19:10:29 +0100 Subject: [PATCH 017/118] makefile fixes --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 33ecfb414..71cfdfe74 100644 --- a/Makefile +++ b/Makefile @@ -91,8 +91,8 @@ deps-linux: ## Builds Linux-specific secure storage dependencies build-linux: check-reqs init patch-submodules prebuild-unix deps-linux @echo "1. Generating pubspec.yaml and building native crypto plugins..." - #cd scripts && yes "yes" | BUILD_ISAR_FROM_SOURCE=0 ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f - bash -c 'rustup() { echo "1.89.0-stable"; echo "1.85.1-stable"; return 0; }; export -f rustup; ./build_app.sh -a $(APP_NAME) -p macos -v $(VERSION) -b $(BUILD_NUM) -f' + cd scripts && yes yes | BUILD_ISAR_FROM_SOURCE=0 PROTOC=$$(which protoc) \ + bash -c 'rustup() { echo "1.89.0-stable"; echo "1.85.1-stable"; return 0; }; export -f rustup; ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f' @echo "2. Fetching Dart dependencies..." $(FLUTTER) pub get @echo "3. Building secp256k1 (coinlib)..." From e1a9c7819d941fee8284d53ee2b9181d0b81ed52 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 16 Mar 2026 19:24:36 +0100 Subject: [PATCH 018/118] makefile fixes --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 71cfdfe74..7ff421926 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ FLUTTER ?= flutter DART ?= dart export PROTOC = $(shell which protoc 2>/dev/null) +PROTOC_PATH := $(shell which protoc 2>/dev/null) .PHONY: help check-reqs check-reqs-windows check-macos-sdk init clean prebuild-unix prebuild-windows deps-linux build-linux build-macos build-ios build-android build-windows @@ -91,6 +92,7 @@ deps-linux: ## Builds Linux-specific secure storage dependencies build-linux: check-reqs init patch-submodules prebuild-unix deps-linux @echo "1. Generating pubspec.yaml and building native crypto plugins..." + @if [ -z "$(PROTOC_PATH)" ]; then echo "ERROR: protoc not found!"; exit 1; fi cd scripts && yes yes | BUILD_ISAR_FROM_SOURCE=0 PROTOC=$$(which protoc) \ bash -c 'rustup() { echo "1.89.0-stable"; echo "1.85.1-stable"; return 0; }; export -f rustup; ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f' @echo "2. Fetching Dart dependencies..." @@ -118,10 +120,12 @@ build-macos: check-reqs check-macos-sdk init patch-submodules prebuild-unix ## C @echo "3. Generating app config and building native crypto plugins..." cd scripts && yes yes | BUILD_ISAR_FROM_SOURCE=0 \ bash -c 'rustup() { echo "1.89.0-stable"; echo "1.85.1-stable"; return 0; }; export -f rustup; ./build_app.sh -a $(APP_NAME) -p macos -v $(VERSION) -b $(BUILD_NUM) -f' + @echo "4. Building secp256k1 (coinlib)..." $(FLUTTER) pub run coinlib:build_macos @echo "5. Compiling Flutter App..." + @chmod -R u+w macos/ env -u CXXFLAGS -u CFLAGS -u LDFLAGS -u CPATH -u LIBRARY_PATH $(FLUTTER) build macos --release From 62db43c2053fcbc6cf51242f329a55a142674095 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 08:36:32 +0100 Subject: [PATCH 019/118] successful macOS build --- Makefile | 267 ++++++++++++++++++++++++-------------------------- flake.lock | 61 ++++++++++++ flake.nix | 51 +++++++--- macos/Podfile | 3 +- 4 files changed, 229 insertions(+), 153 deletions(-) create mode 100644 flake.lock diff --git a/Makefile b/Makefile index 7ff421926..fc1227705 100644 --- a/Makefile +++ b/Makefile @@ -1,164 +1,149 @@ # ============================================================================== # Stack Wallet Universal Build Makefile -# Override variables if needed: make build-linux VERSION=3.0.0 BUILD_NUM=300 +# Usage: make VERSION=x.x.x BUILD_NUM=xxx # ============================================================================== -APP_NAME ?= stack_wallet -VERSION ?= 2.1.0 -BUILD_NUM ?= 210 -FLUTTER ?= flutter -DART ?= dart +APP_NAME ?= stack_wallet +VERSION ?= 2.1.0 +BUILD_NUM ?= 210 +FLUTTER ?= flutter +DART ?= dart +PROTOC_PATH := $(shell which protoc 2>/dev/null) -export PROTOC = $(shell which protoc 2>/dev/null) -PROTOC_PATH := $(shell which protoc 2>/dev/null) +.PHONY: help check-reqs check-reqs-windows check-macos-sdk init clean prebuild-unix prebuild-windows deps-linux patch-submodules build-linux build-macos build-ios build-android build-windows -.PHONY: help check-reqs check-reqs-windows check-macos-sdk init clean prebuild-unix prebuild-windows deps-linux build-linux build-macos build-ios build-android build-windows - -help: ## Shows all available make commands +help: ## Show available commands @echo "Available targets:" - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "%-20s %s\n", $$1, $$2}' -# --- PREREQUISITES CHECK --- +# --- PREREQUISITES --- -check-reqs: ## Checks if essential build tools (Flutter, Rust, CMake, etc.) are installed +check-reqs: ## Verify essential build tools @echo "Checking core prerequisites..." - @command -v $(FLUTTER) >/dev/null 2>&1 || { echo >&2 "❌ Flutter is not installed. Aborting."; exit 1; } - @command -v $(DART) >/dev/null 2>&1 || { echo >&2 "❌ Dart is not installed. Aborting."; exit 1; } - @command -v cargo >/dev/null 2>&1 || { echo >&2 "❌ Rust (cargo) is not installed. Aborting."; exit 1; } - @command -v rustup >/dev/null 2>&1 || { echo >&2 "❌ rustup is not installed. Aborting."; exit 1; } - @command -v cmake >/dev/null 2>&1 || { echo >&2 "❌ CMake is not installed. Aborting."; exit 1; } - @command -v meson >/dev/null 2>&1 || { echo >&2 "❌ Meson is not installed. Aborting."; exit 1; } - @command -v pkg-config >/dev/null 2>&1 || { echo >&2 "❌ pkg-config is not installed. Aborting."; exit 1; } - @echo "✅ All core CLI requirements found!" - -check-macos-sdk: ## NEW: Specifically checks for full Xcode installation on macOS -ifeq ($(shell uname), Darwin) + @command -v $(FLUTTER) >/dev/null 2>&1 || { echo >&2 "[ERROR] Flutter not installed."; exit 1; } + @command -v $(DART) >/dev/null 2>&1 || { echo >&2 "[ERROR] Dart not installed."; exit 1; } + @command -v cargo >/dev/null 2>&1 || { echo >&2 "[ERROR] Rust not installed."; exit 1; } + @command -v cmake >/dev/null 2>&1 || { echo >&2 "[ERROR] CMake not installed."; exit 1; } + @command -v pkg-config >/dev/null 2>&1 || { echo >&2 "[ERROR] pkg-config not installed."; exit 1; } + @echo "[OK] All core CLI requirements found!" + +check-macos-sdk: ## Verify XCode on macOS +ifeq ($(shell uname),Darwin) @echo "Checking macOS SDK requirements..." @xcode-select -p | grep -q "Xcode.app" || ( \ - echo "❌ ERROR: Full Xcode installation not detected!"; \ - echo " The build requires the full Xcode app, not just Command Line Tools."; \ - echo " Path should be: /Applications/Xcode.app/Contents/Developer"; \ + echo "[ERROR] Full Xcode installation not detected! Path: /Applications/Xcode.app"; \ exit 1) - @echo "✅ Xcode SDK path looks good." + @echo "[OK] Xcode SDK path looks good." endif -check-reqs-windows: ## Specific checks for Windows/WSL environments - @echo "Checking Windows specific prerequisites..." - @command -v wsl >/dev/null 2>&1 || { echo >&2 "❌ WSL is not installed. Aborting."; exit 1; } - @echo "✅ Windows/WSL requirements found!" +check-reqs-windows: ## Verify Windows/WSL requirements + @echo "Checking Windows prerequisites..." + @command -v wsl >/dev/null 2>&1 || { echo >&2 "[ERROR] WSL is not installed."; exit 1; } + @echo "[OK] Windows/WSL requirements found!" -# --- COMMON SETUP STEPS --- +# --- MAINTENANCE --- -init: ## Clones the repository and initializes all submodules - git submodule update --init --recursive +init: ## Initialize all submodules + @git submodule update --init --recursive -clean: ## Cleans all Flutter, Dart, Rust, and flaky dependency artifacts - @echo "1. Cleaning local Flutter and Rust artifacts..." - @chmod -R u+w crypto_plugins/ 2>/dev/null || true - $(FLUTTER) clean +clean: ## Remove artifacts and fix permissions + @echo "Cleaning Flutter and Rust artifacts..." + @chmod -R u+w crypto_plugins/ build/ macos/ 2>/dev/null || true + @$(FLUTTER) clean @if [ -f "Cargo.toml" ]; then cargo clean; fi - - @echo "2. Cleaning local platform specific artifacts..." - rm -rf macos/Pods macos/Podfile.lock - rm -rf ios/Pods ios/Podfile.lock - rm -rf build/ - - @echo "3. Cleaning flaky external dependency residues (Pub-Cache)..." + @rm -rf macos/Pods macos/Podfile.lock ios/Pods ios/Podfile.lock build/ + @echo "Cleaning submodule target folders..." + @find crypto_plugins/ -type d \( -name "target" -o -name "build" \) -exec rm -rf {} + 2>/dev/null || true + @echo "Cleaning external residues..." @chmod -R u+w $(HOME)/.pub-cache/git/ 2>/dev/null || true - @find $(HOME)/.pub-cache/git/ -type d \( -name "build" -o -name "target" \) \ - -path "*flutter_lib*" -exec rm -rf {} + 2>/dev/null || true - @echo "All clean. You can now run build-macos or build-linux starting from a fresh state." - -prebuild-unix: ## Executes the prebuild script (keys/parameters) for Unix systems - cd scripts && ./prebuild.sh + @find $(HOME)/.pub-cache/git/ -type d \( -name "build" -o -name "target" \) -path "*flutter_lib*" -exec rm -rf {} + 2>/dev/null || true + @echo "[OK] Project is now in a pristine state." -prebuild-windows: ## Executes the prebuild script for Windows (via PowerShell) - cd scripts && powershell.exe -ExecutionPolicy Bypass -File prebuild.ps1 - -patch-submodules: ## Patches non-portable sed calls and version logic in submodules - @echo "Cleaning up old build artifacts..." +patch-submodules: ## Apply portability patches to submodules + @echo "Patching submodules for portability..." @chmod -R u+w crypto_plugins/ 2>/dev/null || true @rm -rf crypto_plugins/*/scripts/macos/build - @echo "Patching submodules for portability (Bash & Dart)..." - @find crypto_plugins -name "build_all.sh" -exec sed -i.bak 's|/\$${OS}_VERSION/c\\.*|s\|/\\\*\$${OSX}_VERSION\\\*/.*\|/\\\*\$${OSX}_VERSION\\\*/ const \$${OSX}_VERSION = \\"$$COMMIT\\";\|g|g' {} \; - @find crypto_plugins/frostdart -name "build_macos.dart" -type f -exec sed -i.bak 's/\["-i", ".bak",/\["-i.bak",/g' {} + - @find crypto_plugins -name "*.bak" -delete - @echo "All submodules patched and ready." - -# --- LINUX --- - -deps-linux: ## Builds Linux-specific secure storage dependencies - cd scripts/linux && ./build_secure_storage_deps.sh - -build-linux: check-reqs init patch-submodules prebuild-unix deps-linux - @echo "1. Generating pubspec.yaml and building native crypto plugins..." - @if [ -z "$(PROTOC_PATH)" ]; then echo "ERROR: protoc not found!"; exit 1; fi - cd scripts && yes yes | BUILD_ISAR_FROM_SOURCE=0 PROTOC=$$(which protoc) \ - bash -c 'rustup() { echo "1.89.0-stable"; echo "1.85.1-stable"; return 0; }; export -f rustup; ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f' - @echo "2. Fetching Dart dependencies..." - $(FLUTTER) pub get - @echo "3. Building secp256k1 (coinlib)..." - $(FLUTTER) pub run coinlib:build_linux - @echo "4. Compiling Flutter App..." - $(FLUTTER) build linux --release - -# --- MACOS --- - -build-macos: check-reqs check-macos-sdk init patch-submodules prebuild-unix ## Complete release build for macOS - @echo "0. Repairing permissions and healing korrupt Xcode project..." - @chmod -R u+w $(HOME)/.pub-cache/git/ 2>/dev/null || true - @chmod -R u+w macos/ 2>/dev/null || true - rm -rf macos/Runner.xcodeproj macos/Runner.xcworkspace - $(FLUTTER) create --platforms=macos . - - @echo "1. Patching version placeholders..." - ./scripts/app_config/shared/update_version.sh -v $(VERSION) -b $(BUILD_NUM) - - @echo "2. Fetching Dart dependencies..." - $(FLUTTER) pub get - - @echo "3. Generating app config and building native crypto plugins..." - cd scripts && yes yes | BUILD_ISAR_FROM_SOURCE=0 \ - bash -c 'rustup() { echo "1.89.0-stable"; echo "1.85.1-stable"; return 0; }; export -f rustup; ./build_app.sh -a $(APP_NAME) -p macos -v $(VERSION) -b $(BUILD_NUM) -f' - - @echo "4. Building secp256k1 (coinlib)..." - $(FLUTTER) pub run coinlib:build_macos - - @echo "5. Compiling Flutter App..." - @chmod -R u+w macos/ - env -u CXXFLAGS -u CFLAGS -u LDFLAGS -u CPATH -u LIBRARY_PATH $(FLUTTER) build macos --release - - -# --- IOS --- - -build-ios: check-reqs check-macos-sdk init prebuild-unix ## Complete release build for iOS - @echo "1. Generating pubspec.yaml and building native crypto plugins..." - cd scripts && ./build_app.sh -a $(APP_NAME) -p ios -v $(VERSION) -b $(BUILD_NUM) -f - @echo "2. Fetching Dart dependencies..." - $(FLUTTER) pub get - @echo "3. Compiling Flutter App..." - $(FLUTTER) build ios --release --no-codesign - -# --- ANDROID --- - -build-android: check-reqs init prebuild-unix ## Complete release build for Android (APK) - @echo "1. Generating pubspec.yaml and building native crypto plugins..." - cd scripts && ./build_app.sh -a $(APP_NAME) -p android -v $(VERSION) -b $(BUILD_NUM) -f - @echo "2. Fetching Dart dependencies..." - $(FLUTTER) pub get - @echo "3. Compiling Flutter App..." - $(FLUTTER) build apk --release - -# --- WINDOWS --- - -build-windows: check-reqs check-reqs-windows init prebuild-windows ## Complete release build for Windows - @echo "1. Generating pubspec.yaml and building native plugins in WSL..." - wsl bash -c "cd scripts && ./build_app.sh -a $(APP_NAME) -p windows -v $(VERSION) -b $(BUILD_NUM) -f" - @echo "2. Fetching Dart dependencies natively..." - $(FLUTTER) pub get - @echo "3. Building secp256k1 natively..." - $(DART) run coinlib:build_windows - @echo "4. Building frostdart natively..." - cd crypto_plugins/frostdart && build_all.bat - @echo "5. Compiling Flutter App..." - $(FLUTTER) build windows --release + @find crypto_plugins -name "build_all.sh" -exec sed -i.bak 's|/\$${OS}_VERSION/c\\.*|s\|/\\\*\$${OSX}_VERSION\\\*/.*\|/\\\*\$${OSX}_VERSION\\\*/ const \$${OSX}_VERSION = \\"$$COMMIT\\";\|g|g' {} \; 2>/dev/null || true + @find crypto_plugins/frostdart -name "build_*.dart" -type f -exec sed -i.bak 's/\["-i", ".bak",/\["-i.bak",/g' {} + 2>/dev/null || true + @echo "Fixing Epic Cash header logic..." + @sed -i.bak 's|cp target/epic_cash_wallet.h libepic_cash_wallet.h|mkdir -p target \&\& touch target/epic_cash_wallet.h \&\& cp target/epic_cash_wallet.h libepic_cash_wallet.h|g' crypto_plugins/flutter_libepiccash/scripts/macos/build_all.sh 2>/dev/null || true + @sed -i.bak 's|cbindgen --config cbindgen.toml --crate epic-cash-wallet --output target/epic_cash_wallet.h|cbindgen --config cbindgen.toml --crate epic-cash-wallet --output target/epic_cash_wallet.h \&\& cp target/epic_cash_wallet.h libepic_cash_wallet.h|g' crypto_plugins/flutter_libepiccash/scripts/macos/build_all.sh 2>/dev/null || true + @echo "Fixing Frostdart binary path..." + @find crypto_plugins/frostdart/scripts -name "build_all.sh" -exec sed -i.bak "s|.*dart build_|$(shell which dart) build_|g" {} + 2>/dev/null || true + @echo "Disabling strict Rust checks..." + @find crypto_plugins scripts -type f -name "rust_version.sh" -exec sed -i.bak 's/exit 1/echo "Bypassed by Nix"/g' {} + 2>/dev/null || true + @find crypto_plugins -name "*.bak" -delete 2>/dev/null || true + @echo "[OK] Submodules patched." + +# --- PLATFORM BUILDS --- + +build-macos: ## Build MacOS Release (Self-healing) + @echo "--- Sanitizing environment..." + @sed -i 's/xelis_dart_sdk: 0.30.9/xelis_dart_sdk:/g' scripts/app_config/templates/pubspec.template.yaml 2>/dev/null || true + @sed -i 's/\xc2\xa0/ /g' scripts/app_config/templates/pubspec.template.yaml 2>/dev/null || true + @chmod -R u+w . 2>/dev/null || true + @rm -rf build/secp256k1 macos/Runner.xcworkspace crypto_plugins/*/scripts/macos/build + @echo "--- Configuring project..." + @./scripts/app_config/configure_stack_wallet.sh macos + @./scripts/app_config/shared/update_version.sh -v $(VERSION) -b $(BUILD_NUM) + @echo "--- Restoring metadata..." + @$(FLUTTER) create --platforms=macos . > /dev/null + @# Nix-provided Flutter templates can be copied as read-only; CocoaPods must rewrite these files. + @chmod -R u+w macos/Runner.xcworkspace macos/Runner.xcodeproj macos/Flutter 2>/dev/null || true + @# Keep app target deployment aligned with plugin minimums (e.g. camera_macos >= 11.0). + @sed -i.bak -e "s/MACOSX_DEPLOYMENT_TARGET = 10\\.15;/MACOSX_DEPLOYMENT_TARGET = 11.0;/g" macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true + @rm -f macos/Runner.xcodeproj/project.pbxproj.bak + @$(FLUTTER) pub get + @# Ensure generated build settings are single-line key/value entries for CocoaPods xcconfig parser. + @[ -f macos/Flutter/ephemeral/Flutter-Generated.xcconfig ] && \ + sed -i.bak -E 's/[[:space:]]+$$//' macos/Flutter/ephemeral/Flutter-Generated.xcconfig && \ + rm -f macos/Flutter/ephemeral/Flutter-Generated.xcconfig.bak || true + @echo "--- Building native dependencies..." + @rm -rf build/secp256k1 + @$(FLUTTER) pub run coinlib:build_macos + @echo "--- Patching Podfile..." + @sed -i.bak -e "s/platform :osx, '10.11'/platform :osx, '11.0'/g" -e "s/platform :osx, '10.15'/platform :osx, '11.0'/g" macos/Podfile 2>/dev/null || true + @rm -f macos/Podfile.bak + @echo "--- Final Compilation..." + @rm -rf macos/Pods macos/Podfile.lock + @env \ + -u LD -u LDFLAGS -u NIX_LDFLAGS -u NIX_CFLAGS_LINK \ + -u CFLAGS -u CXXFLAGS -u CPPFLAGS \ + -u SDKROOT -u BINDGEN_EXTRA_CLANG_ARGS \ + -u IPHONEOS_DEPLOYMENT_TARGET -u TVOS_DEPLOYMENT_TARGET -u WATCHOS_DEPLOYMENT_TARGET \ + -u XROS_DEPLOYMENT_TARGET -u XR_DEPLOYMENT_TARGET \ + MACOSX_DEPLOYMENT_TARGET=11.0 \ + $(FLUTTER) build macos --release + +build-ios: check-reqs check-macos-sdk init ## Build iOS Release + @echo "--- Configuring project..." + @cd scripts && ./build_app.sh -a $(APP_NAME) -p ios -v $(VERSION) -b $(BUILD_NUM) -f + @echo "--- Building app..." + @$(FLUTTER) pub get + @$(FLUTTER) build ios --release --no-codesign + +build-linux: check-reqs init patch-submodules ## Build Linux Release + @echo "--- Generating config..." + @if [ -z "$(PROTOC_PATH)" ]; then echo "[ERROR] protoc not found!"; exit 1; fi + @cd scripts && yes yes | BUILD_ISAR_FROM_SOURCE=0 PROTOC="$(PROTOC_PATH)" ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f + @echo "--- Building app..." + @$(FLUTTER) pub get + @$(FLUTTER) pub run coinlib:build_linux + @$(FLUTTER) build linux --release + +build-android: check-reqs init ## Build Android APK + @echo "--- Configuring project..." + @cd scripts && ./build_app.sh -a $(APP_NAME) -p android -v $(VERSION) -b $(BUILD_NUM) -f + @echo "--- Building app..." + @$(FLUTTER) pub get + @$(FLUTTER) build apk --release + +build-windows: check-reqs check-reqs-windows init ## Build Windows Release + @echo "--- Building native plugins in WSL..." + @wsl bash -c "cd scripts && ./build_app.sh -a $(APP_NAME) -p windows -v $(VERSION) -b $(BUILD_NUM) -f" + @echo "--- Building native dependencies..." + @$(FLUTTER) pub get + @$(DART) run coinlib:build_windows + @cd crypto_plugins/frostdart && build_all.bat + @echo "--- Compiling app..." + @$(FLUTTER) build windows --release diff --git a/flake.lock b/flake.lock new file mode 100644 index 000000000..1f675e1ee --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1773646010, + "narHash": "sha256-iYrs97hS7p5u4lQzuNWzuALGIOdkPXvjz7bviiBjUu8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "5b2c2d84341b2afb5647081c1386a80d7a8d8605", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix index c2fcb8913..971700345 100644 --- a/flake.nix +++ b/flake.nix @@ -59,7 +59,7 @@ # ========================================== if ! rustup toolchain list | grep -q "1.89.0"; then echo "Initializing Rust toolchains (this happens only once)..." - rustup install 1.89.0 1.85.1 1.81.0 + rustup install 1.89.0 1.85.1 1.81.0 stable rustup default 1.89.0 if [[ "${system}" == *"darwin"* ]]; then @@ -89,24 +89,53 @@ ${lib.optionalString pkgs.stdenv.isDarwin '' export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer" export SDKROOT=$(xcrun --sdk macosx --show-sdk-path) + export MACOSX_DEPLOYMENT_TARGET="11.0" - #unset CPATH - #export CPATH="$SDKROOT/usr/include" - #export LIBRARY_PATH="$SDKROOT/usr/lib" - #export CXXFLAGS="-isysroot $SDKROOT -I$SDKROOT/usr/include/c++/v1" - #export CFLAGS="-isysroot $SDKROOT" - #export LDFLAGS="-isysroot $SDKROOT" - export BINDGEN_EXTRA_CLANG_ARGS="-isysroot $SDKROOT" + # --- NIX C++ COMPILER OVERRIDE --- + export CC=/usr/bin/clang + export CXX=/usr/bin/clang++ + export AR=/usr/bin/ar + export AS=/usr/bin/as + export NM=/usr/bin/nm + export RANLIB=/usr/bin/ranlib + export STRIP=/usr/bin/strip + export BINDGEN_EXTRA_CLANG_ARGS="-isysroot $SDKROOT" + mkdir -p .nix-bin ln -sf /usr/bin/xcodebuild .nix-bin/xcodebuild - ln -sf /usr/bin/xcrun .nix-bin/xcrun - ln -sf /usr/bin/lipo .nix-bin/lipo ln -sf /usr/bin/clang .nix-bin/clang ln -sf /usr/bin/clang++ .nix-bin/clang++ - + + # SMART LIPO & XCRUN WRAPPER + rm -f .nix-bin/lipo .nix-bin/xcrun + + echo '#!/bin/bash' > .nix-bin/lipo + echo 'for arg in "$@"; do' >> .nix-bin/lipo + echo ' if [[ "$arg" == *"FlutterMacOS.framework"* ]]; then' >> .nix-bin/lipo + echo ' chmod -R u+w "$(dirname "$arg")" 2>/dev/null || true' >> .nix-bin/lipo + echo ' fi' >> .nix-bin/lipo + echo 'done' >> .nix-bin/lipo + echo 'exec /usr/bin/lipo "$@"' >> .nix-bin/lipo + chmod +x .nix-bin/lipo + + echo '#!/bin/bash' > .nix-bin/xcrun + echo 'if [ "$1" = "-f" ] && [ "$2" = "lipo" ]; then' >> .nix-bin/xcrun + echo ' echo "'$PWD'/.nix-bin/lipo"' >> .nix-bin/xcrun + echo ' exit 0' >> .nix-bin/xcrun + echo 'fi' >> .nix-bin/xcrun + echo "" >> .nix-bin/xcrun + echo '# Keep xcrun tool invocations pinned to macOS deployment context.' >> .nix-bin/xcrun + echo 'unset IPHONEOS_DEPLOYMENT_TARGET TVOS_DEPLOYMENT_TARGET WATCHOS_DEPLOYMENT_TARGET' >> .nix-bin/xcrun + echo 'unset XROS_DEPLOYMENT_TARGET XR_DEPLOYMENT_TARGET VISIONOS_DEPLOYMENT_TARGET DRIVERKIT_DEPLOYMENT_TARGET' >> .nix-bin/xcrun + echo 'export MACOSX_DEPLOYMENT_TARGET="''${MACOSX_DEPLOYMENT_TARGET:-11.0}"' >> .nix-bin/xcrun + echo 'export SDKROOT="''${SDKROOT:-$(/usr/bin/xcrun --sdk macosx --show-sdk-path)}"' >> .nix-bin/xcrun + echo 'exec /usr/bin/xcrun "$@"' >> .nix-bin/xcrun + chmod +x .nix-bin/xcrun + export PATH="$PWD/.nix-bin:$PATH" ''} + ''; }; } diff --git a/macos/Podfile b/macos/Podfile index 3936acf0c..de1395f9f 100644 --- a/macos/Podfile +++ b/macos/Podfile @@ -1,4 +1,4 @@ -platform :osx, '10.15' +platform :osx, '11.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -40,6 +40,7 @@ post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_macos_build_settings(target) target.build_configurations.each do |config| + config.build_settings['MACOSX_DEPLOYMENT_TARGET'] = '11.0' config.build_settings['ARCHS'] = 'arm64' config.build_settings['VALID_ARCHS'] = 'arm64' end From 52ce8069e4855c8448e4dd31a3ca03c6ff8020e5 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Mon, 11 May 2026 22:30:26 -0500 Subject: [PATCH 020/118] fixing env bash calls for nixos Co-authored-by: sneurlax --- scripts/linux/build_secp256k1.sh | 3 ++- scripts/linux/build_secure_storage_deps.sh | 2 +- scripts/windows/build_secp256k1_wsl.sh | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/linux/build_secp256k1.sh b/scripts/linux/build_secp256k1.sh index e139cc937..19850db78 100755 --- a/scripts/linux/build_secp256k1.sh +++ b/scripts/linux/build_secp256k1.sh @@ -11,4 +11,5 @@ cmake .. cmake --build . mkdir -p ../../../../../build cp lib/libsecp256k1.so.2.*.* "../../../../../build/libsecp256k1.so" -cd ../../../ \ No newline at end of file +cd ../../../ +#!/usr/bin/env bash diff --git a/scripts/linux/build_secure_storage_deps.sh b/scripts/linux/build_secure_storage_deps.sh index 145b34718..4cc62e7d2 100755 --- a/scripts/linux/build_secure_storage_deps.sh +++ b/scripts/linux/build_secure_storage_deps.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if [ "${USE_SYSTEM_SECURE_STORAGE_DEPS:-0}" = "1" ]; then echo "USE_SYSTEM_SECURE_STORAGE_DEPS is set; skipping build of jsoncpp and libsecret (using system packages)" diff --git a/scripts/windows/build_secp256k1_wsl.sh b/scripts/windows/build_secp256k1_wsl.sh index a39cd3bee..ff4e1653d 100644 --- a/scripts/windows/build_secp256k1_wsl.sh +++ b/scripts/windows/build_secp256k1_wsl.sh @@ -12,3 +12,4 @@ cmake --build . mkdir -p ../../../../../build cp bin/libsecp256k1-2.dll "../../../../../build/secp256k1.dll" cd ../../../ +#!/usr/bin/env bash From ed122ef32dec08c4293e640b1ec55c7ad1d342e3 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 09:48:00 +0100 Subject: [PATCH 021/118] macOS build split into phases --- Makefile | 68 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index fc1227705..757e3d493 100644 --- a/Makefile +++ b/Makefile @@ -8,9 +8,20 @@ VERSION ?= 2.1.0 BUILD_NUM ?= 210 FLUTTER ?= flutter DART ?= dart +APP_PROJECT_ROOT_DIR ?= $(CURDIR) PROTOC_PATH := $(shell which protoc 2>/dev/null) +MACOS_ENV_UNSET = -u LD -u LDFLAGS -u NIX_LDFLAGS -u NIX_CFLAGS_LINK \ + -u CFLAGS -u CXXFLAGS -u CPPFLAGS \ + -u SDKROOT -u BINDGEN_EXTRA_CLANG_ARGS \ + -u IPHONEOS_DEPLOYMENT_TARGET -u TVOS_DEPLOYMENT_TARGET -u WATCHOS_DEPLOYMENT_TARGET \ + -u XROS_DEPLOYMENT_TARGET -u XR_DEPLOYMENT_TARGET +MACOS_ENV_SET = MACOSX_DEPLOYMENT_TARGET=11.0 -.PHONY: help check-reqs check-reqs-windows check-macos-sdk init clean prebuild-unix prebuild-windows deps-linux patch-submodules build-linux build-macos build-ios build-android build-windows +export APP_PROJECT_ROOT_DIR + +.PHONY: help check-reqs check-reqs-windows check-macos-sdk init clean prebuild-unix prebuild-windows deps-linux patch-submodules \ + build-linux build-macos build-ios build-android build-windows \ + macos-prepare macos-configure macos-restore-metadata macos-build-native macos-build-app diagnose-macos-env help: ## Show available commands @echo "Available targets:" @@ -22,7 +33,11 @@ check-reqs: ## Verify essential build tools @echo "Checking core prerequisites..." @command -v $(FLUTTER) >/dev/null 2>&1 || { echo >&2 "[ERROR] Flutter not installed."; exit 1; } @command -v $(DART) >/dev/null 2>&1 || { echo >&2 "[ERROR] Dart not installed."; exit 1; } - @command -v cargo >/dev/null 2>&1 || { echo >&2 "[ERROR] Rust not installed."; exit 1; } + @command -v rustup >/dev/null 2>&1 || { echo >&2 "[ERROR] rustup not installed."; exit 1; } + @rustup which rustc >/dev/null 2>&1 || { echo >&2 "[ERROR] rustc toolchain not available via rustup."; exit 1; } + @rustup which cargo >/dev/null 2>&1 || { echo >&2 "[ERROR] cargo toolchain not available via rustup."; exit 1; } + @rustup run stable rustc -vV >/dev/null 2>&1 || { echo >&2 "[ERROR] rustup stable toolchain not available."; exit 1; } + @command -v go >/dev/null 2>&1 || { echo >&2 "[ERROR] Go not installed."; exit 1; } @command -v cmake >/dev/null 2>&1 || { echo >&2 "[ERROR] CMake not installed."; exit 1; } @command -v pkg-config >/dev/null 2>&1 || { echo >&2 "[ERROR] pkg-config not installed."; exit 1; } @echo "[OK] All core CLI requirements found!" @@ -77,15 +92,21 @@ patch-submodules: ## Apply portability patches to submodules # --- PLATFORM BUILDS --- -build-macos: ## Build MacOS Release (Self-healing) +build-macos: macos-prepare macos-configure macos-restore-metadata macos-build-native macos-build-app ## Build MacOS Release (Self-healing) + +macos-prepare: @echo "--- Sanitizing environment..." @sed -i 's/xelis_dart_sdk: 0.30.9/xelis_dart_sdk:/g' scripts/app_config/templates/pubspec.template.yaml 2>/dev/null || true @sed -i 's/\xc2\xa0/ /g' scripts/app_config/templates/pubspec.template.yaml 2>/dev/null || true @chmod -R u+w . 2>/dev/null || true @rm -rf build/secp256k1 macos/Runner.xcworkspace crypto_plugins/*/scripts/macos/build + +macos-configure: @echo "--- Configuring project..." @./scripts/app_config/configure_stack_wallet.sh macos @./scripts/app_config/shared/update_version.sh -v $(VERSION) -b $(BUILD_NUM) + +macos-restore-metadata: @echo "--- Restoring metadata..." @$(FLUTTER) create --platforms=macos . > /dev/null @# Nix-provided Flutter templates can be copied as read-only; CocoaPods must rewrite these files. @@ -98,23 +119,48 @@ build-macos: ## Build MacOS Release (Self-healing) @[ -f macos/Flutter/ephemeral/Flutter-Generated.xcconfig ] && \ sed -i.bak -E 's/[[:space:]]+$$//' macos/Flutter/ephemeral/Flutter-Generated.xcconfig && \ rm -f macos/Flutter/ephemeral/Flutter-Generated.xcconfig.bak || true + +macos-build-native: @echo "--- Building native dependencies..." @rm -rf build/secp256k1 - @$(FLUTTER) pub run coinlib:build_macos + @$(DART) run coinlib:build_macos @echo "--- Patching Podfile..." @sed -i.bak -e "s/platform :osx, '10.11'/platform :osx, '11.0'/g" -e "s/platform :osx, '10.15'/platform :osx, '11.0'/g" macos/Podfile 2>/dev/null || true @rm -f macos/Podfile.bak + +macos-build-app: @echo "--- Final Compilation..." @rm -rf macos/Pods macos/Podfile.lock - @env \ - -u LD -u LDFLAGS -u NIX_LDFLAGS -u NIX_CFLAGS_LINK \ - -u CFLAGS -u CXXFLAGS -u CPPFLAGS \ - -u SDKROOT -u BINDGEN_EXTRA_CLANG_ARGS \ - -u IPHONEOS_DEPLOYMENT_TARGET -u TVOS_DEPLOYMENT_TARGET -u WATCHOS_DEPLOYMENT_TARGET \ - -u XROS_DEPLOYMENT_TARGET -u XR_DEPLOYMENT_TARGET \ - MACOSX_DEPLOYMENT_TARGET=11.0 \ + @env $(MACOS_ENV_UNSET) $(MACOS_ENV_SET) \ + RUSTUP_HOME="$$HOME/.rustup" \ + CARGO_HOME="$$HOME/.cargo" \ + RUSTUP_TOOLCHAIN=stable \ + PATH="$$(dirname "$$(/opt/homebrew/bin/rustup which rustc)"):/opt/homebrew/opt/rustup/bin:/opt/homebrew/bin:$$HOME/.cargo/bin:$$PATH" \ $(FLUTTER) build macos --release +diagnose-macos-env: ## Print macOS build env and tool resolution + @echo "--- Toolchain diagnostics ---" + @echo "flutter: $$(command -v $(FLUTTER) || echo missing)" + @echo "dart: $$(command -v $(DART) || echo missing)" + @echo "xcrun: $$(command -v xcrun || echo missing)" + @echo "clang: $$(command -v clang || echo missing)" + @echo "go: $$(command -v go || echo missing)" + @echo "rustup: $$(command -v rustup || echo missing)" + @echo "rustc: $$(command -v rustc || echo missing)" + @echo "cargo: $$(command -v cargo || echo missing)" + @echo "rustup rustc: $$(rustup which rustc 2>/dev/null || echo missing)" + @echo "rustup cargo: $$(rustup which cargo 2>/dev/null || echo missing)" + @echo "xcode-select: $$(xcode-select -p 2>/dev/null || echo missing)" + @echo "SDKROOT=$${SDKROOT:-}" + @echo "MACOSX_DEPLOYMENT_TARGET=$${MACOSX_DEPLOYMENT_TARGET:-}" + @echo "IPHONEOS_DEPLOYMENT_TARGET=$${IPHONEOS_DEPLOYMENT_TARGET:-}" + @echo "TVOS_DEPLOYMENT_TARGET=$${TVOS_DEPLOYMENT_TARGET:-}" + @echo "WATCHOS_DEPLOYMENT_TARGET=$${WATCHOS_DEPLOYMENT_TARGET:-}" + @echo "XROS_DEPLOYMENT_TARGET=$${XROS_DEPLOYMENT_TARGET:-}" + @echo "XR_DEPLOYMENT_TARGET=$${XR_DEPLOYMENT_TARGET:-}" + @echo "NIX_LDFLAGS=$${NIX_LDFLAGS:-}" + @echo "NIX_CFLAGS_LINK=$${NIX_CFLAGS_LINK:-}" + build-ios: check-reqs check-macos-sdk init ## Build iOS Release @echo "--- Configuring project..." @cd scripts && ./build_app.sh -a $(APP_NAME) -p ios -v $(VERSION) -b $(BUILD_NUM) -f From ebb3774010f3ebeff12384bcbbd5aaa16a96e7dd Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 09:48:55 +0100 Subject: [PATCH 022/118] NEW_APP_ID_SNAKE changed from com.cypherstack.stack_duo to com.cypherstack.stackduo (fixes invalid bundle-id chars) --- scripts/app_config/configure_stack_duo.sh | 4 ++-- scripts/app_config/configure_stack_wallet.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/app_config/configure_stack_duo.sh b/scripts/app_config/configure_stack_duo.sh index c410a1841..6edee2899 100755 --- a/scripts/app_config/configure_stack_duo.sh +++ b/scripts/app_config/configure_stack_duo.sh @@ -7,7 +7,7 @@ set -x -e export NEW_NAME="Stack Duo" export NEW_APP_ID="com.cypherstack.stackduo" export NEW_APP_ID_CAMEL="com.cypherstack.stackDuo" -export NEW_APP_ID_SNAKE="com.cypherstack.stack_duo" +export NEW_APP_ID_SNAKE="com.cypherstack.stackduo" export NEW_BASIC_NAME="stack_duo" NEW_PUBSPEC_NAME="stackduo" @@ -91,4 +91,4 @@ _swapDefaults = ( toFuzzyNet: "xmr", ); -EOF \ No newline at end of file +EOF diff --git a/scripts/app_config/configure_stack_wallet.sh b/scripts/app_config/configure_stack_wallet.sh index 2d83715d1..6c1939013 100755 --- a/scripts/app_config/configure_stack_wallet.sh +++ b/scripts/app_config/configure_stack_wallet.sh @@ -7,7 +7,7 @@ set -x -e export NEW_NAME="Stack Wallet" export NEW_APP_ID="com.cypherstack.stackwallet" export NEW_APP_ID_CAMEL="com.cypherstack.stackWallet" -export NEW_APP_ID_SNAKE="com.cypherstack.stack_wallet" +export NEW_APP_ID_SNAKE="com.cypherstack.stackwallet" export NEW_BASIC_NAME="stack_wallet" NEW_PUBSPEC_NAME="stackwallet" From 795a993f1f63a5cdcb0f5314cf894678cf68483a Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 09:50:06 +0100 Subject: [PATCH 023/118] adding direnv and macOS build tools install helper script --- .envrc | 98 ++++++++++++++++++++++++++++ scripts/install_macos_build_tools.sh | 57 ++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 .envrc create mode 100755 scripts/install_macos_build_tools.sh diff --git a/.envrc b/.envrc new file mode 100644 index 000000000..fddb462e1 --- /dev/null +++ b/.envrc @@ -0,0 +1,98 @@ +#!/usr/bin/env bash + +# ============================================================================== +# STACK WALLET AUTOMATIC ENV (direnv) +# ============================================================================== + +set -euo pipefail + +# 1. PATHS & BASICS +export APP_PROJECT_ROOT_DIR="$PWD" +PATH_add .direnv-bin +PATH_add "$HOME/.cargo/bin" +if [ -d "/opt/homebrew/opt/rustup/bin" ]; then + PATH_add /opt/homebrew/opt/rustup/bin +fi +if [ -f "$HOME/.cargo/env" ]; then + # shellcheck disable=SC1090 + source "$HOME/.cargo/env" +fi + +# 2. RUST TOOLCHAIN AUTOMATION +if command -v rustup >/dev/null 2>&1; then + REQUIRED_RUST=(1.89.0 1.85.1 1.81.0) + + for v in "${REQUIRED_RUST[@]}"; do + if ! rustup toolchain list | grep -q "$v"; then + echo "Installing missing Rust version: $v..." + rustup install "$v" + fi + done + + rustup default 1.89.0 + rustup target add aarch64-apple-darwin aarch64-apple-ios >/dev/null 2>&1 || true + + if ! command -v cbindgen >/dev/null 2>&1 || ! command -v cargo-lipo >/dev/null 2>&1; then + echo "Installing Cargo tools (cbindgen, cargo-ndk, cargo-lipo)..." + cargo install cargo-ndk cbindgen cargo-lipo + fi +else + echo "ERROR: rustup not found. Install rustup first." +fi + +# 3. MACOS SDK & COMPILER OVERRIDES +export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer" +export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)" +export MACOSX_DEPLOYMENT_TARGET="11.0" + +export CC=/usr/bin/clang +export CXX=/usr/bin/clang++ +export AR=/usr/bin/ar +export AS=/usr/bin/as +export NM=/usr/bin/nm +export RANLIB=/usr/bin/ranlib +export STRIP=/usr/bin/strip +export BINDGEN_EXTRA_CLANG_ARGS="-isysroot $SDKROOT" + +# 4. PYTHON VIRTUAL ENV +if [ ! -d ".venv" ]; then + echo "Creating Python venv and installing dependencies..." + python3 -m venv .venv + source .venv/bin/activate + pip install toml tomli jinja2 markdown markupsafe pygments typogrify +else + source .venv/bin/activate +fi + +# 5. XCODE TOOL WRAPPERS +mkdir -p .direnv-bin + +cat > .direnv-bin/lipo <<'EOF' +#!/usr/bin/env bash +for arg in "$@"; do + if [[ "$arg" == *"FlutterMacOS.framework"* ]]; then + chmod -R u+w "$(dirname "$arg")" 2>/dev/null || true + fi +done +exec /usr/bin/lipo "$@" +EOF +chmod +x .direnv-bin/lipo + +cat > .direnv-bin/xcrun <<'EOF' +#!/usr/bin/env bash +if [ "$1" = "-f" ] && [ "$2" = "lipo" ]; then + echo "$PWD/.direnv-bin/lipo" + exit 0 +fi + +# Keep xcrun tool invocations pinned to macOS deployment context. +unset IPHONEOS_DEPLOYMENT_TARGET TVOS_DEPLOYMENT_TARGET WATCHOS_DEPLOYMENT_TARGET +unset XROS_DEPLOYMENT_TARGET XR_DEPLOYMENT_TARGET VISIONOS_DEPLOYMENT_TARGET DRIVERKIT_DEPLOYMENT_TARGET +export MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-11.0}" +export SDKROOT="${SDKROOT:-$(/usr/bin/xcrun --sdk macosx --show-sdk-path)}" + +exec /usr/bin/xcrun "$@" +EOF +chmod +x .direnv-bin/xcrun + +echo "Stack Wallet direnv environment loaded." diff --git a/scripts/install_macos_build_tools.sh b/scripts/install_macos_build_tools.sh new file mode 100755 index 000000000..25177e3cc --- /dev/null +++ b/scripts/install_macos_build_tools.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [[ "$(uname -s)" != "Darwin" ]]; then + echo "This installer is for macOS only." + exit 1 +fi + +if ! command -v brew >/dev/null 2>&1; then + echo "Homebrew is required. Install it first: https://brew.sh" + exit 1 +fi + +echo "Installing Homebrew packages..." +brew install direnv rustup-init cmake ninja pkg-config gnu-sed cocoapods go + +echo "Installing Flutter cask..." +brew install --cask flutter + +if ! command -v rustup >/dev/null 2>&1; then + echo "Initializing Rust toolchain..." + rustup-init -y +fi + +if [[ -f "$HOME/.cargo/env" ]]; then + # shellcheck disable=SC1090 + source "$HOME/.cargo/env" +fi + +echo "Ensuring Rust toolchains are installed..." +rustup toolchain install stable +rustup default stable +rustup toolchain install 1.89.0 1.85.1 1.81.0 +rustup default 1.89.0 +rustup target add aarch64-apple-darwin aarch64-apple-ios >/dev/null 2>&1 || true + +echo "Verifying toolchain..." +if command -v flutter >/dev/null 2>&1; then + flutter --version +else + echo "flutter not found in PATH. Add Flutter bin to your shell profile." +fi + +if command -v dart >/dev/null 2>&1; then + dart --version +else + echo "dart not found in PATH. It should come with Flutter." +fi + +rustup --version +rustc --version +rustup run stable rustc --version +pod --version +go version + +echo "Done." From a0c85bd59457f4672af77a561c95400881c90543 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 09:52:05 +0100 Subject: [PATCH 024/118] Replaced exit 1 with echo 'Bypassed by Nix' in missing-toolchain branches --- scripts/rust_version.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/rust_version.sh b/scripts/rust_version.sh index 68c52d6b9..b48750952 100755 --- a/scripts/rust_version.sh +++ b/scripts/rust_version.sh @@ -6,7 +6,7 @@ set_rust_to_everything_else() { rustup default 1.89.0 else echo "Rust version 1.89.0 is not installed. Please install it using 'rustup install 1.89.0'." >&2 - exit 1 + echo "Bypassed by Nix" fi } @@ -15,7 +15,7 @@ set_rust_version_for_libepiccash() { rustup default 1.89.0 else echo "Rust version 1.89.0 is not installed. Please install it using 'rustup install 1.89.0'." >&2 - exit 1 + echo "Bypassed by Nix" fi } @@ -24,6 +24,6 @@ set_rust_version_for_libmwc() { rustup default 1.85.1 else echo "Rust version 1.85.1 is not installed. Please install it using 'rustup install 1.85.1'." >&2 - exit 1 + echo "Bypassed by Nix" fi } \ No newline at end of file From 3bf60c07cfefdb5e59383ccd553c6afffd802b37 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 10:03:47 +0100 Subject: [PATCH 025/118] fixing current repo path for APP_PROJECT_ROOT_DIR --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 757e3d493..8ac7adb29 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ VERSION ?= 2.1.0 BUILD_NUM ?= 210 FLUTTER ?= flutter DART ?= dart -APP_PROJECT_ROOT_DIR ?= $(CURDIR) +APP_PROJECT_ROOT_DIR := $(CURDIR) PROTOC_PATH := $(shell which protoc 2>/dev/null) MACOS_ENV_UNSET = -u LD -u LDFLAGS -u NIX_LDFLAGS -u NIX_CFLAGS_LINK \ -u CFLAGS -u CXXFLAGS -u CPPFLAGS \ From fa14da7304003e756f88f48c0cd5b338c61f93b5 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 10:06:29 +0100 Subject: [PATCH 026/118] scripts now compute project root from their own location --- scripts/app_config/configure_stack_duo.sh | 7 +++++++ scripts/app_config/configure_stack_wallet.sh | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/scripts/app_config/configure_stack_duo.sh b/scripts/app_config/configure_stack_duo.sh index 6edee2899..0b17b89b6 100755 --- a/scripts/app_config/configure_stack_duo.sh +++ b/scripts/app_config/configure_stack_duo.sh @@ -4,6 +4,13 @@ set -x -e # Configure files for Duo. +# Derive project root from script location when APP_PROJECT_ROOT_DIR is unset/stale. +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +ROOT_FROM_SCRIPT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)" +if [[ -z "${APP_PROJECT_ROOT_DIR:-}" || ! -f "${APP_PROJECT_ROOT_DIR}/pubspec.yaml" ]]; then + export APP_PROJECT_ROOT_DIR="${ROOT_FROM_SCRIPT}" +fi + export NEW_NAME="Stack Duo" export NEW_APP_ID="com.cypherstack.stackduo" export NEW_APP_ID_CAMEL="com.cypherstack.stackDuo" diff --git a/scripts/app_config/configure_stack_wallet.sh b/scripts/app_config/configure_stack_wallet.sh index 6c1939013..0a1663cd1 100755 --- a/scripts/app_config/configure_stack_wallet.sh +++ b/scripts/app_config/configure_stack_wallet.sh @@ -4,6 +4,13 @@ set -x -e # Configure files for Stack Wallet. +# Derive project root from script location when APP_PROJECT_ROOT_DIR is unset/stale. +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +ROOT_FROM_SCRIPT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)" +if [[ -z "${APP_PROJECT_ROOT_DIR:-}" || ! -f "${APP_PROJECT_ROOT_DIR}/pubspec.yaml" ]]; then + export APP_PROJECT_ROOT_DIR="${ROOT_FROM_SCRIPT}" +fi + export NEW_NAME="Stack Wallet" export NEW_APP_ID="com.cypherstack.stackwallet" export NEW_APP_ID_CAMEL="com.cypherstack.stackWallet" From 380874e8d8effb24530df02d0ee6b600499166d6 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 10:13:04 +0100 Subject: [PATCH 027/118] adding pubspec.yaml creation to macos-configure --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 8ac7adb29..e8c53b5e8 100644 --- a/Makefile +++ b/Makefile @@ -103,6 +103,10 @@ macos-prepare: macos-configure: @echo "--- Configuring project..." + @if [ ! -f pubspec.yaml ]; then \ + echo "--- pubspec.yaml missing; generating from template..."; \ + cp scripts/app_config/templates/pubspec.template.yaml pubspec.yaml; \ + fi @./scripts/app_config/configure_stack_wallet.sh macos @./scripts/app_config/shared/update_version.sh -v $(VERSION) -b $(BUILD_NUM) From 0ca3fb178ad0282fcc3cd3d407d50103def69916 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 10:15:49 +0100 Subject: [PATCH 028/118] git submodule update --init --recursive for macos-configure --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index e8c53b5e8..4680f7f54 100644 --- a/Makefile +++ b/Makefile @@ -103,6 +103,8 @@ macos-prepare: macos-configure: @echo "--- Configuring project..." + @echo "--- Initializing submodules..." + @git submodule update --init --recursive @if [ ! -f pubspec.yaml ]; then \ echo "--- pubspec.yaml missing; generating from template..."; \ cp scripts/app_config/templates/pubspec.template.yaml pubspec.yaml; \ From 6abc46c29aef95c3f0c2d659dd53240292d93729 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 10:19:47 +0100 Subject: [PATCH 029/118] fixing xelis_dart_sdk version bug --- Makefile | 1 - scripts/app_config/templates/pubspec.template.yaml | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 4680f7f54..9631aa4cf 100644 --- a/Makefile +++ b/Makefile @@ -96,7 +96,6 @@ build-macos: macos-prepare macos-configure macos-restore-metadata macos-build-na macos-prepare: @echo "--- Sanitizing environment..." - @sed -i 's/xelis_dart_sdk: 0.30.9/xelis_dart_sdk:/g' scripts/app_config/templates/pubspec.template.yaml 2>/dev/null || true @sed -i 's/\xc2\xa0/ /g' scripts/app_config/templates/pubspec.template.yaml 2>/dev/null || true @chmod -R u+w . 2>/dev/null || true @rm -rf build/secp256k1 macos/Runner.xcworkspace crypto_plugins/*/scripts/macos/build diff --git a/scripts/app_config/templates/pubspec.template.yaml b/scripts/app_config/templates/pubspec.template.yaml index 140001fe0..aee68c81b 100644 --- a/scripts/app_config/templates/pubspec.template.yaml +++ b/scripts/app_config/templates/pubspec.template.yaml @@ -31,9 +31,9 @@ dependencies: # %%ENABLE_XEL%% # xelis_dart_sdk: 0.30.9 -## git: -## url: https://github.com/xelis-project/xelis-dart-sdk.git -## ref: f1da98f8bad8b9ad3645661a23f9efb83e44b0c9 +# git: +# url: https://github.com/xelis-project/xelis-dart-sdk.git +# ref: f1da98f8bad8b9ad3645661a23f9efb83e44b0c9 # xelis_flutter: # git: # url: https://github.com/xelis-project/xelis-flutter-ffi.git From a3b3022c5e262bf26a276ae1d0fd319d20a7a996 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 10:21:18 +0100 Subject: [PATCH 030/118] fixing wrong formatting of xelis_dart_sdk yaml --- scripts/app_config/templates/pubspec.template.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/app_config/templates/pubspec.template.yaml b/scripts/app_config/templates/pubspec.template.yaml index aee68c81b..2e7212191 100644 --- a/scripts/app_config/templates/pubspec.template.yaml +++ b/scripts/app_config/templates/pubspec.template.yaml @@ -31,9 +31,6 @@ dependencies: # %%ENABLE_XEL%% # xelis_dart_sdk: 0.30.9 -# git: -# url: https://github.com/xelis-project/xelis-dart-sdk.git -# ref: f1da98f8bad8b9ad3645661a23f9efb83e44b0c9 # xelis_flutter: # git: # url: https://github.com/xelis-project/xelis-flutter-ffi.git From ea0054257b63b177d637abc0443bc26906373ec0 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 10:26:14 +0100 Subject: [PATCH 031/118] fix(macos): bootstrap missing local build files in macos-configure --- Makefile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Makefile b/Makefile index 9631aa4cf..8dfdc3f82 100644 --- a/Makefile +++ b/Makefile @@ -104,6 +104,16 @@ macos-configure: @echo "--- Configuring project..." @echo "--- Initializing submodules..." @git submodule update --init --recursive + @echo "--- Bootstrapping local config files..." + @bash scripts/prebuild.sh + @if [ ! -f crypto_plugins/flutter_libepiccash/lib/git_versions.dart ] && [ -f crypto_plugins/flutter_libepiccash/lib/git_versions_example.dart ]; then \ + echo "--- Creating flutter_libepiccash git_versions.dart from example..."; \ + cp crypto_plugins/flutter_libepiccash/lib/git_versions_example.dart crypto_plugins/flutter_libepiccash/lib/git_versions.dart; \ + fi + @if [ ! -f crypto_plugins/flutter_libmwc/lib/git_versions.dart ] && [ -f crypto_plugins/flutter_libmwc/lib/git_versions_example.dart ]; then \ + echo "--- Creating flutter_libmwc git_versions.dart from example..."; \ + cp crypto_plugins/flutter_libmwc/lib/git_versions_example.dart crypto_plugins/flutter_libmwc/lib/git_versions.dart; \ + fi @if [ ! -f pubspec.yaml ]; then \ echo "--- pubspec.yaml missing; generating from template..."; \ cp scripts/app_config/templates/pubspec.template.yaml pubspec.yaml; \ From 8e6f95378faf2a9097b52f1369f4e33dae076644 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 10:27:28 +0100 Subject: [PATCH 032/118] fix(macos): run prebuild.sh from scripts directory --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8dfdc3f82..3ab031437 100644 --- a/Makefile +++ b/Makefile @@ -105,7 +105,7 @@ macos-configure: @echo "--- Initializing submodules..." @git submodule update --init --recursive @echo "--- Bootstrapping local config files..." - @bash scripts/prebuild.sh + @cd scripts && bash prebuild.sh @if [ ! -f crypto_plugins/flutter_libepiccash/lib/git_versions.dart ] && [ -f crypto_plugins/flutter_libepiccash/lib/git_versions_example.dart ]; then \ echo "--- Creating flutter_libepiccash git_versions.dart from example..."; \ cp crypto_plugins/flutter_libepiccash/lib/git_versions_example.dart crypto_plugins/flutter_libepiccash/lib/git_versions.dart; \ From 58ac7e141fb35da8e09dc49ef15be0b08c307e04 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 10:35:03 +0100 Subject: [PATCH 033/118] asset prep --- scripts/app_config/configure_stack_duo.sh | 9 +++++++++ scripts/app_config/configure_stack_wallet.sh | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/scripts/app_config/configure_stack_duo.sh b/scripts/app_config/configure_stack_duo.sh index 0b17b89b6..11d863ac0 100755 --- a/scripts/app_config/configure_stack_duo.sh +++ b/scripts/app_config/configure_stack_duo.sh @@ -20,6 +20,12 @@ export NEW_BASIC_NAME="stack_duo" NEW_PUBSPEC_NAME="stackduo" PUBSPEC_FILE="${APP_PROJECT_ROOT_DIR}/pubspec.yaml" +if [[ ! -f "${PUBSPEC_FILE}" ]]; then + echo "Error: pubspec.yaml not found at ${PUBSPEC_FILE}" >&2 + echo "Run from repo root and restore it with: git checkout -- pubspec.yaml" >&2 + exit 1 +fi + # String replacements. if [[ "$(uname)" == 'Darwin' ]]; then # macos specific sed @@ -30,6 +36,9 @@ else sed -i "s/description: PLACEHOLDER/description: ${NEW_NAME}/g" "${PUBSPEC_FILE}" fi +# Ensure app assets are linked for this flavor/platform. +"${APP_PROJECT_ROOT_DIR}/scripts/app_config/shared/link_assets.sh" "${NEW_BASIC_NAME}" "$1" + dart "${APP_PROJECT_ROOT_DIR}/tool/process_pubspec_deps.dart" \ "${PUBSPEC_FILE}" \ XMR \ diff --git a/scripts/app_config/configure_stack_wallet.sh b/scripts/app_config/configure_stack_wallet.sh index 0a1663cd1..f74068a0f 100755 --- a/scripts/app_config/configure_stack_wallet.sh +++ b/scripts/app_config/configure_stack_wallet.sh @@ -20,6 +20,12 @@ export NEW_BASIC_NAME="stack_wallet" NEW_PUBSPEC_NAME="stackwallet" PUBSPEC_FILE="${APP_PROJECT_ROOT_DIR}/pubspec.yaml" +if [[ ! -f "${PUBSPEC_FILE}" ]]; then + echo "Error: pubspec.yaml not found at ${PUBSPEC_FILE}" >&2 + echo "Run from repo root and restore it with: git checkout -- pubspec.yaml" >&2 + exit 1 +fi + # ========================================== # FIX: Cross-Platform sed (macOS, Linux, Nix) # ========================================== @@ -27,6 +33,9 @@ sed -i.bak "s/name: PLACEHOLDER/name: ${NEW_PUBSPEC_NAME}/g" "${PUBSPEC_FILE}" sed -i.bak "s/description: PLACEHOLDER/description: ${NEW_NAME}/g" "${PUBSPEC_FILE}" rm -f "${PUBSPEC_FILE}.bak" +# Ensure app assets are linked for this flavor/platform. +"${APP_PROJECT_ROOT_DIR}/scripts/app_config/shared/link_assets.sh" "${NEW_BASIC_NAME}" "$1" + dart "${APP_PROJECT_ROOT_DIR}/tool/process_pubspec_deps.dart" \ "${PUBSPEC_FILE}" \ MWC \ From 322fafaf4504d29e1ef6f80851a2fdeba996709d Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 10:59:46 +0100 Subject: [PATCH 034/118] fix(macos): correct Pods xcconfig include paths for Flutter macOS configs --- Makefile | 4 ++++ macos/Flutter/Flutter-Debug.xcconfig | 2 +- macos/Flutter/Flutter-Release.xcconfig | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3ab031437..1af779d70 100644 --- a/Makefile +++ b/Makefile @@ -126,6 +126,10 @@ macos-restore-metadata: @$(FLUTTER) create --platforms=macos . > /dev/null @# Nix-provided Flutter templates can be copied as read-only; CocoaPods must rewrite these files. @chmod -R u+w macos/Runner.xcworkspace macos/Runner.xcodeproj macos/Flutter 2>/dev/null || true + @# Ensure Pods includes are resolved relative to macos/Flutter/*.xcconfig. + @sed -i.bak -e 's|#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner\.debug\.xcconfig"|#include? "../Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"|g' macos/Flutter/Flutter-Debug.xcconfig 2>/dev/null || true + @sed -i.bak -e 's|#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner\.release\.xcconfig"|#include? "../Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"|g' macos/Flutter/Flutter-Release.xcconfig 2>/dev/null || true + @rm -f macos/Flutter/Flutter-Debug.xcconfig.bak macos/Flutter/Flutter-Release.xcconfig.bak @# Keep app target deployment aligned with plugin minimums (e.g. camera_macos >= 11.0). @sed -i.bak -e "s/MACOSX_DEPLOYMENT_TARGET = 10\\.15;/MACOSX_DEPLOYMENT_TARGET = 11.0;/g" macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true @rm -f macos/Runner.xcodeproj/project.pbxproj.bak diff --git a/macos/Flutter/Flutter-Debug.xcconfig b/macos/Flutter/Flutter-Debug.xcconfig index 4b81f9b2d..b8eb5550c 100644 --- a/macos/Flutter/Flutter-Debug.xcconfig +++ b/macos/Flutter/Flutter-Debug.xcconfig @@ -1,2 +1,2 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include? "../Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/Flutter-Release.xcconfig b/macos/Flutter/Flutter-Release.xcconfig index 5caa9d157..575a9767c 100644 --- a/macos/Flutter/Flutter-Release.xcconfig +++ b/macos/Flutter/Flutter-Release.xcconfig @@ -1,2 +1,2 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include? "../Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" From 92dc48d644a431b58b4f9120704bdacb0dcdb0a4 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 11:10:33 +0100 Subject: [PATCH 035/118] fix(macos): use Debug/Release xcconfigs for Runner target to restore CocoaPods plugin modules --- Makefile | 4 ++++ .../templates/macos/Runner.xcodeproj/project.pbxproj | 7 +++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 1af779d70..59089645f 100644 --- a/Makefile +++ b/Makefile @@ -132,6 +132,10 @@ macos-restore-metadata: @rm -f macos/Flutter/Flutter-Debug.xcconfig.bak macos/Flutter/Flutter-Release.xcconfig.bak @# Keep app target deployment aligned with plugin minimums (e.g. camera_macos >= 11.0). @sed -i.bak -e "s/MACOSX_DEPLOYMENT_TARGET = 10\\.15;/MACOSX_DEPLOYMENT_TARGET = 11.0;/g" macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true + @# Runner target configs must inherit Debug/Release xcconfigs (not AppInfo) so Pods module paths are available. + @perl -0777 -i.bak -pe 's/(33CC10FC2044A3C60003C045 \/\* Debug \*\/ = \{\s*isa = XCBuildConfiguration;\s*)baseConfigurationReference = 33E5194F232828860026EE4D \/\* AppInfo\.xcconfig \*\//$${1}baseConfigurationReference = 9740EEB21CF90195004384FC \/\* Debug.xcconfig \*\//s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true + @perl -0777 -i.bak -pe 's/(33CC10FD2044A3C60003C045 \/\* Release \*\/ = \{\s*isa = XCBuildConfiguration;\s*)baseConfigurationReference = 33E5194F232828860026EE4D \/\* AppInfo\.xcconfig \*\//$${1}baseConfigurationReference = 7AFA3C8E1D35360C0083082E \/\* Release.xcconfig \*\//s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true + @perl -0777 -i.bak -pe 's/(338D0CEA231458BD00FA5F75 \/\* Profile \*\/ = \{\s*isa = XCBuildConfiguration;\s*)baseConfigurationReference = 33E5194F232828860026EE4D \/\* AppInfo\.xcconfig \*\//$${1}baseConfigurationReference = 7AFA3C8E1D35360C0083082E \/\* Release.xcconfig \*\//s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true @rm -f macos/Runner.xcodeproj/project.pbxproj.bak @$(FLUTTER) pub get @# Ensure generated build settings are single-line key/value entries for CocoaPods xcconfig parser. diff --git a/scripts/app_config/templates/macos/Runner.xcodeproj/project.pbxproj b/scripts/app_config/templates/macos/Runner.xcodeproj/project.pbxproj index d6cb54f86..25ad3b582 100644 --- a/scripts/app_config/templates/macos/Runner.xcodeproj/project.pbxproj +++ b/scripts/app_config/templates/macos/Runner.xcodeproj/project.pbxproj @@ -228,7 +228,6 @@ 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, 529691D83C3BADE14E2EAC03 /* [CP] Embed Pods Frameworks */, ); @@ -555,7 +554,7 @@ }; 338D0CEA231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; @@ -706,7 +705,7 @@ }; 33CC10FC2044A3C60003C045 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; @@ -748,7 +747,7 @@ }; 33CC10FD2044A3C60003C045 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; From b1f2ac8d5fc4ed165a58a28d0a2cd486367bf032 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 11:22:52 +0100 Subject: [PATCH 036/118] macos: rebuild native crypto plugins during build-macos --- Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Makefile b/Makefile index 59089645f..e0b1e8c45 100644 --- a/Makefile +++ b/Makefile @@ -145,6 +145,12 @@ macos-restore-metadata: macos-build-native: @echo "--- Building native dependencies..." + @env $(MACOS_ENV_UNSET) $(MACOS_ENV_SET) \ + RUSTUP_HOME="$$HOME/.rustup" \ + CARGO_HOME="$$HOME/.cargo" \ + RUSTUP_TOOLCHAIN=stable \ + PATH="$$(dirname "$$(/opt/homebrew/bin/rustup which rustc)"):/opt/homebrew/opt/rustup/bin:/opt/homebrew/bin:$$HOME/.cargo/bin:$$PATH" \ + bash scripts/macos/build_all.sh @rm -rf build/secp256k1 @$(DART) run coinlib:build_macos @echo "--- Patching Podfile..." From b1a423fd0e3012f9ae8f357c02612942e65ede20 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 11:26:48 +0100 Subject: [PATCH 037/118] macos: unify build path and add fresh-clone CI smoke build Co-authored-by: sneurlax --- .github/workflows/test.yaml | 23 +++++++++++++++++++++++ Makefile | 2 +- scripts/build_app.sh | 5 +++++ scripts/install_macos_build_tools.sh | 5 ++++- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 585e2d9a7..defb31451 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -81,3 +81,26 @@ jobs: with: token: ${{secrets.CODECOV_TOKEN}} file: coverage/lcov.info + + macos-fresh-build: + runs-on: macos-14 + steps: + - name: Prepare repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.38.1' + channel: 'stable' + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install macOS build dependencies + run: ./scripts/install_macos_build_tools.sh + + - name: Fresh clone smoke build (macOS) + run: make build-macos VERSION=0.0.1 BUILD_NUM=1 diff --git a/Makefile b/Makefile index e0b1e8c45..5c16a2c03 100644 --- a/Makefile +++ b/Makefile @@ -92,7 +92,7 @@ patch-submodules: ## Apply portability patches to submodules # --- PLATFORM BUILDS --- -build-macos: macos-prepare macos-configure macos-restore-metadata macos-build-native macos-build-app ## Build MacOS Release (Self-healing) +build-macos: check-reqs check-macos-sdk macos-prepare macos-configure macos-restore-metadata macos-build-native macos-build-app ## Build MacOS Release (Single source of truth) macos-prepare: @echo "--- Sanitizing environment..." diff --git a/scripts/build_app.sh b/scripts/build_app.sh index 893856e9e..b3b930f38 100755 --- a/scripts/build_app.sh +++ b/scripts/build_app.sh @@ -72,6 +72,11 @@ if [ -z "$APP_NAMED_ID" ]; then usage fi +# Keep macOS stack_wallet builds on the Makefile path so setup steps stay in one place. +if [ "$APP_BUILD_PLATFORM" = "macos" ] && [ "$APP_NAMED_ID" = "stack_wallet" ]; then + exec make -C "${APP_PROJECT_ROOT_DIR}" build-macos VERSION="${APP_VERSION_STRING}" BUILD_NUM="${APP_BUILD_NUMBER}" +fi + confirmDisclaimer set -x diff --git a/scripts/install_macos_build_tools.sh b/scripts/install_macos_build_tools.sh index 25177e3cc..09ffbcf30 100755 --- a/scripts/install_macos_build_tools.sh +++ b/scripts/install_macos_build_tools.sh @@ -13,7 +13,7 @@ if ! command -v brew >/dev/null 2>&1; then fi echo "Installing Homebrew packages..." -brew install direnv rustup-init cmake ninja pkg-config gnu-sed cocoapods go +brew install direnv rustup-init cmake ninja pkg-config gnu-sed cocoapods go protobuf echo "Installing Flutter cask..." brew install --cask flutter @@ -35,6 +35,9 @@ rustup toolchain install 1.89.0 1.85.1 1.81.0 rustup default 1.89.0 rustup target add aarch64-apple-darwin aarch64-apple-ios >/dev/null 2>&1 || true +echo "Installing Rust CLI build tools..." +cargo install cargo-lipo cbindgen || true + echo "Verifying toolchain..." if command -v flutter >/dev/null 2>&1; then flutter --version From 1f6d937161ddfa32cf645c209b642a655bcb77bf Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 11:35:41 +0100 Subject: [PATCH 038/118] macos: fix scripts/macos/build_all.sh path resolution when run from repo root --- scripts/macos/build_all.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/macos/build_all.sh b/scripts/macos/build_all.sh index 2012568b1..4c1691582 100755 --- a/scripts/macos/build_all.sh +++ b/scripts/macos/build_all.sh @@ -2,18 +2,19 @@ set -x -e +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd -- "${SCRIPT_DIR}/../.." && pwd)" # libepiccash requires old rust -source ../rust_version.sh +source "${SCRIPT_DIR}/../rust_version.sh" set_rust_version_for_libepiccash -(cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) +(cd "${ROOT_DIR}/crypto_plugins/flutter_libepiccash/scripts/macos" && ./build_all.sh ) set_rust_version_for_libmwc -(cd ../../crypto_plugins/flutter_libmwc/scripts/macos && ./build_all.sh ) +(cd "${ROOT_DIR}/crypto_plugins/flutter_libmwc/scripts/macos" && ./build_all.sh ) # set rust (back) to a more recent stable release after building epiccash set_rust_to_everything_else -(cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) +(cd "${ROOT_DIR}/crypto_plugins/frostdart/scripts/macos" && ./build_all.sh ) wait echo "Done building" - From 5eb09593618fcff066d5a67e4b2f69151fec9e19 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 11:41:17 +0100 Subject: [PATCH 039/118] macos: stop forcing stable rust toolchain for native plugin build --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5c16a2c03..d64505d3e 100644 --- a/Makefile +++ b/Makefile @@ -148,8 +148,7 @@ macos-build-native: @env $(MACOS_ENV_UNSET) $(MACOS_ENV_SET) \ RUSTUP_HOME="$$HOME/.rustup" \ CARGO_HOME="$$HOME/.cargo" \ - RUSTUP_TOOLCHAIN=stable \ - PATH="$$(dirname "$$(/opt/homebrew/bin/rustup which rustc)"):/opt/homebrew/opt/rustup/bin:/opt/homebrew/bin:$$HOME/.cargo/bin:$$PATH" \ + PATH="/opt/homebrew/opt/rustup/bin:/opt/homebrew/bin:$$HOME/.cargo/bin:$$PATH" \ bash scripts/macos/build_all.sh @rm -rf build/secp256k1 @$(DART) run coinlib:build_macos From 8e963a58e65c9b59dc003580ce8a6ee8dc4cb4de Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 11:54:13 +0100 Subject: [PATCH 040/118] macos: fix tor_ffi build by ensuring rust x86_64-apple-darwin target is installed --- Makefile | 2 ++ scripts/install_macos_build_tools.sh | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d64505d3e..3b1194287 100644 --- a/Makefile +++ b/Makefile @@ -98,6 +98,8 @@ macos-prepare: @echo "--- Sanitizing environment..." @sed -i 's/\xc2\xa0/ /g' scripts/app_config/templates/pubspec.template.yaml 2>/dev/null || true @chmod -R u+w . 2>/dev/null || true + @rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain stable >/dev/null 2>&1 || true + @rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain 1.85.1 >/dev/null 2>&1 || true @rm -rf build/secp256k1 macos/Runner.xcworkspace crypto_plugins/*/scripts/macos/build macos-configure: diff --git a/scripts/install_macos_build_tools.sh b/scripts/install_macos_build_tools.sh index 09ffbcf30..272339d84 100755 --- a/scripts/install_macos_build_tools.sh +++ b/scripts/install_macos_build_tools.sh @@ -33,7 +33,9 @@ rustup toolchain install stable rustup default stable rustup toolchain install 1.89.0 1.85.1 1.81.0 rustup default 1.89.0 -rustup target add aarch64-apple-darwin aarch64-apple-ios >/dev/null 2>&1 || true +rustup target add aarch64-apple-darwin x86_64-apple-darwin aarch64-apple-ios --toolchain stable >/dev/null 2>&1 || true +rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain 1.85.1 >/dev/null 2>&1 || true +rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain 1.89.0 >/dev/null 2>&1 || true echo "Installing Rust CLI build tools..." cargo install cargo-lipo cbindgen || true From ef4e68265d15f07c341c93cff81f519953ba826c Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 12:02:20 +0100 Subject: [PATCH 041/118] macos: patch flutter_libepiccash build script at runtime from main repo --- Makefile | 3 ++ .../flutter_libepiccash_macos_build_all.sh | 51 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 scripts/patches/flutter_libepiccash_macos_build_all.sh diff --git a/Makefile b/Makefile index 3b1194287..07acb5fc3 100644 --- a/Makefile +++ b/Makefile @@ -147,6 +147,9 @@ macos-restore-metadata: macos-build-native: @echo "--- Building native dependencies..." + @echo "--- Applying local patch for flutter_libepiccash macOS build script..." + @cp scripts/patches/flutter_libepiccash_macos_build_all.sh crypto_plugins/flutter_libepiccash/scripts/macos/build_all.sh + @chmod +x crypto_plugins/flutter_libepiccash/scripts/macos/build_all.sh @env $(MACOS_ENV_UNSET) $(MACOS_ENV_SET) \ RUSTUP_HOME="$$HOME/.rustup" \ CARGO_HOME="$$HOME/.cargo" \ diff --git a/scripts/patches/flutter_libepiccash_macos_build_all.sh b/scripts/patches/flutter_libepiccash_macos_build_all.sh new file mode 100644 index 000000000..b3d4a210f --- /dev/null +++ b/scripts/patches/flutter_libepiccash_macos_build_all.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -euo pipefail + +mkdir -p build +echo "$(git log -1 --pretty=format:%H) $(date)" >> build/git_commit_version.txt + +VERSIONS_FILE=../../lib/git_versions.dart +EXAMPLE_VERSIONS_FILE=../../lib/git_versions_example.dart +if [ ! -f "$VERSIONS_FILE" ]; then + cp "$EXAMPLE_VERSIONS_FILE" "$VERSIONS_FILE" +fi + +COMMIT=$(git log -1 --pretty=format:%H) +OSX="OSX" +sed -i.bak "s|/\*${OSX}_VERSION\*/.*|/\*${OSX}_VERSION\*/ const ${OSX}_VERSION = \"$COMMIT\";|g" "$VERSIONS_FILE" +rm -f "${VERSIONS_FILE}.bak" + +rm -rf build/rust +cp -r ../../rust build/rust +cd build/rust + +mkdir -p target +cargo lipo --release --targets aarch64-apple-darwin + +cbindgen --config cbindgen.toml --crate epic-cash-wallet --output target/epic_cash_wallet.h +cp target/epic_cash_wallet.h libepic_cash_wallet.h +mkdir -p Headers +cp target/epic_cash_wallet.h Headers/libepic_cash_wallet.h +cp target/epic_cash_wallet.h ../../../../macos/Classes/FlutterLibepiccashPlugin.h + +RANDOMX_LIB=$(find target/aarch64-apple-darwin/release/build -name "librandomx.a" | head -n 1 || true) +if [ -n "${RANDOMX_LIB}" ] && [ -f "${RANDOMX_LIB}" ]; then + echo "Found RandomX library at: ${RANDOMX_LIB}" + libtool -static -o target/aarch64-apple-darwin/release/libepic_cash_wallet_combined.a \ + target/aarch64-apple-darwin/release/libepic_cash_wallet.a \ + "${RANDOMX_LIB}" + MAIN_LIB=target/aarch64-apple-darwin/release/libepic_cash_wallet_combined.a +else + echo "Warning: librandomx.a not found, using libepic_cash_wallet.a only" + MAIN_LIB=target/aarch64-apple-darwin/release/libepic_cash_wallet.a +fi + +xcodebuild -create-xcframework \ + -library "${MAIN_LIB}" \ + -headers libepic_cash_wallet.h \ + -output ../EpicWallet.xcframework + +fwk=../../../../macos/framework +rm -rf "${fwk}" +mkdir -p "${fwk}" +mv ../EpicWallet.xcframework "${fwk}" From f90542389c503f6330497646412fe26d4bbc2e23 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 12:23:41 +0100 Subject: [PATCH 042/118] fix(macos): prevent empty Runner module name and stabilize xcconfig inheritance --- Makefile | 12 +++++ macos/Runner/Configs/Debug.xcconfig | 1 + macos/Runner/Configs/Release.xcconfig | 1 + .../macos/Runner.xcodeproj/project.pbxproj | 47 ++++++++++--------- 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 07acb5fc3..12eff3827 100644 --- a/Makefile +++ b/Makefile @@ -134,10 +134,22 @@ macos-restore-metadata: @rm -f macos/Flutter/Flutter-Debug.xcconfig.bak macos/Flutter/Flutter-Release.xcconfig.bak @# Keep app target deployment aligned with plugin minimums (e.g. camera_macos >= 11.0). @sed -i.bak -e "s/MACOSX_DEPLOYMENT_TARGET = 10\\.15;/MACOSX_DEPLOYMENT_TARGET = 11.0;/g" macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true + @# Ensure Runner configs inherit app metadata (PRODUCT_NAME/BUNDLE ID) from AppInfo. + @grep -q 'AppInfo.xcconfig' macos/Runner/Configs/Debug.xcconfig || \ + sed -i.bak -e '/Flutter-Debug.xcconfig/a\ +#include "AppInfo.xcconfig"' macos/Runner/Configs/Debug.xcconfig 2>/dev/null || true + @grep -q 'AppInfo.xcconfig' macos/Runner/Configs/Release.xcconfig || \ + sed -i.bak -e '/Flutter-Release.xcconfig/a\ +#include "AppInfo.xcconfig"' macos/Runner/Configs/Release.xcconfig 2>/dev/null || true + @rm -f macos/Runner/Configs/Debug.xcconfig.bak macos/Runner/Configs/Release.xcconfig.bak @# Runner target configs must inherit Debug/Release xcconfigs (not AppInfo) so Pods module paths are available. @perl -0777 -i.bak -pe 's/(33CC10FC2044A3C60003C045 \/\* Debug \*\/ = \{\s*isa = XCBuildConfiguration;\s*)baseConfigurationReference = 33E5194F232828860026EE4D \/\* AppInfo\.xcconfig \*\//$${1}baseConfigurationReference = 9740EEB21CF90195004384FC \/\* Debug.xcconfig \*\//s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true @perl -0777 -i.bak -pe 's/(33CC10FD2044A3C60003C045 \/\* Release \*\/ = \{\s*isa = XCBuildConfiguration;\s*)baseConfigurationReference = 33E5194F232828860026EE4D \/\* AppInfo\.xcconfig \*\//$${1}baseConfigurationReference = 7AFA3C8E1D35360C0083082E \/\* Release.xcconfig \*\//s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true @perl -0777 -i.bak -pe 's/(338D0CEA231458BD00FA5F75 \/\* Profile \*\/ = \{\s*isa = XCBuildConfiguration;\s*)baseConfigurationReference = 33E5194F232828860026EE4D \/\* AppInfo\.xcconfig \*\//$${1}baseConfigurationReference = 7AFA3C8E1D35360C0083082E \/\* Release.xcconfig \*\//s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true + @# Force a valid Swift module identifier for Runner even when PRODUCT_NAME is space-separated. + @perl -0777 -i.bak -pe 's/(33CC10FC2044A3C60003C045 \/\* Debug \*\/ = \{\s*isa = XCBuildConfiguration;.*?buildSettings = \{.*?)(\n\s*PROVISIONING_PROFILE_SPECIFIER = "";)/$${1}\n\t\t\t\tPRODUCT_MODULE_NAME = stack_wallet;$${2}/s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true + @perl -0777 -i.bak -pe 's/(33CC10FD2044A3C60003C045 \/\* Release \*\/ = \{\s*isa = XCBuildConfiguration;.*?buildSettings = \{.*?)(\n\s*PROVISIONING_PROFILE_SPECIFIER = "";)/$${1}\n\t\t\t\tPRODUCT_MODULE_NAME = stack_wallet;$${2}/s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true + @perl -0777 -i.bak -pe 's/(338D0CEA231458BD00FA5F75 \/\* Profile \*\/ = \{\s*isa = XCBuildConfiguration;.*?buildSettings = \{.*?)(\n\s*PROVISIONING_PROFILE_SPECIFIER = "";)/$${1}\n\t\t\t\tPRODUCT_MODULE_NAME = stack_wallet;$${2}/s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true @rm -f macos/Runner.xcodeproj/project.pbxproj.bak @$(FLUTTER) pub get @# Ensure generated build settings are single-line key/value entries for CocoaPods xcconfig parser. diff --git a/macos/Runner/Configs/Debug.xcconfig b/macos/Runner/Configs/Debug.xcconfig index 36b0fd946..3bc8b00f1 100644 --- a/macos/Runner/Configs/Debug.xcconfig +++ b/macos/Runner/Configs/Debug.xcconfig @@ -1,2 +1,3 @@ #include "../../Flutter/Flutter-Debug.xcconfig" +#include "AppInfo.xcconfig" #include "Warnings.xcconfig" diff --git a/macos/Runner/Configs/Release.xcconfig b/macos/Runner/Configs/Release.xcconfig index dff4f4956..71202c7d6 100644 --- a/macos/Runner/Configs/Release.xcconfig +++ b/macos/Runner/Configs/Release.xcconfig @@ -1,2 +1,3 @@ #include "../../Flutter/Flutter-Release.xcconfig" +#include "AppInfo.xcconfig" #include "Warnings.xcconfig" diff --git a/scripts/app_config/templates/macos/Runner.xcodeproj/project.pbxproj b/scripts/app_config/templates/macos/Runner.xcodeproj/project.pbxproj index 25ad3b582..4c2c2a72a 100644 --- a/scripts/app_config/templates/macos/Runner.xcodeproj/project.pbxproj +++ b/scripts/app_config/templates/macos/Runner.xcodeproj/project.pbxproj @@ -583,13 +583,14 @@ "$(inherited)", "@executable_path/../Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"", - /usr/lib/swift, - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"", + /usr/lib/swift, + ); + PRODUCT_MODULE_NAME = stack_wallet; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; }; name = Profile; }; @@ -734,14 +735,15 @@ "$(inherited)", "@executable_path/../Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"", - /usr/lib/swift, - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"", + /usr/lib/swift, + ); + PRODUCT_MODULE_NAME = stack_wallet; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -776,13 +778,14 @@ "$(inherited)", "@executable_path/../Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"", - /usr/lib/swift, - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"", + /usr/lib/swift, + ); + PRODUCT_MODULE_NAME = stack_wallet; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; }; name = Release; }; From 28cc19998d8bd5ea6699dcea0f6bde0789f2a7ca Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 12:48:52 +0100 Subject: [PATCH 043/118] build(macos): harden sed usage and patch libmwc script via superproject --- Makefile | 9 ++++- .../patches/flutter_libmwc_macos_build_all.sh | 38 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 scripts/patches/flutter_libmwc_macos_build_all.sh diff --git a/Makefile b/Makefile index 12eff3827..f05e1e666 100644 --- a/Makefile +++ b/Makefile @@ -78,7 +78,8 @@ patch-submodules: ## Apply portability patches to submodules @echo "Patching submodules for portability..." @chmod -R u+w crypto_plugins/ 2>/dev/null || true @rm -rf crypto_plugins/*/scripts/macos/build - @find crypto_plugins -name "build_all.sh" -exec sed -i.bak 's|/\$${OS}_VERSION/c\\.*|s\|/\\\*\$${OSX}_VERSION\\\*/.*\|/\\\*\$${OSX}_VERSION\\\*/ const \$${OSX}_VERSION = \\"$$COMMIT\\";\|g|g' {} \; 2>/dev/null || true + @# NOTE: avoid brittle cross-platform in-place sed rewrites for build_all.sh files here. + @# Platform-specific script patching is handled explicitly in build targets via scripts/patches/*. @find crypto_plugins/frostdart -name "build_*.dart" -type f -exec sed -i.bak 's/\["-i", ".bak",/\["-i.bak",/g' {} + 2>/dev/null || true @echo "Fixing Epic Cash header logic..." @sed -i.bak 's|cp target/epic_cash_wallet.h libepic_cash_wallet.h|mkdir -p target \&\& touch target/epic_cash_wallet.h \&\& cp target/epic_cash_wallet.h libepic_cash_wallet.h|g' crypto_plugins/flutter_libepiccash/scripts/macos/build_all.sh 2>/dev/null || true @@ -96,7 +97,8 @@ build-macos: check-reqs check-macos-sdk macos-prepare macos-configure macos-rest macos-prepare: @echo "--- Sanitizing environment..." - @sed -i 's/\xc2\xa0/ /g' scripts/app_config/templates/pubspec.template.yaml 2>/dev/null || true + @sed -i.bak 's/\xc2\xa0/ /g' scripts/app_config/templates/pubspec.template.yaml 2>/dev/null || true + @rm -f scripts/app_config/templates/pubspec.template.yaml.bak @chmod -R u+w . 2>/dev/null || true @rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain stable >/dev/null 2>&1 || true @rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain 1.85.1 >/dev/null 2>&1 || true @@ -162,6 +164,9 @@ macos-build-native: @echo "--- Applying local patch for flutter_libepiccash macOS build script..." @cp scripts/patches/flutter_libepiccash_macos_build_all.sh crypto_plugins/flutter_libepiccash/scripts/macos/build_all.sh @chmod +x crypto_plugins/flutter_libepiccash/scripts/macos/build_all.sh + @echo "--- Applying local patch for flutter_libmwc macOS build script..." + @cp scripts/patches/flutter_libmwc_macos_build_all.sh crypto_plugins/flutter_libmwc/scripts/macos/build_all.sh + @chmod +x crypto_plugins/flutter_libmwc/scripts/macos/build_all.sh @env $(MACOS_ENV_UNSET) $(MACOS_ENV_SET) \ RUSTUP_HOME="$$HOME/.rustup" \ CARGO_HOME="$$HOME/.cargo" \ diff --git a/scripts/patches/flutter_libmwc_macos_build_all.sh b/scripts/patches/flutter_libmwc_macos_build_all.sh new file mode 100644 index 000000000..47bf44f7e --- /dev/null +++ b/scripts/patches/flutter_libmwc_macos_build_all.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -e +rm -rf build +mkdir build +echo ''$(git log -1 --pretty=format:"%H")' '$(date) >> build/git_commit_version.txt +VERSIONS_FILE=../../lib/git_versions.dart +EXAMPLE_VERSIONS_FILE=../../lib/git_versions_example.dart +if [ ! -f "$VERSIONS_FILE" ]; then + cp $EXAMPLE_VERSIONS_FILE $VERSIONS_FILE +fi +COMMIT=$(git log -1 --pretty=format:"%H") +OSX="OSX" +tmp_file="${VERSIONS_FILE}.tmp" +awk -v os="$OSX" -v commit="$COMMIT" ' + index($0, "/*" os "_VERSION*/") { print "/*" os "_VERSION*/ const " os "_VERSION = \"" commit "\";"; next } + { print } +' "$VERSIONS_FILE" > "$tmp_file" +mv "$tmp_file" "$VERSIONS_FILE" +cp -r ../../rust build/rust +cd build/rust + +# some people need this apparently +export PROTOC=/opt/homebrew/bin/protoc + +# building +cbindgen src/lib.rs -l c > libmwc_wallet.h +cargo lipo --release --targets aarch64-apple-darwin + +xcodebuild -create-xcframework \ + -library target/aarch64-apple-darwin/release/libmwc_wallet.a \ + -headers libmwc_wallet.h \ + -output ../MWCWallet.xcframework + +# moving files to the macos project +fwk=../../../../macos/framework/ +rm -rf ${fwk} +mkdir ${fwk} +mv ../MWCWallet.xcframework ${fwk} From 387601c7cb69cbed67581b73a852a9e8ad1ea71a Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 12:52:00 +0100 Subject: [PATCH 044/118] build(macos): enforce reproducible arm64 pod architecture settings --- Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Makefile b/Makefile index f05e1e666..15d302ca3 100644 --- a/Makefile +++ b/Makefile @@ -176,6 +176,14 @@ macos-build-native: @$(DART) run coinlib:build_macos @echo "--- Patching Podfile..." @sed -i.bak -e "s/platform :osx, '10.11'/platform :osx, '11.0'/g" -e "s/platform :osx, '10.15'/platform :osx, '11.0'/g" macos/Podfile 2>/dev/null || true + @# Force deterministic arm64-only CocoaPods builds on Apple Silicon (avoid x86_64 Swift header failures). + @grep -q "EXCLUDED_ARCHS\\[sdk=macosx\\*\\]" macos/Podfile || \ + sed -i.bak -e "/MACOSX_DEPLOYMENT_TARGET.*11.0/a\\ + config.build_settings['EXCLUDED_ARCHS[sdk=macosx*]'] = 'x86_64'\\ + config.build_settings['ONLY_ACTIVE_ARCH'] = 'YES'" macos/Podfile 2>/dev/null || true + @grep -q "config.build_settings\\['ARCHS'\\] = 'arm64'" macos/Podfile || \ + sed -i.bak -e "/MACOSX_DEPLOYMENT_TARGET.*11.0/a\\ + config.build_settings['ARCHS'] = 'arm64'" macos/Podfile 2>/dev/null || true @rm -f macos/Podfile.bak macos-build-app: From 810e6cbe80cb64ebdce6f93779f760aa67be00fa Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 12:53:46 +0100 Subject: [PATCH 045/118] fixing introduced error in multiline sed --- Makefile | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 15d302ca3..cab54b750 100644 --- a/Makefile +++ b/Makefile @@ -177,13 +177,9 @@ macos-build-native: @echo "--- Patching Podfile..." @sed -i.bak -e "s/platform :osx, '10.11'/platform :osx, '11.0'/g" -e "s/platform :osx, '10.15'/platform :osx, '11.0'/g" macos/Podfile 2>/dev/null || true @# Force deterministic arm64-only CocoaPods builds on Apple Silicon (avoid x86_64 Swift header failures). - @grep -q "EXCLUDED_ARCHS\\[sdk=macosx\\*\\]" macos/Podfile || \ - sed -i.bak -e "/MACOSX_DEPLOYMENT_TARGET.*11.0/a\\ - config.build_settings['EXCLUDED_ARCHS[sdk=macosx*]'] = 'x86_64'\\ - config.build_settings['ONLY_ACTIVE_ARCH'] = 'YES'" macos/Podfile 2>/dev/null || true - @grep -q "config.build_settings\\['ARCHS'\\] = 'arm64'" macos/Podfile || \ - sed -i.bak -e "/MACOSX_DEPLOYMENT_TARGET.*11.0/a\\ - config.build_settings['ARCHS'] = 'arm64'" macos/Podfile 2>/dev/null || true + @perl -0777 -i.bak -pe "s/(config\\.build_settings\\['MACOSX_DEPLOYMENT_TARGET'\\]\\s*=\\s*'11\\.0'\\s*\\n)(?!\\s*config\\.build_settings\\['EXCLUDED_ARCHS\\[sdk=macosx\\*\\]'\\])/\$$1 config.build_settings['EXCLUDED_ARCHS[sdk=macosx*]'] = 'x86_64'\\n/s" macos/Podfile 2>/dev/null || true + @perl -0777 -i.bak -pe "s/(config\\.build_settings\\['MACOSX_DEPLOYMENT_TARGET'\\]\\s*=\\s*'11\\.0'\\s*\\n)(?!\\s*config\\.build_settings\\['ONLY_ACTIVE_ARCH'\\])/\$$1 config.build_settings['ONLY_ACTIVE_ARCH'] = 'YES'\\n/s" macos/Podfile 2>/dev/null || true + @perl -0777 -i.bak -pe "s/(config\\.build_settings\\['MACOSX_DEPLOYMENT_TARGET'\\]\\s*=\\s*'11\\.0'\\s*\\n)(?!\\s*config\\.build_settings\\['ARCHS'\\])/\$$1 config.build_settings['ARCHS'] = 'arm64'\\n/s" macos/Podfile 2>/dev/null || true @rm -f macos/Podfile.bak macos-build-app: From b6387319efe427e59a3d402e570251b45b05f0e4 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 13:08:12 +0100 Subject: [PATCH 046/118] build(macos): harden sed rewrites for frostdart and enforce reproducible arm64 pod settings --- Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index cab54b750..effeb3d3a 100644 --- a/Makefile +++ b/Makefile @@ -80,12 +80,14 @@ patch-submodules: ## Apply portability patches to submodules @rm -rf crypto_plugins/*/scripts/macos/build @# NOTE: avoid brittle cross-platform in-place sed rewrites for build_all.sh files here. @# Platform-specific script patching is handled explicitly in build targets via scripts/patches/*. - @find crypto_plugins/frostdart -name "build_*.dart" -type f -exec sed -i.bak 's/\["-i", ".bak",/\["-i.bak",/g' {} + 2>/dev/null || true + @find crypto_plugins/frostdart -name "build_*.dart" -type f -exec perl -0777 -i.bak -pe 's/\["-i"\s*,\s*"\.bak"\s*,/\["-i.bak",/g' {} + 2>/dev/null || true @echo "Fixing Epic Cash header logic..." @sed -i.bak 's|cp target/epic_cash_wallet.h libepic_cash_wallet.h|mkdir -p target \&\& touch target/epic_cash_wallet.h \&\& cp target/epic_cash_wallet.h libepic_cash_wallet.h|g' crypto_plugins/flutter_libepiccash/scripts/macos/build_all.sh 2>/dev/null || true @sed -i.bak 's|cbindgen --config cbindgen.toml --crate epic-cash-wallet --output target/epic_cash_wallet.h|cbindgen --config cbindgen.toml --crate epic-cash-wallet --output target/epic_cash_wallet.h \&\& cp target/epic_cash_wallet.h libepic_cash_wallet.h|g' crypto_plugins/flutter_libepiccash/scripts/macos/build_all.sh 2>/dev/null || true @echo "Fixing Frostdart binary path..." - @find crypto_plugins/frostdart/scripts -name "build_all.sh" -exec sed -i.bak "s|.*dart build_|$(shell which dart) build_|g" {} + 2>/dev/null || true + @find crypto_plugins/frostdart/scripts -name "build_all.sh" -exec perl -0777 -i.bak -pe 's|^.*dart\s+build_|dart build_|mg' {} + 2>/dev/null || true + @# GNU/BSD sed compatibility: ensure Frostdart macOS script uses -i.bak form. + @perl -0777 -i.bak -pe 's/_run\("sed",\s*\["-i"\s*,\s*"\.bak"\s*,\s*"s\/frostdart\/hrf-api\/",\s*"cargo\.toml"\]\);/_run("sed", ["-i.bak", "s\/frostdart\/hrf-api\/", "cargo.toml"]);/g' crypto_plugins/frostdart/scripts/macos/build_macos.dart 2>/dev/null || true @echo "Disabling strict Rust checks..." @find crypto_plugins scripts -type f -name "rust_version.sh" -exec sed -i.bak 's/exit 1/echo "Bypassed by Nix"/g' {} + 2>/dev/null || true @find crypto_plugins -name "*.bak" -delete 2>/dev/null || true From a044b610cb5b407668c53433e73db2974710a716 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 13:16:07 +0100 Subject: [PATCH 047/118] build(macos): patch frostdart sed invocation during native build --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index effeb3d3a..85b5aaaba 100644 --- a/Makefile +++ b/Makefile @@ -169,6 +169,8 @@ macos-build-native: @echo "--- Applying local patch for flutter_libmwc macOS build script..." @cp scripts/patches/flutter_libmwc_macos_build_all.sh crypto_plugins/flutter_libmwc/scripts/macos/build_all.sh @chmod +x crypto_plugins/flutter_libmwc/scripts/macos/build_all.sh + @# Ensure Frostdart macOS build script uses sed -i.bak form (GNU/BSD compatibility). + @perl -0777 -i.bak -pe 's/_run\("sed",\s*\["-i"\s*,\s*"\.bak"\s*,\s*"s\/frostdart\/hrf-api\/",\s*"cargo\.toml"\]\);/_run("sed", ["-i.bak", "s\/frostdart\/hrf-api\/", "cargo.toml"]);/g' crypto_plugins/frostdart/scripts/macos/build_macos.dart 2>/dev/null || true @env $(MACOS_ENV_UNSET) $(MACOS_ENV_SET) \ RUSTUP_HOME="$$HOME/.rustup" \ CARGO_HOME="$$HOME/.cargo" \ From 14240e291615e955539153041f614a0af14e6dae Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 13:24:05 +0100 Subject: [PATCH 048/118] build(macos): use flutter pub for coinlib build step in nix env --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 85b5aaaba..7201e14bf 100644 --- a/Makefile +++ b/Makefile @@ -177,7 +177,7 @@ macos-build-native: PATH="/opt/homebrew/opt/rustup/bin:/opt/homebrew/bin:$$HOME/.cargo/bin:$$PATH" \ bash scripts/macos/build_all.sh @rm -rf build/secp256k1 - @$(DART) run coinlib:build_macos + @$(FLUTTER) pub run coinlib:build_macos @echo "--- Patching Podfile..." @sed -i.bak -e "s/platform :osx, '10.11'/platform :osx, '11.0'/g" -e "s/platform :osx, '10.15'/platform :osx, '11.0'/g" macos/Podfile 2>/dev/null || true @# Force deterministic arm64-only CocoaPods builds on Apple Silicon (avoid x86_64 Swift header failures). From 7895630b2a079700d2bb5d0cb89d8fb7d4fbc336 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 13:43:16 +0100 Subject: [PATCH 049/118] build(macos): make CocoaPods/plugin resolution reproducible in nix shell --- Makefile | 13 +++-- macos/Podfile | 2 - scripts/macos/patch_coinlib_podspec.sh | 69 ++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 9 deletions(-) create mode 100755 scripts/macos/patch_coinlib_podspec.sh diff --git a/Makefile b/Makefile index 7201e14bf..2b7593030 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ VERSION ?= 2.1.0 BUILD_NUM ?= 210 FLUTTER ?= flutter DART ?= dart +PUB_CACHE ?= $(APP_PROJECT_ROOT_DIR)/.pub-cache APP_PROJECT_ROOT_DIR := $(CURDIR) PROTOC_PATH := $(shell which protoc 2>/dev/null) MACOS_ENV_UNSET = -u LD -u LDFLAGS -u NIX_LDFLAGS -u NIX_CFLAGS_LINK \ @@ -18,6 +19,7 @@ MACOS_ENV_UNSET = -u LD -u LDFLAGS -u NIX_LDFLAGS -u NIX_CFLAGS_LINK \ MACOS_ENV_SET = MACOSX_DEPLOYMENT_TARGET=11.0 export APP_PROJECT_ROOT_DIR +export PUB_CACHE .PHONY: help check-reqs check-reqs-windows check-macos-sdk init clean prebuild-unix prebuild-windows deps-linux patch-submodules \ build-linux build-macos build-ios build-android build-windows \ @@ -69,9 +71,9 @@ clean: ## Remove artifacts and fix permissions @rm -rf macos/Pods macos/Podfile.lock ios/Pods ios/Podfile.lock build/ @echo "Cleaning submodule target folders..." @find crypto_plugins/ -type d \( -name "target" -o -name "build" \) -exec rm -rf {} + 2>/dev/null || true - @echo "Cleaning external residues..." - @chmod -R u+w $(HOME)/.pub-cache/git/ 2>/dev/null || true - @find $(HOME)/.pub-cache/git/ -type d \( -name "build" -o -name "target" \) -path "*flutter_lib*" -exec rm -rf {} + 2>/dev/null || true + @echo "Cleaning local pub cache residues..." + @chmod -R u+w $(PUB_CACHE)/git/ 2>/dev/null || true + @find $(PUB_CACHE)/git/ -type d \( -name "build" -o -name "target" \) -path "*flutter_lib*" -exec rm -rf {} + 2>/dev/null || true @echo "[OK] Project is now in a pristine state." patch-submodules: ## Apply portability patches to submodules @@ -156,6 +158,7 @@ macos-restore-metadata: @perl -0777 -i.bak -pe 's/(338D0CEA231458BD00FA5F75 \/\* Profile \*\/ = \{\s*isa = XCBuildConfiguration;.*?buildSettings = \{.*?)(\n\s*PROVISIONING_PROFILE_SPECIFIER = "";)/$${1}\n\t\t\t\tPRODUCT_MODULE_NAME = stack_wallet;$${2}/s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true @rm -f macos/Runner.xcodeproj/project.pbxproj.bak @$(FLUTTER) pub get + @bash scripts/macos/patch_coinlib_podspec.sh @# Ensure generated build settings are single-line key/value entries for CocoaPods xcconfig parser. @[ -f macos/Flutter/ephemeral/Flutter-Generated.xcconfig ] && \ sed -i.bak -E 's/[[:space:]]+$$//' macos/Flutter/ephemeral/Flutter-Generated.xcconfig && \ @@ -180,10 +183,6 @@ macos-build-native: @$(FLUTTER) pub run coinlib:build_macos @echo "--- Patching Podfile..." @sed -i.bak -e "s/platform :osx, '10.11'/platform :osx, '11.0'/g" -e "s/platform :osx, '10.15'/platform :osx, '11.0'/g" macos/Podfile 2>/dev/null || true - @# Force deterministic arm64-only CocoaPods builds on Apple Silicon (avoid x86_64 Swift header failures). - @perl -0777 -i.bak -pe "s/(config\\.build_settings\\['MACOSX_DEPLOYMENT_TARGET'\\]\\s*=\\s*'11\\.0'\\s*\\n)(?!\\s*config\\.build_settings\\['EXCLUDED_ARCHS\\[sdk=macosx\\*\\]'\\])/\$$1 config.build_settings['EXCLUDED_ARCHS[sdk=macosx*]'] = 'x86_64'\\n/s" macos/Podfile 2>/dev/null || true - @perl -0777 -i.bak -pe "s/(config\\.build_settings\\['MACOSX_DEPLOYMENT_TARGET'\\]\\s*=\\s*'11\\.0'\\s*\\n)(?!\\s*config\\.build_settings\\['ONLY_ACTIVE_ARCH'\\])/\$$1 config.build_settings['ONLY_ACTIVE_ARCH'] = 'YES'\\n/s" macos/Podfile 2>/dev/null || true - @perl -0777 -i.bak -pe "s/(config\\.build_settings\\['MACOSX_DEPLOYMENT_TARGET'\\]\\s*=\\s*'11\\.0'\\s*\\n)(?!\\s*config\\.build_settings\\['ARCHS'\\])/\$$1 config.build_settings['ARCHS'] = 'arm64'\\n/s" macos/Podfile 2>/dev/null || true @rm -f macos/Podfile.bak macos-build-app: diff --git a/macos/Podfile b/macos/Podfile index de1395f9f..c816319bc 100644 --- a/macos/Podfile +++ b/macos/Podfile @@ -41,8 +41,6 @@ post_install do |installer| flutter_additional_macos_build_settings(target) target.build_configurations.each do |config| config.build_settings['MACOSX_DEPLOYMENT_TARGET'] = '11.0' - config.build_settings['ARCHS'] = 'arm64' - config.build_settings['VALID_ARCHS'] = 'arm64' end end end diff --git a/scripts/macos/patch_coinlib_podspec.sh b/scripts/macos/patch_coinlib_podspec.sh new file mode 100755 index 000000000..4703133b1 --- /dev/null +++ b/scripts/macos/patch_coinlib_podspec.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +set -euo pipefail + +PUB_CACHE_DIR="${PUB_CACHE:-$PWD/.pub-cache}" +COINLIB_SPEC="" + +if [ -d "$PUB_CACHE_DIR/git" ]; then + COINLIB_SPEC="$(find "$PUB_CACHE_DIR/git" -maxdepth 4 -type f -path '*/coinlib_flutter/darwin/coinlib_flutter.podspec' | head -n 1)" +fi + +if [ -z "$COINLIB_SPEC" ]; then + echo "[WARN] coinlib_flutter.podspec not found under PUB_CACHE=$PUB_CACHE_DIR; skipping patch" + exit 0 +fi + +if grep -q "STACK_WALLET_COINLIB_PATCH" "$COINLIB_SPEC"; then + echo "[OK] coinlib podspec already patched: $COINLIB_SPEC" + exit 0 +fi + +TMP_FILE="$(mktemp)" +cat > "$TMP_FILE" <<'RUBY' +# STACK_WALLET_COINLIB_PATCH: make secp setup idempotent for reproducible pod install. +require 'fileutils' +secp_dir = File.expand_path('build/secp256k1', __dir__) +unless Dir.exist?(secp_dir) + FileUtils.mkdir_p(File.dirname(secp_dir)) + system('git', 'clone', 'https://github.com/bitcoin-core/secp256k1', secp_dir) or raise 'coinlib: failed to clone secp256k1' +end +Dir.chdir(secp_dir) do + system('git', 'checkout', 'e3a885d42a7800c1ccebad94ad1e2b82c4df5c65') or raise 'coinlib: failed to checkout pinned secp256k1 commit' +end + +Pod::Spec.new do |s| + s.name = 'coinlib_flutter' + s.module_name = 'secp256k1' + s.version = '0.5.0' + s.summary = 'Cryptographic primitives from the secp256k1 library' + s.description = <<-DESC +The secp256k1 library bundled into the flutter plugin via cocoapods. + DESC + s.homepage = 'http://peercoin.net' + s.license = { :file => '../LICENSE' } + s.author = 'Peercoin Developers' + + # This will ensure the source files in Classes/ are included in the native + # builds of apps using this FFI plugin. Podspec does not support relative + # paths, so Classes contains a forwarder C file that relatively imports + # `../src/*` so that the C sources can be shared among all target platforms. + s.source = { :path => '.' } + s.source_files = 'Classes/*.c' + s.compiler_flags = '-Wno-unused-function', '-Wno-shorten-64-to-32' + + s.ios.dependency 'Flutter' + s.osx.dependency 'FlutterMacOS' + s.ios.deployment_target = '11.0' + s.osx.deployment_target = '10.14' + + # Flutter.framework does not contain a i386 slice. + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } + s.swift_version = '5.0' + +end +RUBY + +cp "$TMP_FILE" "$COINLIB_SPEC" +rm -f "$TMP_FILE" + +echo "[OK] patched coinlib podspec: $COINLIB_SPEC" From d875fedc522a918eec876803e417bf8da348373c Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 15:09:16 +0100 Subject: [PATCH 050/118] build(macos): harden reproducible nix setup and coinlib toolchain requirements --- Makefile | 4 ++++ flake.nix | 5 ++++- scripts/install_macos_build_tools.sh | 4 +++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2b7593030..3e9be7ae3 100644 --- a/Makefile +++ b/Makefile @@ -42,6 +42,10 @@ check-reqs: ## Verify essential build tools @command -v go >/dev/null 2>&1 || { echo >&2 "[ERROR] Go not installed."; exit 1; } @command -v cmake >/dev/null 2>&1 || { echo >&2 "[ERROR] CMake not installed."; exit 1; } @command -v pkg-config >/dev/null 2>&1 || { echo >&2 "[ERROR] pkg-config not installed."; exit 1; } +ifeq ($(shell uname),Darwin) + @command -v autoreconf >/dev/null 2>&1 || { echo >&2 "[ERROR] autoconf/autoreconf not installed."; exit 1; } + @command -v aclocal >/dev/null 2>&1 || { echo >&2 "[ERROR] automake/aclocal not installed."; exit 1; } +endif @echo "[OK] All core CLI requirements found!" check-macos-sdk: ## Verify XCode on macOS diff --git a/flake.nix b/flake.nix index 971700345..ffc5a8a32 100644 --- a/flake.nix +++ b/flake.nix @@ -37,7 +37,10 @@ macPackages = lib.optionals pkgs.stdenv.isDarwin (with pkgs; [ cocoapods - libiconv + libiconv + autoconf + automake + libtool ]); in diff --git a/scripts/install_macos_build_tools.sh b/scripts/install_macos_build_tools.sh index 272339d84..8b7201738 100755 --- a/scripts/install_macos_build_tools.sh +++ b/scripts/install_macos_build_tools.sh @@ -13,7 +13,7 @@ if ! command -v brew >/dev/null 2>&1; then fi echo "Installing Homebrew packages..." -brew install direnv rustup-init cmake ninja pkg-config gnu-sed cocoapods go protobuf +brew install direnv rustup-init cmake ninja pkg-config gnu-sed cocoapods go protobuf autoconf automake libtool echo "Installing Flutter cask..." brew install --cask flutter @@ -58,5 +58,7 @@ rustc --version rustup run stable rustc --version pod --version go version +autoreconf --version | head -n 1 || true +aclocal --version | head -n 1 || true echo "Done." From 69b96aed157d86ad8933e695004c83720b160a11 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 15:32:13 +0100 Subject: [PATCH 051/118] build(macos): improve reproducibility and drop unused rust 1.81.0 --- docs/building.md | 8 ++++---- flake.nix | 2 +- scripts/install_macos_build_tools.sh | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/building.md b/docs/building.md index 17978457d..dff508079 100644 --- a/docs/building.md +++ b/docs/building.md @@ -51,7 +51,7 @@ Install [Rust](https://www.rust-lang.org/tools/install) via [rustup.rs](https:// ``` curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source ~/.bashrc -rustup install 1.89.0 1.85.1 1.81.0 +rustup install 1.89.0 1.85.1 rustup default 1.89.0 cargo install cargo-ndk ``` @@ -198,11 +198,11 @@ brew install brotli cairo coreutils gdbm gettext glib gmp libevent libidn2 libng ``` -Download and install [Rust](https://www.rust-lang.org/tools/install). [Rustup](https://rustup.rs/) is recommended for Rust setup. Use `rustc` to confirm successful installation. Install toolchains 1.81.0, 1.85.1, and 1.89.0 as well as `cbindgen` and `cargo-lipo` too. You will also have to add the platform target(s) `aarch64-apple-ios` and/or `aarch64-apple-darwin`. You can use the command(s): +Download and install [Rust](https://www.rust-lang.org/tools/install). [Rustup](https://rustup.rs/) is recommended for Rust setup. Use `rustc` to confirm successful installation. Install toolchains 1.85.1 and 1.89.0 as well as `cbindgen` and `cargo-lipo` too. You will also have to add the platform target(s) `aarch64-apple-ios` and/or `aarch64-apple-darwin`. You can use the command(s): ``` curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source ~/.bashrc -rustup install 1.89.0 1.85.1 1.81.0 +rustup install 1.89.0 1.85.1 rustup default 1.89.0 cargo install cargo-ndk cargo install cbindgen cargo-lipo @@ -283,7 +283,7 @@ Install Flutter 3.38.5 on your Windows host (not in WSL2) by [following their gu ### Rust Install [Rust](https://www.rust-lang.org/tools/install) on the Windows host (not in WSL2). Download the installer from [rustup.rs](https://rustup.rs), make sure it works on the commandline (you may need to open a new terminal), and install the following versions: ``` -rustup install 1.89.0 1.85.1 1.81.0 +rustup install 1.89.0 1.85.1 rustup default 1.89.0 cargo install cargo-ndk ``` diff --git a/flake.nix b/flake.nix index ffc5a8a32..f9312952a 100644 --- a/flake.nix +++ b/flake.nix @@ -62,7 +62,7 @@ # ========================================== if ! rustup toolchain list | grep -q "1.89.0"; then echo "Initializing Rust toolchains (this happens only once)..." - rustup install 1.89.0 1.85.1 1.81.0 stable + rustup install 1.89.0 1.85.1 stable rustup default 1.89.0 if [[ "${system}" == *"darwin"* ]]; then diff --git a/scripts/install_macos_build_tools.sh b/scripts/install_macos_build_tools.sh index 8b7201738..c5be09ae6 100755 --- a/scripts/install_macos_build_tools.sh +++ b/scripts/install_macos_build_tools.sh @@ -31,7 +31,7 @@ fi echo "Ensuring Rust toolchains are installed..." rustup toolchain install stable rustup default stable -rustup toolchain install 1.89.0 1.85.1 1.81.0 +rustup toolchain install 1.89.0 1.85.1 rustup default 1.89.0 rustup target add aarch64-apple-darwin x86_64-apple-darwin aarch64-apple-ios --toolchain stable >/dev/null 2>&1 || true rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain 1.85.1 >/dev/null 2>&1 || true From 1eedefaef6af59b9a512cabc80e67afab602e629 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 15:37:27 +0100 Subject: [PATCH 052/118] build(macos): force darwin-arm64 app build for reproducible Apple Silicon direnv builds --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3e9be7ae3..b46f54ddb 100644 --- a/Makefile +++ b/Makefile @@ -197,7 +197,7 @@ macos-build-app: CARGO_HOME="$$HOME/.cargo" \ RUSTUP_TOOLCHAIN=stable \ PATH="$$(dirname "$$(/opt/homebrew/bin/rustup which rustc)"):/opt/homebrew/opt/rustup/bin:/opt/homebrew/bin:$$HOME/.cargo/bin:$$PATH" \ - $(FLUTTER) build macos --release + $(FLUTTER) build macos --release --target-platform=darwin-arm64 diagnose-macos-env: ## Print macOS build env and tool resolution @echo "--- Toolchain diagnostics ---" From 36ebfa6095fe9534f0c45f57b5f6da8a9344f915 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 15:39:14 +0100 Subject: [PATCH 053/118] Adding distinct arm build only --- .metadata | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.metadata b/.metadata index 675f4a740..a21daf5c2 100644 --- a/.metadata +++ b/.metadata @@ -1,11 +1,11 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled. +# This file should be version controlled and should not be manually edited. version: - revision: f92f44110e87bad5ff168335c36da6f6053036e6 - channel: stable + revision: "ff37bef603469fb030f2b72995ab929ccfc227f0" + channel: "stable" project_type: app @@ -13,11 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: f92f44110e87bad5ff168335c36da6f6053036e6 - base_revision: f92f44110e87bad5ff168335c36da6f6053036e6 + create_revision: ff37bef603469fb030f2b72995ab929ccfc227f0 + base_revision: ff37bef603469fb030f2b72995ab929ccfc227f0 - platform: macos - create_revision: f92f44110e87bad5ff168335c36da6f6053036e6 - base_revision: f92f44110e87bad5ff168335c36da6f6053036e6 + create_revision: ff37bef603469fb030f2b72995ab929ccfc227f0 + base_revision: ff37bef603469fb030f2b72995ab929ccfc227f0 # User provided section From 9d6ce68f4b17609ff9676aceefdb7e5d3519b49e Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 15:49:55 +0100 Subject: [PATCH 054/118] build(macos): force arm64 via env vars instead of unsupported flutter flag --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b46f54ddb..95eaeecb4 100644 --- a/Makefile +++ b/Makefile @@ -197,7 +197,7 @@ macos-build-app: CARGO_HOME="$$HOME/.cargo" \ RUSTUP_TOOLCHAIN=stable \ PATH="$$(dirname "$$(/opt/homebrew/bin/rustup which rustc)"):/opt/homebrew/opt/rustup/bin:/opt/homebrew/bin:$$HOME/.cargo/bin:$$PATH" \ - $(FLUTTER) build macos --release --target-platform=darwin-arm64 + ARCHS=arm64 EXCLUDED_ARCHS=x86_64 ONLY_ACTIVE_ARCH=YES $(FLUTTER) build macos --release diagnose-macos-env: ## Print macOS build env and tool resolution @echo "--- Toolchain diagnostics ---" From ac2579892fb395c8ca7b5e0251b475bffb9f21ad Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 15:57:27 +0100 Subject: [PATCH 055/118] build(macos): force Apple libtool in epiccash patch under nix --- scripts/patches/flutter_libepiccash_macos_build_all.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/patches/flutter_libepiccash_macos_build_all.sh b/scripts/patches/flutter_libepiccash_macos_build_all.sh index b3d4a210f..6a5917b1e 100644 --- a/scripts/patches/flutter_libepiccash_macos_build_all.sh +++ b/scripts/patches/flutter_libepiccash_macos_build_all.sh @@ -31,7 +31,7 @@ cp target/epic_cash_wallet.h ../../../../macos/Classes/FlutterLibepiccashPlugin. RANDOMX_LIB=$(find target/aarch64-apple-darwin/release/build -name "librandomx.a" | head -n 1 || true) if [ -n "${RANDOMX_LIB}" ] && [ -f "${RANDOMX_LIB}" ]; then echo "Found RandomX library at: ${RANDOMX_LIB}" - libtool -static -o target/aarch64-apple-darwin/release/libepic_cash_wallet_combined.a \ + /usr/bin/libtool -static -o target/aarch64-apple-darwin/release/libepic_cash_wallet_combined.a \ target/aarch64-apple-darwin/release/libepic_cash_wallet.a \ "${RANDOMX_LIB}" MAIN_LIB=target/aarch64-apple-darwin/release/libepic_cash_wallet_combined.a From d6823c3ddc83ebca2eb1a2b4096e22c7dc567c47 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 16:06:42 +0100 Subject: [PATCH 056/118] build(macos): force Apple clang/binutils and SDKROOT in native nix builds --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile b/Makefile index 95eaeecb4..ab2cfb98a 100644 --- a/Makefile +++ b/Makefile @@ -181,6 +181,11 @@ macos-build-native: @env $(MACOS_ENV_UNSET) $(MACOS_ENV_SET) \ RUSTUP_HOME="$$HOME/.rustup" \ CARGO_HOME="$$HOME/.cargo" \ + CC="/usr/bin/clang" \ + CXX="/usr/bin/clang++" \ + AR="/usr/bin/ar" \ + RANLIB="/usr/bin/ranlib" \ + SDKROOT="$$(xcrun --sdk macosx --show-sdk-path)" \ PATH="/opt/homebrew/opt/rustup/bin:/opt/homebrew/bin:$$HOME/.cargo/bin:$$PATH" \ bash scripts/macos/build_all.sh @rm -rf build/secp256k1 From 0ade1c90623178f1996a9c0df06143c13f7901d7 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 16:11:25 +0100 Subject: [PATCH 057/118] build(macos): clear make jobserver flags for libmwc openssl build in nix --- Makefile | 4 ++++ scripts/patches/flutter_libmwc_macos_build_all.sh | 2 ++ 2 files changed, 6 insertions(+) diff --git a/Makefile b/Makefile index ab2cfb98a..f319d8d98 100644 --- a/Makefile +++ b/Makefile @@ -181,6 +181,10 @@ macos-build-native: @env $(MACOS_ENV_UNSET) $(MACOS_ENV_SET) \ RUSTUP_HOME="$$HOME/.rustup" \ CARGO_HOME="$$HOME/.cargo" \ + MAKEFLAGS= \ + MFLAGS= \ + CARGO_MAKEFLAGS= \ + CARGO_BUILD_JOBS=1 \ CC="/usr/bin/clang" \ CXX="/usr/bin/clang++" \ AR="/usr/bin/ar" \ diff --git a/scripts/patches/flutter_libmwc_macos_build_all.sh b/scripts/patches/flutter_libmwc_macos_build_all.sh index 47bf44f7e..02243d9cf 100644 --- a/scripts/patches/flutter_libmwc_macos_build_all.sh +++ b/scripts/patches/flutter_libmwc_macos_build_all.sh @@ -21,6 +21,8 @@ cd build/rust # some people need this apparently export PROTOC=/opt/homebrew/bin/protoc +unset MAKEFLAGS MFLAGS CARGO_MAKEFLAGS +export CARGO_BUILD_JOBS=1 # building cbindgen src/lib.rs -l c > libmwc_wallet.h From ac59ca835117a98294cd89e419ea14e70af9d775 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 16:18:23 +0100 Subject: [PATCH 058/118] initial version of nixos build tools --- scripts/install_nixos_build_tools.sh | 71 ++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100755 scripts/install_nixos_build_tools.sh diff --git a/scripts/install_nixos_build_tools.sh b/scripts/install_nixos_build_tools.sh new file mode 100755 index 000000000..caaadd861 --- /dev/null +++ b/scripts/install_nixos_build_tools.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [[ "$(uname -s)" != "Linux" ]]; then + echo "This installer is for Linux/NixOS only." + exit 1 +fi + +if ! command -v nix >/dev/null 2>&1; then + echo "Nix is required. Install it first: https://nixos.org/download/" + exit 1 +fi + +if ! command -v rustup >/dev/null 2>&1; then + echo "rustup is required. Install it first (for toolchain pinning): https://rustup.rs" + exit 1 +fi + +echo "Installing Nix profile packages..." +nix profile install \ + nixpkgs#direnv \ + nixpkgs#flutter \ + nixpkgs#go \ + nixpkgs#cmake \ + nixpkgs#ninja \ + nixpkgs#pkg-config \ + nixpkgs#gnumake \ + nixpkgs#gnused \ + nixpkgs#protobuf \ + nixpkgs#autoconf \ + nixpkgs#automake \ + nixpkgs#libtool \ + nixpkgs#clang || true + +echo "Ensuring Rust toolchains are installed..." +rustup toolchain install stable +rustup default stable +rustup toolchain install 1.89.0 1.85.1 +rustup default 1.89.0 +rustup target add aarch64-unknown-linux-gnu x86_64-unknown-linux-gnu --toolchain stable >/dev/null 2>&1 || true +rustup target add aarch64-unknown-linux-gnu x86_64-unknown-linux-gnu --toolchain 1.85.1 >/dev/null 2>&1 || true +rustup target add aarch64-unknown-linux-gnu x86_64-unknown-linux-gnu --toolchain 1.89.0 >/dev/null 2>&1 || true + +echo "Installing Rust CLI build tools..." +cargo install cargo-ndk cbindgen cargo-lipo || true + +echo "Verifying toolchain..." +if command -v flutter >/dev/null 2>&1; then + flutter --version +else + echo "flutter not found in PATH." +fi + +if command -v dart >/dev/null 2>&1; then + dart --version +else + echo "dart not found in PATH. It should come with Flutter." +fi + +rustup --version +rustc --version +rustup run stable rustc --version +go version +protoc --version || true +cmake --version | head -n 1 || true +pkg-config --version || true +autoreconf --version | head -n 1 || true +aclocal --version | head -n 1 || true + +echo "Done." From 460463c58e07da739bd7042fd5dde3b6deb794a3 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 16:20:06 +0100 Subject: [PATCH 059/118] update of nixos build tools --- scripts/install_nixos_build_tools.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/install_nixos_build_tools.sh b/scripts/install_nixos_build_tools.sh index caaadd861..5a6e133cd 100755 --- a/scripts/install_nixos_build_tools.sh +++ b/scripts/install_nixos_build_tools.sh @@ -18,7 +18,7 @@ if ! command -v rustup >/dev/null 2>&1; then fi echo "Installing Nix profile packages..." -nix profile install \ +nix --extra-experimental-features "nix-command flakes" profile add \ nixpkgs#direnv \ nixpkgs#flutter \ nixpkgs#go \ From bb93e51344312221d7b2be6cab7b7035bb2b9b84 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 16:23:43 +0100 Subject: [PATCH 060/118] build(macos): serialize epiccash cargo build to avoid openssl jobserver races --- scripts/patches/flutter_libepiccash_macos_build_all.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/patches/flutter_libepiccash_macos_build_all.sh b/scripts/patches/flutter_libepiccash_macos_build_all.sh index 6a5917b1e..948e5e88c 100644 --- a/scripts/patches/flutter_libepiccash_macos_build_all.sh +++ b/scripts/patches/flutter_libepiccash_macos_build_all.sh @@ -20,6 +20,8 @@ cp -r ../../rust build/rust cd build/rust mkdir -p target +unset MAKEFLAGS MFLAGS CARGO_MAKEFLAGS +export CARGO_BUILD_JOBS=1 cargo lipo --release --targets aarch64-apple-darwin cbindgen --config cbindgen.toml --crate epic-cash-wallet --output target/epic_cash_wallet.h From 64d42625283c71b50b8e4019e17bedd5e276cdba Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 16:39:06 +0100 Subject: [PATCH 061/118] build(macos): sanitize cargo env to prevent openssl/lmdb race failures under nix --- scripts/patches/flutter_libepiccash_macos_build_all.sh | 6 ++++-- scripts/patches/flutter_libmwc_macos_build_all.sh | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/patches/flutter_libepiccash_macos_build_all.sh b/scripts/patches/flutter_libepiccash_macos_build_all.sh index 948e5e88c..35442dd9c 100644 --- a/scripts/patches/flutter_libepiccash_macos_build_all.sh +++ b/scripts/patches/flutter_libepiccash_macos_build_all.sh @@ -20,9 +20,11 @@ cp -r ../../rust build/rust cd build/rust mkdir -p target -unset MAKEFLAGS MFLAGS CARGO_MAKEFLAGS +unset MAKEFLAGS MFLAGS CARGO_MAKEFLAGS MAKELEVEL MAKE_TERMOUT MAKE_TERMERR export CARGO_BUILD_JOBS=1 -cargo lipo --release --targets aarch64-apple-darwin +export MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-11.0}" +env -u MAKEFLAGS -u MFLAGS -u CARGO_MAKEFLAGS -u MAKELEVEL -u MAKE_TERMOUT -u MAKE_TERMERR \ + cargo lipo --release --targets aarch64-apple-darwin cbindgen --config cbindgen.toml --crate epic-cash-wallet --output target/epic_cash_wallet.h cp target/epic_cash_wallet.h libepic_cash_wallet.h diff --git a/scripts/patches/flutter_libmwc_macos_build_all.sh b/scripts/patches/flutter_libmwc_macos_build_all.sh index 02243d9cf..fcdd00cfe 100644 --- a/scripts/patches/flutter_libmwc_macos_build_all.sh +++ b/scripts/patches/flutter_libmwc_macos_build_all.sh @@ -21,12 +21,14 @@ cd build/rust # some people need this apparently export PROTOC=/opt/homebrew/bin/protoc -unset MAKEFLAGS MFLAGS CARGO_MAKEFLAGS +unset MAKEFLAGS MFLAGS CARGO_MAKEFLAGS MAKELEVEL MAKE_TERMOUT MAKE_TERMERR export CARGO_BUILD_JOBS=1 +export MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-11.0}" # building cbindgen src/lib.rs -l c > libmwc_wallet.h -cargo lipo --release --targets aarch64-apple-darwin +env -u MAKEFLAGS -u MFLAGS -u CARGO_MAKEFLAGS -u MAKELEVEL -u MAKE_TERMOUT -u MAKE_TERMERR \ + cargo lipo --release --targets aarch64-apple-darwin xcodebuild -create-xcframework \ -library target/aarch64-apple-darwin/release/libmwc_wallet.a \ From d10230e5636bb785b2996ee713ca5b1e72a9031f Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 16:43:10 +0100 Subject: [PATCH 062/118] build(macos): validate epiccash combined archive and fallback on failure --- .../flutter_libepiccash_macos_build_all.sh | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/scripts/patches/flutter_libepiccash_macos_build_all.sh b/scripts/patches/flutter_libepiccash_macos_build_all.sh index 35442dd9c..cc9f4e3cb 100644 --- a/scripts/patches/flutter_libepiccash_macos_build_all.sh +++ b/scripts/patches/flutter_libepiccash_macos_build_all.sh @@ -35,10 +35,22 @@ cp target/epic_cash_wallet.h ../../../../macos/Classes/FlutterLibepiccashPlugin. RANDOMX_LIB=$(find target/aarch64-apple-darwin/release/build -name "librandomx.a" | head -n 1 || true) if [ -n "${RANDOMX_LIB}" ] && [ -f "${RANDOMX_LIB}" ]; then echo "Found RandomX library at: ${RANDOMX_LIB}" - /usr/bin/libtool -static -o target/aarch64-apple-darwin/release/libepic_cash_wallet_combined.a \ - target/aarch64-apple-darwin/release/libepic_cash_wallet.a \ - "${RANDOMX_LIB}" - MAIN_LIB=target/aarch64-apple-darwin/release/libepic_cash_wallet_combined.a + COMBINED_LIB=target/aarch64-apple-darwin/release/libepic_cash_wallet_combined.a + if /usr/bin/libtool -static -o "${COMBINED_LIB}" \ + target/aarch64-apple-darwin/release/libepic_cash_wallet.a \ + "${RANDOMX_LIB}" && \ + [ -f "${COMBINED_LIB}" ]; then + /usr/bin/ranlib "${COMBINED_LIB}" || true + if /usr/bin/ar -t "${COMBINED_LIB}" >/dev/null 2>&1; then + MAIN_LIB="${COMBINED_LIB}" + else + echo "Warning: combined archive is invalid, falling back to libepic_cash_wallet.a" + MAIN_LIB=target/aarch64-apple-darwin/release/libepic_cash_wallet.a + fi + else + echo "Warning: failed to create combined archive, falling back to libepic_cash_wallet.a" + MAIN_LIB=target/aarch64-apple-darwin/release/libepic_cash_wallet.a + fi else echo "Warning: librandomx.a not found, using libepic_cash_wallet.a only" MAIN_LIB=target/aarch64-apple-darwin/release/libepic_cash_wallet.a From 0bfb888a0f7595ad77a1aa4983f9b3ba4d2a831f Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 16:45:11 +0100 Subject: [PATCH 063/118] build(macos): replace cargo lipo with cargo build for stable nix arm64 builds --- scripts/patches/flutter_libepiccash_macos_build_all.sh | 2 +- scripts/patches/flutter_libmwc_macos_build_all.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/patches/flutter_libepiccash_macos_build_all.sh b/scripts/patches/flutter_libepiccash_macos_build_all.sh index cc9f4e3cb..29e361e31 100644 --- a/scripts/patches/flutter_libepiccash_macos_build_all.sh +++ b/scripts/patches/flutter_libepiccash_macos_build_all.sh @@ -24,7 +24,7 @@ unset MAKEFLAGS MFLAGS CARGO_MAKEFLAGS MAKELEVEL MAKE_TERMOUT MAKE_TERMERR export CARGO_BUILD_JOBS=1 export MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-11.0}" env -u MAKEFLAGS -u MFLAGS -u CARGO_MAKEFLAGS -u MAKELEVEL -u MAKE_TERMOUT -u MAKE_TERMERR \ - cargo lipo --release --targets aarch64-apple-darwin + cargo build --release --target aarch64-apple-darwin --lib cbindgen --config cbindgen.toml --crate epic-cash-wallet --output target/epic_cash_wallet.h cp target/epic_cash_wallet.h libepic_cash_wallet.h diff --git a/scripts/patches/flutter_libmwc_macos_build_all.sh b/scripts/patches/flutter_libmwc_macos_build_all.sh index fcdd00cfe..4d170f6d6 100644 --- a/scripts/patches/flutter_libmwc_macos_build_all.sh +++ b/scripts/patches/flutter_libmwc_macos_build_all.sh @@ -28,7 +28,7 @@ export MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-11.0}" # building cbindgen src/lib.rs -l c > libmwc_wallet.h env -u MAKEFLAGS -u MFLAGS -u CARGO_MAKEFLAGS -u MAKELEVEL -u MAKE_TERMOUT -u MAKE_TERMERR \ - cargo lipo --release --targets aarch64-apple-darwin + cargo build --release --target aarch64-apple-darwin --lib xcodebuild -create-xcframework \ -library target/aarch64-apple-darwin/release/libmwc_wallet.a \ From 2b3ed0921f3860c4d76cc91170fdebe23d11a219 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 16:48:57 +0100 Subject: [PATCH 064/118] build(macos): stabilize epiccash cargo target dir and retry on transient deps-dir race --- .../flutter_libepiccash_macos_build_all.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/scripts/patches/flutter_libepiccash_macos_build_all.sh b/scripts/patches/flutter_libepiccash_macos_build_all.sh index 29e361e31..4e065fc07 100644 --- a/scripts/patches/flutter_libepiccash_macos_build_all.sh +++ b/scripts/patches/flutter_libepiccash_macos_build_all.sh @@ -23,8 +23,19 @@ mkdir -p target unset MAKEFLAGS MFLAGS CARGO_MAKEFLAGS MAKELEVEL MAKE_TERMOUT MAKE_TERMERR export CARGO_BUILD_JOBS=1 export MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-11.0}" -env -u MAKEFLAGS -u MFLAGS -u CARGO_MAKEFLAGS -u MAKELEVEL -u MAKE_TERMOUT -u MAKE_TERMERR \ - cargo build --release --target aarch64-apple-darwin --lib +export CARGO_TARGET_DIR="$(pwd)/target" +mkdir -p "${CARGO_TARGET_DIR}/aarch64-apple-darwin/release/deps" + +run_cargo_build() { + env -u MAKEFLAGS -u MFLAGS -u CARGO_MAKEFLAGS -u MAKELEVEL -u MAKE_TERMOUT -u MAKE_TERMERR \ + cargo build --release --target aarch64-apple-darwin --lib +} + +if ! run_cargo_build; then + echo "Warning: cargo build failed once; retrying after recreating target dirs..." + mkdir -p "${CARGO_TARGET_DIR}/aarch64-apple-darwin/release/deps" + run_cargo_build +fi cbindgen --config cbindgen.toml --crate epic-cash-wallet --output target/epic_cash_wallet.h cp target/epic_cash_wallet.h libepic_cash_wallet.h From e4b05e974fd53ce2a46b1935bd77bf1564339761 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 17:41:13 +0100 Subject: [PATCH 065/118] build(macos): restore automatic cargo parallelism while keeping nix env safeguards --- Makefile | 1 - .../flutter_libepiccash_macos_build_all.sh | 16 ++++++++-------- .../patches/flutter_libmwc_macos_build_all.sh | 1 - 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index f319d8d98..2ff239932 100644 --- a/Makefile +++ b/Makefile @@ -184,7 +184,6 @@ macos-build-native: MAKEFLAGS= \ MFLAGS= \ CARGO_MAKEFLAGS= \ - CARGO_BUILD_JOBS=1 \ CC="/usr/bin/clang" \ CXX="/usr/bin/clang++" \ AR="/usr/bin/ar" \ diff --git a/scripts/patches/flutter_libepiccash_macos_build_all.sh b/scripts/patches/flutter_libepiccash_macos_build_all.sh index 4e065fc07..0697c6afd 100644 --- a/scripts/patches/flutter_libepiccash_macos_build_all.sh +++ b/scripts/patches/flutter_libepiccash_macos_build_all.sh @@ -21,9 +21,8 @@ cd build/rust mkdir -p target unset MAKEFLAGS MFLAGS CARGO_MAKEFLAGS MAKELEVEL MAKE_TERMOUT MAKE_TERMERR -export CARGO_BUILD_JOBS=1 export MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-11.0}" -export CARGO_TARGET_DIR="$(pwd)/target" +export CARGO_TARGET_DIR="$(mktemp -d "${TMPDIR:-/tmp}/epiccash-target.XXXXXX")" mkdir -p "${CARGO_TARGET_DIR}/aarch64-apple-darwin/release/deps" run_cargo_build() { @@ -43,12 +42,13 @@ mkdir -p Headers cp target/epic_cash_wallet.h Headers/libepic_cash_wallet.h cp target/epic_cash_wallet.h ../../../../macos/Classes/FlutterLibepiccashPlugin.h -RANDOMX_LIB=$(find target/aarch64-apple-darwin/release/build -name "librandomx.a" | head -n 1 || true) +BASE_LIB="${CARGO_TARGET_DIR}/aarch64-apple-darwin/release/libepic_cash_wallet.a" +RANDOMX_LIB=$(find "${CARGO_TARGET_DIR}/aarch64-apple-darwin/release/build" -name "librandomx.a" | head -n 1 || true) if [ -n "${RANDOMX_LIB}" ] && [ -f "${RANDOMX_LIB}" ]; then echo "Found RandomX library at: ${RANDOMX_LIB}" - COMBINED_LIB=target/aarch64-apple-darwin/release/libepic_cash_wallet_combined.a + COMBINED_LIB="${CARGO_TARGET_DIR}/aarch64-apple-darwin/release/libepic_cash_wallet_combined.a" if /usr/bin/libtool -static -o "${COMBINED_LIB}" \ - target/aarch64-apple-darwin/release/libepic_cash_wallet.a \ + "${BASE_LIB}" \ "${RANDOMX_LIB}" && \ [ -f "${COMBINED_LIB}" ]; then /usr/bin/ranlib "${COMBINED_LIB}" || true @@ -56,15 +56,15 @@ if [ -n "${RANDOMX_LIB}" ] && [ -f "${RANDOMX_LIB}" ]; then MAIN_LIB="${COMBINED_LIB}" else echo "Warning: combined archive is invalid, falling back to libepic_cash_wallet.a" - MAIN_LIB=target/aarch64-apple-darwin/release/libepic_cash_wallet.a + MAIN_LIB="${BASE_LIB}" fi else echo "Warning: failed to create combined archive, falling back to libepic_cash_wallet.a" - MAIN_LIB=target/aarch64-apple-darwin/release/libepic_cash_wallet.a + MAIN_LIB="${BASE_LIB}" fi else echo "Warning: librandomx.a not found, using libepic_cash_wallet.a only" - MAIN_LIB=target/aarch64-apple-darwin/release/libepic_cash_wallet.a + MAIN_LIB="${BASE_LIB}" fi xcodebuild -create-xcframework \ diff --git a/scripts/patches/flutter_libmwc_macos_build_all.sh b/scripts/patches/flutter_libmwc_macos_build_all.sh index 4d170f6d6..c7fc2541c 100644 --- a/scripts/patches/flutter_libmwc_macos_build_all.sh +++ b/scripts/patches/flutter_libmwc_macos_build_all.sh @@ -22,7 +22,6 @@ cd build/rust # some people need this apparently export PROTOC=/opt/homebrew/bin/protoc unset MAKEFLAGS MFLAGS CARGO_MAKEFLAGS MAKELEVEL MAKE_TERMOUT MAKE_TERMERR -export CARGO_BUILD_JOBS=1 export MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-11.0}" # building From 41455bb2b07c8faf83b2be52d2796e24106f62db Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 17:58:47 +0100 Subject: [PATCH 066/118] build-linux: normalize linux shebangs for nixos --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 2ff239932..0fedd91ac 100644 --- a/Makefile +++ b/Makefile @@ -92,6 +92,8 @@ patch-submodules: ## Apply portability patches to submodules @sed -i.bak 's|cbindgen --config cbindgen.toml --crate epic-cash-wallet --output target/epic_cash_wallet.h|cbindgen --config cbindgen.toml --crate epic-cash-wallet --output target/epic_cash_wallet.h \&\& cp target/epic_cash_wallet.h libepic_cash_wallet.h|g' crypto_plugins/flutter_libepiccash/scripts/macos/build_all.sh 2>/dev/null || true @echo "Fixing Frostdart binary path..." @find crypto_plugins/frostdart/scripts -name "build_all.sh" -exec perl -0777 -i.bak -pe 's|^.*dart\s+build_|dart build_|mg' {} + 2>/dev/null || true + @echo "Normalizing Linux script shebangs for NixOS..." + @find crypto_plugins -path "*/scripts/linux/*.sh" -type f -exec sed -i.bak '1s|^#!/bin/bash$$|#!/usr/bin/env bash|' {} + 2>/dev/null || true @# GNU/BSD sed compatibility: ensure Frostdart macOS script uses -i.bak form. @perl -0777 -i.bak -pe 's/_run\("sed",\s*\["-i"\s*,\s*"\.bak"\s*,\s*"s\/frostdart\/hrf-api\/",\s*"cargo\.toml"\]\);/_run("sed", ["-i.bak", "s\/frostdart\/hrf-api\/", "cargo.toml"]);/g' crypto_plugins/frostdart/scripts/macos/build_macos.dart 2>/dev/null || true @echo "Disabling strict Rust checks..." From f2f79d354377e307047163171356a22aea8cfe97 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 18:15:48 +0100 Subject: [PATCH 067/118] build-linux: skip coinlib build when no container runtime --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0fedd91ac..c0ad947cc 100644 --- a/Makefile +++ b/Makefile @@ -245,7 +245,11 @@ build-linux: check-reqs init patch-submodules ## Build Linux Release @cd scripts && yes yes | BUILD_ISAR_FROM_SOURCE=0 PROTOC="$(PROTOC_PATH)" ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f @echo "--- Building app..." @$(FLUTTER) pub get - @$(FLUTTER) pub run coinlib:build_linux + @if command -v podman >/dev/null 2>&1 || command -v docker >/dev/null 2>&1; then \ + $(DART) run coinlib:build_linux; \ + else \ + echo "[WARN] podman/docker not found; skipping coinlib:build_linux"; \ + fi @$(FLUTTER) build linux --release build-android: check-reqs init ## Build Android APK From d807217a6b3af8a6ea8c102010c3f2f7900aa1b2 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 18:22:58 +0100 Subject: [PATCH 068/118] linux: generate local libsecret pkg-config metadata --- scripts/linux/build_secure_storage_deps.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/scripts/linux/build_secure_storage_deps.sh b/scripts/linux/build_secure_storage_deps.sh index 4cc62e7d2..4069412db 100755 --- a/scripts/linux/build_secure_storage_deps.sh +++ b/scripts/linux/build_secure_storage_deps.sh @@ -44,3 +44,19 @@ if ! [ -x "$(command -v ninja)" ]; then exit 1 fi ninja -C _build + +# Publish a local pkg-config file that points at the locally built libsecret. +# This avoids relying on distro-specific libsecret/glib pkg-config metadata. +mkdir -p "$LINUX_DIRECTORY/pc" +cat > "$LINUX_DIRECTORY/pc/libsecret-1.pc" < Date: Tue, 17 Mar 2026 18:29:21 +0100 Subject: [PATCH 069/118] build-linux: export local libsecret pkg-config for flutter --- Makefile | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c0ad947cc..a90559710 100644 --- a/Makefile +++ b/Makefile @@ -245,12 +245,26 @@ build-linux: check-reqs init patch-submodules ## Build Linux Release @cd scripts && yes yes | BUILD_ISAR_FROM_SOURCE=0 PROTOC="$(PROTOC_PATH)" ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f @echo "--- Building app..." @$(FLUTTER) pub get + @mkdir -p scripts/linux/pc + @cat > scripts/linux/pc/libsecret-1.pc </dev/null 2>&1 || command -v docker >/dev/null 2>&1; then \ $(DART) run coinlib:build_linux; \ else \ echo "[WARN] podman/docker not found; skipping coinlib:build_linux"; \ fi - @$(FLUTTER) build linux --release + @PKG_CONFIG_PATH="$(CURDIR)/scripts/linux/pc:$(CURDIR)/scripts/linux/build/libsecret/_build/meson-uninstalled:$$PKG_CONFIG_PATH" \ + $(FLUTTER) build linux --release build-android: check-reqs init ## Build Android APK @echo "--- Configuring project..." From 4159e4b00af4c11f6d832d68575f9d3c53f0e599 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 18:30:34 +0100 Subject: [PATCH 070/118] makefile: fix build-linux recipe separator regression --- Makefile | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index a90559710..81a9d899c 100644 --- a/Makefile +++ b/Makefile @@ -246,18 +246,18 @@ build-linux: check-reqs init patch-submodules ## Build Linux Release @echo "--- Building app..." @$(FLUTTER) pub get @mkdir -p scripts/linux/pc - @cat > scripts/linux/pc/libsecret-1.pc < scripts/linux/pc/libsecret-1.pc @if command -v podman >/dev/null 2>&1 || command -v docker >/dev/null 2>&1; then \ $(DART) run coinlib:build_linux; \ else \ From 7f43e1a0e7942a9c2f1d037849221039b61c2290 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Tue, 17 Mar 2026 18:37:07 +0100 Subject: [PATCH 071/118] build-linux: preflight libsecret pkg-config resolution --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 81a9d899c..3d356716b 100644 --- a/Makefile +++ b/Makefile @@ -263,6 +263,9 @@ build-linux: check-reqs init patch-submodules ## Build Linux Release else \ echo "[WARN] podman/docker not found; skipping coinlib:build_linux"; \ fi + @PKG_CONFIG_PATH="$(CURDIR)/scripts/linux/pc:$(CURDIR)/scripts/linux/build/libsecret/_build/meson-uninstalled:$$PKG_CONFIG_PATH" \ + pkg-config --modversion libsecret-1 >/dev/null || \ + { echo "[ERROR] libsecret-1 not resolvable via pkg-config"; exit 1; } @PKG_CONFIG_PATH="$(CURDIR)/scripts/linux/pc:$(CURDIR)/scripts/linux/build/libsecret/_build/meson-uninstalled:$$PKG_CONFIG_PATH" \ $(FLUTTER) build linux --release From 468b6012d9cfd18350891e38b29ccd2d17d2996a Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Wed, 18 Mar 2026 02:10:52 +0100 Subject: [PATCH 072/118] build-linux: disable pkg-config uninstalled resolution --- Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3d356716b..c5772bf57 100644 --- a/Makefile +++ b/Makefile @@ -263,10 +263,12 @@ build-linux: check-reqs init patch-submodules ## Build Linux Release else \ echo "[WARN] podman/docker not found; skipping coinlib:build_linux"; \ fi - @PKG_CONFIG_PATH="$(CURDIR)/scripts/linux/pc:$(CURDIR)/scripts/linux/build/libsecret/_build/meson-uninstalled:$$PKG_CONFIG_PATH" \ + @PKG_CONFIG_DISABLE_UNINSTALLED=1 \ + PKG_CONFIG_PATH="$(CURDIR)/scripts/linux/pc:$$PKG_CONFIG_PATH" \ pkg-config --modversion libsecret-1 >/dev/null || \ { echo "[ERROR] libsecret-1 not resolvable via pkg-config"; exit 1; } - @PKG_CONFIG_PATH="$(CURDIR)/scripts/linux/pc:$(CURDIR)/scripts/linux/build/libsecret/_build/meson-uninstalled:$$PKG_CONFIG_PATH" \ + @PKG_CONFIG_DISABLE_UNINSTALLED=1 \ + PKG_CONFIG_PATH="$(CURDIR)/scripts/linux/pc:$$PKG_CONFIG_PATH" \ $(FLUTTER) build linux --release build-android: check-reqs init ## Build Android APK From 172803f9bb55654132d7b8c7cf3ba24dfde83cb5 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Wed, 18 Mar 2026 02:13:23 +0100 Subject: [PATCH 073/118] check-reqs: require meson and ninja for linux builds --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index c5772bf57..6205a2a73 100644 --- a/Makefile +++ b/Makefile @@ -41,6 +41,8 @@ check-reqs: ## Verify essential build tools @rustup run stable rustc -vV >/dev/null 2>&1 || { echo >&2 "[ERROR] rustup stable toolchain not available."; exit 1; } @command -v go >/dev/null 2>&1 || { echo >&2 "[ERROR] Go not installed."; exit 1; } @command -v cmake >/dev/null 2>&1 || { echo >&2 "[ERROR] CMake not installed."; exit 1; } + @command -v meson >/dev/null 2>&1 || { echo >&2 "[ERROR] Meson not installed. On NixOS, run in 'nix develop' or install meson permanently."; exit 1; } + @command -v ninja >/dev/null 2>&1 || { echo >&2 "[ERROR] Ninja not installed. On NixOS, run in 'nix develop' or install ninja permanently."; exit 1; } @command -v pkg-config >/dev/null 2>&1 || { echo >&2 "[ERROR] pkg-config not installed."; exit 1; } ifeq ($(shell uname),Darwin) @command -v autoreconf >/dev/null 2>&1 || { echo >&2 "[ERROR] autoconf/autoreconf not installed."; exit 1; } From 3650d18dbd6623ff2b27a468eb1d3c6933444282 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Wed, 18 Mar 2026 02:38:26 +0100 Subject: [PATCH 074/118] nix: add opencv and sysprof packages to linux dev shell --- flake.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/flake.nix b/flake.nix index f9312952a..3bfd7bad8 100644 --- a/flake.nix +++ b/flake.nix @@ -33,6 +33,9 @@ llvmPackages.libclang llvmPackages.clang protobuf + opencv + sysprof + libsysprof-capture ]); macPackages = lib.optionals pkgs.stdenv.isDarwin (with pkgs; [ From aebfb7c51d06add5c25ac1e8ef42669614de6e47 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Wed, 18 Mar 2026 02:53:22 +0100 Subject: [PATCH 075/118] build-linux: run prebuild bootstrap before config --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 6205a2a73..acfea614f 100644 --- a/Makefile +++ b/Makefile @@ -242,6 +242,8 @@ build-ios: check-reqs check-macos-sdk init ## Build iOS Release @$(FLUTTER) build ios --release --no-codesign build-linux: check-reqs init patch-submodules ## Build Linux Release + @echo "--- Running prebuild bootstrap..." + @cd scripts && bash prebuild.sh @echo "--- Generating config..." @if [ -z "$(PROTOC_PATH)" ]; then echo "[ERROR] protoc not found!"; exit 1; fi @cd scripts && yes yes | BUILD_ISAR_FROM_SOURCE=0 PROTOC="$(PROTOC_PATH)" ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f From a448a92b4ce862278237045292270c25a8e1b211 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Wed, 18 Mar 2026 03:01:21 +0100 Subject: [PATCH 076/118] build-linux: recreate external_api_keys template before flutter --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index acfea614f..46dc3bab8 100644 --- a/Makefile +++ b/Makefile @@ -248,6 +248,10 @@ build-linux: check-reqs init patch-submodules ## Build Linux Release @if [ -z "$(PROTOC_PATH)" ]; then echo "[ERROR] protoc not found!"; exit 1; fi @cd scripts && yes yes | BUILD_ISAR_FROM_SOURCE=0 PROTOC="$(PROTOC_PATH)" ./build_app.sh -a $(APP_NAME) -p linux -v $(VERSION) -b $(BUILD_NUM) -f @echo "--- Building app..." + @if [ ! -f lib/external_api_keys.dart ]; then \ + echo "[WARN] lib/external_api_keys.dart missing; recreating template."; \ + printf 'const kChangeNowApiKey = "";\nconst kSimpleSwapApiKey = "";\nconst kNanswapApiKey = "";\nconst kNanoSwapRpcApiKey = "";\nconst kWizSwapApiKey = "";\n' > lib/external_api_keys.dart; \ + fi @$(FLUTTER) pub get @mkdir -p scripts/linux/pc @printf '%s\n' \ From 0d36a9ac365144fdad7fa4a4363d9449ab06d727 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Wed, 18 Mar 2026 03:10:30 +0100 Subject: [PATCH 077/118] build-linux: force deterministic pkg-config libdir on nix --- Makefile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 46dc3bab8..5e2154dbd 100644 --- a/Makefile +++ b/Makefile @@ -271,12 +271,18 @@ build-linux: check-reqs init patch-submodules ## Build Linux Release else \ echo "[WARN] podman/docker not found; skipping coinlib:build_linux"; \ fi - @PKG_CONFIG_DISABLE_UNINSTALLED=1 \ - PKG_CONFIG_PATH="$(CURDIR)/scripts/linux/pc:$$PKG_CONFIG_PATH" \ + @SYSPROF_PC_DIR=$$(dirname "$$(find /nix/store -path '*/lib/pkgconfig/sysprof-capture-4.pc' 2>/dev/null | head -n1)"); \ + PC_PATH=$$(pkg-config --variable=pc_path pkg-config 2>/dev/null || echo ""); \ + PKG_CONFIG_DISABLE_UNINSTALLED=1 \ + PKG_CONFIG_PATH= \ + PKG_CONFIG_LIBDIR="$(CURDIR)/scripts/linux/pc:$$SYSPROF_PC_DIR:$$PC_PATH" \ pkg-config --modversion libsecret-1 >/dev/null || \ { echo "[ERROR] libsecret-1 not resolvable via pkg-config"; exit 1; } - @PKG_CONFIG_DISABLE_UNINSTALLED=1 \ - PKG_CONFIG_PATH="$(CURDIR)/scripts/linux/pc:$$PKG_CONFIG_PATH" \ + @SYSPROF_PC_DIR=$$(dirname "$$(find /nix/store -path '*/lib/pkgconfig/sysprof-capture-4.pc' 2>/dev/null | head -n1)"); \ + PC_PATH=$$(pkg-config --variable=pc_path pkg-config 2>/dev/null || echo ""); \ + PKG_CONFIG_DISABLE_UNINSTALLED=1 \ + PKG_CONFIG_PATH= \ + PKG_CONFIG_LIBDIR="$(CURDIR)/scripts/linux/pc:$$SYSPROF_PC_DIR:$$PC_PATH" \ $(FLUTTER) build linux --release build-android: check-reqs init ## Build Android APK From 522f32c2c0ebf755d408b821748ccd1a7176835e Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Wed, 18 Mar 2026 03:29:09 +0100 Subject: [PATCH 078/118] linux: ignore deprecated literal operator warning as error --- scripts/app_config/templates/linux/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/app_config/templates/linux/CMakeLists.txt b/scripts/app_config/templates/linux/CMakeLists.txt index d1c69c17f..d1429c852 100644 --- a/scripts/app_config/templates/linux/CMakeLists.txt +++ b/scripts/app_config/templates/linux/CMakeLists.txt @@ -45,6 +45,8 @@ endif() function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_14) target_compile_options(${TARGET} PRIVATE -Wall -Werror) + # nlohmann::json UDL declarations trigger this warning on newer clang/gcc. + target_compile_options(${TARGET} PRIVATE -Wno-error=deprecated-literal-operator) target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") endfunction() From ad79a1e8cda55e483291dda61429aa02685860ce Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Wed, 18 Mar 2026 03:39:28 +0100 Subject: [PATCH 079/118] linux: force local CMake install prefix for bundle builds --- scripts/app_config/templates/linux/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/app_config/templates/linux/CMakeLists.txt b/scripts/app_config/templates/linux/CMakeLists.txt index d1429c852..8f70ca128 100644 --- a/scripts/app_config/templates/linux/CMakeLists.txt +++ b/scripts/app_config/templates/linux/CMakeLists.txt @@ -135,9 +135,9 @@ include(flutter/generated_plugins.cmake) # By default, "installing" just makes a relocatable bundle in the build # directory. set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() +# Always install into the local build bundle. On NixOS and other constrained +# environments, inheriting /usr/local causes permission failures at install. +set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) # Start with a clean build bundle directory every time. install(CODE " From 6e99dc7ef0afe17e91c863b94cb3252d90264d0a Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Wed, 18 Mar 2026 03:49:19 +0100 Subject: [PATCH 080/118] linux: stage secp256k1 shared lib at CMake install path --- scripts/linux/build_secp256k1.sh | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) mode change 100755 => 100644 scripts/linux/build_secp256k1.sh diff --git a/scripts/linux/build_secp256k1.sh b/scripts/linux/build_secp256k1.sh old mode 100755 new mode 100644 index 19850db78..5e3be13bd --- a/scripts/linux/build_secp256k1.sh +++ b/scripts/linux/build_secp256k1.sh @@ -1,15 +1,32 @@ +#!/usr/bin/env bash +set -e + mkdir -p build cd build + if [ ! -d "secp256k1" ]; then git clone https://github.com/bitcoin-core/secp256k1 fi + cd secp256k1 git checkout 68b55209f1ba3e6c0417789598f5f75649e9c14c git reset --hard -mkdir -p build && cd build + +mkdir -p build +cd build cmake .. cmake --build . + +SECP_SO="$(find lib -maxdepth 1 -type f -name 'libsecp256k1.so*' | sort | head -n1)" +if [ -z "$SECP_SO" ]; then + echo "[ERROR] libsecp256k1 shared library not found after build." + exit 1 +fi + +# Legacy location used by parts of the build pipeline. mkdir -p ../../../../../build -cp lib/libsecp256k1.so.2.*.* "../../../../../build/libsecp256k1.so" -cd ../../../ -#!/usr/bin/env bash +cp "$SECP_SO" ../../../../../build/libsecp256k1.so + +# Location expected by Flutter/CMake install step. +mkdir -p ../../../../../build/linux/x64/release/secp256k1/lib +cp "$SECP_SO" ../../../../../build/linux/x64/release/secp256k1/lib/libsecp256k1.so From 6eb985607d37cdbc91f0a2a62e09096e3982d5f1 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Wed, 18 Mar 2026 03:49:35 +0100 Subject: [PATCH 081/118] linux: restore executable bit on secp256k1 builder --- scripts/linux/build_secp256k1.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 scripts/linux/build_secp256k1.sh diff --git a/scripts/linux/build_secp256k1.sh b/scripts/linux/build_secp256k1.sh old mode 100644 new mode 100755 From 4e1a4769c56eb917c31cf6cf9b0a1b8ae5584fb2 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Wed, 18 Mar 2026 05:34:30 +0100 Subject: [PATCH 082/118] macos: add bootstrap target and install meson --- Makefile | 28 +++++++++++++++++++++++++--- scripts/install_macos_build_tools.sh | 2 +- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 5e2154dbd..ba8a9bbed 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ MACOS_ENV_SET = MACOSX_DEPLOYMENT_TARGET=11.0 export APP_PROJECT_ROOT_DIR export PUB_CACHE -.PHONY: help check-reqs check-reqs-windows check-macos-sdk init clean prebuild-unix prebuild-windows deps-linux patch-submodules \ +.PHONY: help check-reqs check-reqs-windows check-macos-sdk bootstrap-macos init clean prebuild-unix prebuild-windows deps-linux patch-submodules \ build-linux build-macos build-ios build-android build-windows \ macos-prepare macos-configure macos-restore-metadata macos-build-native macos-build-app diagnose-macos-env @@ -41,8 +41,22 @@ check-reqs: ## Verify essential build tools @rustup run stable rustc -vV >/dev/null 2>&1 || { echo >&2 "[ERROR] rustup stable toolchain not available."; exit 1; } @command -v go >/dev/null 2>&1 || { echo >&2 "[ERROR] Go not installed."; exit 1; } @command -v cmake >/dev/null 2>&1 || { echo >&2 "[ERROR] CMake not installed."; exit 1; } - @command -v meson >/dev/null 2>&1 || { echo >&2 "[ERROR] Meson not installed. On NixOS, run in 'nix develop' or install meson permanently."; exit 1; } - @command -v ninja >/dev/null 2>&1 || { echo >&2 "[ERROR] Ninja not installed. On NixOS, run in 'nix develop' or install ninja permanently."; exit 1; } + @command -v meson >/dev/null 2>&1 || { \ + if [ "$(shell uname)" = "Darwin" ]; then \ + echo >&2 "[ERROR] Meson not installed. On macOS, run 'make bootstrap-macos' or 'brew install meson'."; \ + else \ + echo >&2 "[ERROR] Meson not installed. On NixOS, run in 'nix develop' or install meson permanently."; \ + fi; \ + exit 1; \ + } + @command -v ninja >/dev/null 2>&1 || { \ + if [ "$(shell uname)" = "Darwin" ]; then \ + echo >&2 "[ERROR] Ninja not installed. On macOS, run 'make bootstrap-macos' or 'brew install ninja'."; \ + else \ + echo >&2 "[ERROR] Ninja not installed. On NixOS, run in 'nix develop' or install ninja permanently."; \ + fi; \ + exit 1; \ + } @command -v pkg-config >/dev/null 2>&1 || { echo >&2 "[ERROR] pkg-config not installed."; exit 1; } ifeq ($(shell uname),Darwin) @command -v autoreconf >/dev/null 2>&1 || { echo >&2 "[ERROR] autoconf/autoreconf not installed."; exit 1; } @@ -59,6 +73,14 @@ ifeq ($(shell uname),Darwin) @echo "[OK] Xcode SDK path looks good." endif +bootstrap-macos: ## Install required macOS build tools via Homebrew helper script +ifeq ($(shell uname),Darwin) + @bash scripts/install_macos_build_tools.sh +else + @echo "[ERROR] bootstrap-macos is macOS-only." + @exit 1 +endif + check-reqs-windows: ## Verify Windows/WSL requirements @echo "Checking Windows prerequisites..." @command -v wsl >/dev/null 2>&1 || { echo >&2 "[ERROR] WSL is not installed."; exit 1; } diff --git a/scripts/install_macos_build_tools.sh b/scripts/install_macos_build_tools.sh index c5be09ae6..276a863a9 100755 --- a/scripts/install_macos_build_tools.sh +++ b/scripts/install_macos_build_tools.sh @@ -13,7 +13,7 @@ if ! command -v brew >/dev/null 2>&1; then fi echo "Installing Homebrew packages..." -brew install direnv rustup-init cmake ninja pkg-config gnu-sed cocoapods go protobuf autoconf automake libtool +brew install direnv rustup-init cmake meson ninja pkg-config gnu-sed cocoapods go protobuf autoconf automake libtool echo "Installing Flutter cask..." brew install --cask flutter From a77eff07453976b4933ab28fb2569a982ad264ee Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Thu, 19 Mar 2026 04:59:04 +0100 Subject: [PATCH 083/118] macos: replace pbxproj UUID patching with xcconfig overrides --- Makefile | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index ba8a9bbed..36152a51d 100644 --- a/Makefile +++ b/Makefile @@ -178,14 +178,19 @@ macos-restore-metadata: sed -i.bak -e '/Flutter-Release.xcconfig/a\ #include "AppInfo.xcconfig"' macos/Runner/Configs/Release.xcconfig 2>/dev/null || true @rm -f macos/Runner/Configs/Debug.xcconfig.bak macos/Runner/Configs/Release.xcconfig.bak - @# Runner target configs must inherit Debug/Release xcconfigs (not AppInfo) so Pods module paths are available. - @perl -0777 -i.bak -pe 's/(33CC10FC2044A3C60003C045 \/\* Debug \*\/ = \{\s*isa = XCBuildConfiguration;\s*)baseConfigurationReference = 33E5194F232828860026EE4D \/\* AppInfo\.xcconfig \*\//$${1}baseConfigurationReference = 9740EEB21CF90195004384FC \/\* Debug.xcconfig \*\//s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true - @perl -0777 -i.bak -pe 's/(33CC10FD2044A3C60003C045 \/\* Release \*\/ = \{\s*isa = XCBuildConfiguration;\s*)baseConfigurationReference = 33E5194F232828860026EE4D \/\* AppInfo\.xcconfig \*\//$${1}baseConfigurationReference = 7AFA3C8E1D35360C0083082E \/\* Release.xcconfig \*\//s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true - @perl -0777 -i.bak -pe 's/(338D0CEA231458BD00FA5F75 \/\* Profile \*\/ = \{\s*isa = XCBuildConfiguration;\s*)baseConfigurationReference = 33E5194F232828860026EE4D \/\* AppInfo\.xcconfig \*\//$${1}baseConfigurationReference = 7AFA3C8E1D35360C0083082E \/\* Release.xcconfig \*\//s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true - @# Force a valid Swift module identifier for Runner even when PRODUCT_NAME is space-separated. - @perl -0777 -i.bak -pe 's/(33CC10FC2044A3C60003C045 \/\* Debug \*\/ = \{\s*isa = XCBuildConfiguration;.*?buildSettings = \{.*?)(\n\s*PROVISIONING_PROFILE_SPECIFIER = "";)/$${1}\n\t\t\t\tPRODUCT_MODULE_NAME = stack_wallet;$${2}/s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true - @perl -0777 -i.bak -pe 's/(33CC10FD2044A3C60003C045 \/\* Release \*\/ = \{\s*isa = XCBuildConfiguration;.*?buildSettings = \{.*?)(\n\s*PROVISIONING_PROFILE_SPECIFIER = "";)/$${1}\n\t\t\t\tPRODUCT_MODULE_NAME = stack_wallet;$${2}/s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true - @perl -0777 -i.bak -pe 's/(338D0CEA231458BD00FA5F75 \/\* Profile \*\/ = \{\s*isa = XCBuildConfiguration;.*?buildSettings = \{.*?)(\n\s*PROVISIONING_PROFILE_SPECIFIER = "";)/$${1}\n\t\t\t\tPRODUCT_MODULE_NAME = stack_wallet;$${2}/s' macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true + @# Keep local build overrides in xcconfig instead of UUID-based pbxproj rewrites. + @printf '%s\n' \ + '// Auto-generated by Makefile (macos-restore-metadata)' \ + 'PRODUCT_MODULE_NAME = stack_wallet' \ + 'MACOSX_DEPLOYMENT_TARGET = 11.0' \ + > macos/Runner/Configs/CodexOverrides.xcconfig + @grep -q 'CodexOverrides.xcconfig' macos/Runner/Configs/Debug.xcconfig || \ + printf '\n#include "CodexOverrides.xcconfig"\n' >> macos/Runner/Configs/Debug.xcconfig + @grep -q 'CodexOverrides.xcconfig' macos/Runner/Configs/Release.xcconfig || \ + printf '\n#include "CodexOverrides.xcconfig"\n' >> macos/Runner/Configs/Release.xcconfig + @[ -f macos/Runner/Configs/Profile.xcconfig ] && \ + ( grep -q 'CodexOverrides.xcconfig' macos/Runner/Configs/Profile.xcconfig || \ + printf '\n#include "CodexOverrides.xcconfig"\n' >> macos/Runner/Configs/Profile.xcconfig ) || true @rm -f macos/Runner.xcodeproj/project.pbxproj.bak @$(FLUTTER) pub get @bash scripts/macos/patch_coinlib_podspec.sh From a2195348b7a7f3314d3d4205e7b13844e50efc20 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Thu, 19 Mar 2026 05:00:46 +0100 Subject: [PATCH 084/118] makefile: fallback to current dart/flutter when env path is stale --- Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 36152a51d..a7e1f2fa6 100644 --- a/Makefile +++ b/Makefile @@ -6,8 +6,12 @@ APP_NAME ?= stack_wallet VERSION ?= 2.1.0 BUILD_NUM ?= 210 -FLUTTER ?= flutter -DART ?= dart +FLUTTER ?= +DART ?= +FLUTTER_BIN := $(if $(and $(FLUTTER),$(wildcard $(FLUTTER))),$(FLUTTER),$(shell command -v flutter 2>/dev/null)) +DART_BIN := $(if $(and $(DART),$(wildcard $(DART))),$(DART),$(shell command -v dart 2>/dev/null)) +FLUTTER := $(FLUTTER_BIN) +DART := $(DART_BIN) PUB_CACHE ?= $(APP_PROJECT_ROOT_DIR)/.pub-cache APP_PROJECT_ROOT_DIR := $(CURDIR) PROTOC_PATH := $(shell which protoc 2>/dev/null) From 428fd61f909acffc4bdd7b5615ef21a3f5ec9eb5 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Thu, 19 Mar 2026 09:14:59 +0100 Subject: [PATCH 085/118] macos build: split bootstrap from host-agnostic build path --- .envrc | 99 +------------------------------------------------- Makefile | 107 ++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 88 insertions(+), 118 deletions(-) diff --git a/.envrc b/.envrc index fddb462e1..3550a30f2 100644 --- a/.envrc +++ b/.envrc @@ -1,98 +1 @@ -#!/usr/bin/env bash - -# ============================================================================== -# STACK WALLET AUTOMATIC ENV (direnv) -# ============================================================================== - -set -euo pipefail - -# 1. PATHS & BASICS -export APP_PROJECT_ROOT_DIR="$PWD" -PATH_add .direnv-bin -PATH_add "$HOME/.cargo/bin" -if [ -d "/opt/homebrew/opt/rustup/bin" ]; then - PATH_add /opt/homebrew/opt/rustup/bin -fi -if [ -f "$HOME/.cargo/env" ]; then - # shellcheck disable=SC1090 - source "$HOME/.cargo/env" -fi - -# 2. RUST TOOLCHAIN AUTOMATION -if command -v rustup >/dev/null 2>&1; then - REQUIRED_RUST=(1.89.0 1.85.1 1.81.0) - - for v in "${REQUIRED_RUST[@]}"; do - if ! rustup toolchain list | grep -q "$v"; then - echo "Installing missing Rust version: $v..." - rustup install "$v" - fi - done - - rustup default 1.89.0 - rustup target add aarch64-apple-darwin aarch64-apple-ios >/dev/null 2>&1 || true - - if ! command -v cbindgen >/dev/null 2>&1 || ! command -v cargo-lipo >/dev/null 2>&1; then - echo "Installing Cargo tools (cbindgen, cargo-ndk, cargo-lipo)..." - cargo install cargo-ndk cbindgen cargo-lipo - fi -else - echo "ERROR: rustup not found. Install rustup first." -fi - -# 3. MACOS SDK & COMPILER OVERRIDES -export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer" -export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)" -export MACOSX_DEPLOYMENT_TARGET="11.0" - -export CC=/usr/bin/clang -export CXX=/usr/bin/clang++ -export AR=/usr/bin/ar -export AS=/usr/bin/as -export NM=/usr/bin/nm -export RANLIB=/usr/bin/ranlib -export STRIP=/usr/bin/strip -export BINDGEN_EXTRA_CLANG_ARGS="-isysroot $SDKROOT" - -# 4. PYTHON VIRTUAL ENV -if [ ! -d ".venv" ]; then - echo "Creating Python venv and installing dependencies..." - python3 -m venv .venv - source .venv/bin/activate - pip install toml tomli jinja2 markdown markupsafe pygments typogrify -else - source .venv/bin/activate -fi - -# 5. XCODE TOOL WRAPPERS -mkdir -p .direnv-bin - -cat > .direnv-bin/lipo <<'EOF' -#!/usr/bin/env bash -for arg in "$@"; do - if [[ "$arg" == *"FlutterMacOS.framework"* ]]; then - chmod -R u+w "$(dirname "$arg")" 2>/dev/null || true - fi -done -exec /usr/bin/lipo "$@" -EOF -chmod +x .direnv-bin/lipo - -cat > .direnv-bin/xcrun <<'EOF' -#!/usr/bin/env bash -if [ "$1" = "-f" ] && [ "$2" = "lipo" ]; then - echo "$PWD/.direnv-bin/lipo" - exit 0 -fi - -# Keep xcrun tool invocations pinned to macOS deployment context. -unset IPHONEOS_DEPLOYMENT_TARGET TVOS_DEPLOYMENT_TARGET WATCHOS_DEPLOYMENT_TARGET -unset XROS_DEPLOYMENT_TARGET XR_DEPLOYMENT_TARGET VISIONOS_DEPLOYMENT_TARGET DRIVERKIT_DEPLOYMENT_TARGET -export MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-11.0}" -export SDKROOT="${SDKROOT:-$(/usr/bin/xcrun --sdk macosx --show-sdk-path)}" - -exec /usr/bin/xcrun "$@" -EOF -chmod +x .direnv-bin/xcrun - -echo "Stack Wallet direnv environment loaded." +use flake diff --git a/Makefile b/Makefile index a7e1f2fa6..958fd7a50 100644 --- a/Makefile +++ b/Makefile @@ -12,9 +12,14 @@ FLUTTER_BIN := $(if $(and $(FLUTTER),$(wildcard $(FLUTTER))),$(FLUTTER),$(shell DART_BIN := $(if $(and $(DART),$(wildcard $(DART))),$(DART),$(shell command -v dart 2>/dev/null)) FLUTTER := $(FLUTTER_BIN) DART := $(DART_BIN) -PUB_CACHE ?= $(APP_PROJECT_ROOT_DIR)/.pub-cache APP_PROJECT_ROOT_DIR := $(CURDIR) +PUB_CACHE ?= $(APP_PROJECT_ROOT_DIR)/.pub-cache PROTOC_PATH := $(shell which protoc 2>/dev/null) +PROJECT_HOME := $(APP_PROJECT_ROOT_DIR)/.nix-home +PROJECT_CACHE := $(APP_PROJECT_ROOT_DIR)/.cache +PROJECT_TMP := $(APP_PROJECT_ROOT_DIR)/.tmp +PROJECT_CARGO_HOME := $(APP_PROJECT_ROOT_DIR)/.cargo-home +PROJECT_RUSTUP_HOME := $(APP_PROJECT_ROOT_DIR)/.rustup-home MACOS_ENV_UNSET = -u LD -u LDFLAGS -u NIX_LDFLAGS -u NIX_CFLAGS_LINK \ -u CFLAGS -u CXXFLAGS -u CPPFLAGS \ -u SDKROOT -u BINDGEN_EXTRA_CLANG_ARGS \ @@ -25,7 +30,7 @@ MACOS_ENV_SET = MACOSX_DEPLOYMENT_TARGET=11.0 export APP_PROJECT_ROOT_DIR export PUB_CACHE -.PHONY: help check-reqs check-reqs-windows check-macos-sdk bootstrap-macos init clean prebuild-unix prebuild-windows deps-linux patch-submodules \ +.PHONY: help check-reqs check-reqs-macos check-reqs-windows check-macos-sdk bootstrap-macos macos-local-state init clean prebuild-unix prebuild-windows deps-linux patch-submodules \ build-linux build-macos build-ios build-android build-windows \ macos-prepare macos-configure macos-restore-metadata macos-build-native macos-build-app diagnose-macos-env @@ -77,14 +82,44 @@ ifeq ($(shell uname),Darwin) @echo "[OK] Xcode SDK path looks good." endif +check-reqs-macos: ## Verify macOS build tools are available in PATH +ifeq ($(shell uname),Darwin) + @echo "Checking macOS toolchain in PATH..." + @command -v $(FLUTTER) >/dev/null 2>&1 || { echo >&2 "[ERROR] Flutter not installed."; exit 1; } + @command -v $(DART) >/dev/null 2>&1 || { echo >&2 "[ERROR] Dart not installed."; exit 1; } + @command -v rustup >/dev/null 2>&1 || { echo >&2 "[ERROR] rustup not installed."; exit 1; } + @command -v cargo >/dev/null 2>&1 || { echo >&2 "[ERROR] cargo not installed."; exit 1; } + @command -v cmake >/dev/null 2>&1 || { echo >&2 "[ERROR] CMake not installed."; exit 1; } + @command -v meson >/dev/null 2>&1 || { echo >&2 "[ERROR] Meson not installed."; exit 1; } + @command -v ninja >/dev/null 2>&1 || { echo >&2 "[ERROR] Ninja not installed."; exit 1; } + @command -v pkg-config >/dev/null 2>&1 || { echo >&2 "[ERROR] pkg-config not installed."; exit 1; } + @command -v pod >/dev/null 2>&1 || { echo >&2 "[ERROR] CocoaPods (pod) not installed."; exit 1; } + @command -v xcodebuild >/dev/null 2>&1 || { echo >&2 "[ERROR] xcodebuild not available."; exit 1; } + @command -v autoreconf >/dev/null 2>&1 || { echo >&2 "[ERROR] autoconf/autoreconf not installed."; exit 1; } + @command -v aclocal >/dev/null 2>&1 || { echo >&2 "[ERROR] automake/aclocal not installed."; exit 1; } + @echo "[OK] macOS toolchain is available." +else + @echo "[ERROR] check-reqs-macos is macOS-only." + @exit 1 +endif + bootstrap-macos: ## Install required macOS build tools via Homebrew helper script ifeq ($(shell uname),Darwin) @bash scripts/install_macos_build_tools.sh + @rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain stable >/dev/null 2>&1 || true + @rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain 1.85.1 >/dev/null 2>&1 || true else @echo "[ERROR] bootstrap-macos is macOS-only." @exit 1 endif +macos-local-state: ## Create project-local state dirs for reproducible macOS builds +ifeq ($(shell uname),Darwin) + @mkdir -p "$(PROJECT_HOME)" "$(PROJECT_CACHE)" "$(PROJECT_TMP)" "$(PUB_CACHE)" "$(PROJECT_CARGO_HOME)" "$(PROJECT_RUSTUP_HOME)" +else + @true +endif + check-reqs-windows: ## Verify Windows/WSL requirements @echo "Checking Windows prerequisites..." @command -v wsl >/dev/null 2>&1 || { echo >&2 "[ERROR] WSL is not installed."; exit 1; } @@ -131,15 +166,14 @@ patch-submodules: ## Apply portability patches to submodules # --- PLATFORM BUILDS --- -build-macos: check-reqs check-macos-sdk macos-prepare macos-configure macos-restore-metadata macos-build-native macos-build-app ## Build MacOS Release (Single source of truth) +build-macos: check-reqs-macos check-macos-sdk macos-local-state macos-prepare macos-configure macos-restore-metadata macos-build-native macos-build-app ## Build MacOS Release (Single source of truth) macos-prepare: @echo "--- Sanitizing environment..." @sed -i.bak 's/\xc2\xa0/ /g' scripts/app_config/templates/pubspec.template.yaml 2>/dev/null || true @rm -f scripts/app_config/templates/pubspec.template.yaml.bak - @chmod -R u+w . 2>/dev/null || true - @rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain stable >/dev/null 2>&1 || true - @rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain 1.85.1 >/dev/null 2>&1 || true + @chmod -R u+w macos build scripts crypto_plugins 2>/dev/null || true + @[ -f pubspec.yaml ] && chmod u+w pubspec.yaml 2>/dev/null || true @rm -rf build/secp256k1 macos/Runner.xcworkspace crypto_plugins/*/scripts/macos/build macos-configure: @@ -147,7 +181,8 @@ macos-configure: @echo "--- Initializing submodules..." @git submodule update --init --recursive @echo "--- Bootstrapping local config files..." - @cd scripts && bash prebuild.sh + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + cd scripts && bash prebuild.sh @if [ ! -f crypto_plugins/flutter_libepiccash/lib/git_versions.dart ] && [ -f crypto_plugins/flutter_libepiccash/lib/git_versions_example.dart ]; then \ echo "--- Creating flutter_libepiccash git_versions.dart from example..."; \ cp crypto_plugins/flutter_libepiccash/lib/git_versions_example.dart crypto_plugins/flutter_libepiccash/lib/git_versions.dart; \ @@ -160,12 +195,18 @@ macos-configure: echo "--- pubspec.yaml missing; generating from template..."; \ cp scripts/app_config/templates/pubspec.template.yaml pubspec.yaml; \ fi - @./scripts/app_config/configure_stack_wallet.sh macos - @./scripts/app_config/shared/update_version.sh -v $(VERSION) -b $(BUILD_NUM) + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + ./scripts/app_config/configure_stack_wallet.sh macos + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + ./scripts/app_config/shared/update_version.sh -v $(VERSION) -b $(BUILD_NUM) macos-restore-metadata: @echo "--- Restoring metadata..." - @$(FLUTTER) create --platforms=macos . > /dev/null + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + $(FLUTTER) create --platforms=macos . > /dev/null + @rm -rf macos/Runner.xcworkspace macos/Pods macos/Podfile.lock + @chmod -R u+rwX macos 2>/dev/null || true + @chflags -R nouchg macos 2>/dev/null || true @# Nix-provided Flutter templates can be copied as read-only; CocoaPods must rewrite these files. @chmod -R u+w macos/Runner.xcworkspace macos/Runner.xcodeproj macos/Flutter 2>/dev/null || true @# Ensure Pods includes are resolved relative to macos/Flutter/*.xcconfig. @@ -196,11 +237,28 @@ macos-restore-metadata: ( grep -q 'CodexOverrides.xcconfig' macos/Runner/Configs/Profile.xcconfig || \ printf '\n#include "CodexOverrides.xcconfig"\n' >> macos/Runner/Configs/Profile.xcconfig ) || true @rm -f macos/Runner.xcodeproj/project.pbxproj.bak - @$(FLUTTER) pub get - @bash scripts/macos/patch_coinlib_podspec.sh + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + $(FLUTTER) pub get + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + bash scripts/macos/patch_coinlib_podspec.sh @# Ensure generated build settings are single-line key/value entries for CocoaPods xcconfig parser. @[ -f macos/Flutter/ephemeral/Flutter-Generated.xcconfig ] && \ sed -i.bak -E 's/[[:space:]]+$$//' macos/Flutter/ephemeral/Flutter-Generated.xcconfig && \ + awk 'BEGIN{k="";v=""} \ + function flush(){if(k!=""){print k "=" v; k=""; v=""}} \ + /^[A-Za-z_][A-Za-z0-9_]*=/{ \ + if(k!=""){flush()} \ + split($$0,a,"="); \ + key=a[1]; val=substr($$0, length(key)+2); gsub(/[ \t]/,"",val); \ + if(key=="DART_DEFINES"){k=key; v=val; next} \ + print $$0; next \ + } \ + { \ + if(k=="DART_DEFINES"){gsub(/[ \t]/,"",$$0); v=v $$0; next} \ + print $$0 \ + } \ + END{flush()}' macos/Flutter/ephemeral/Flutter-Generated.xcconfig > macos/Flutter/ephemeral/Flutter-Generated.xcconfig.tmp && \ + mv macos/Flutter/ephemeral/Flutter-Generated.xcconfig.tmp macos/Flutter/ephemeral/Flutter-Generated.xcconfig && \ rm -f macos/Flutter/ephemeral/Flutter-Generated.xcconfig.bak || true macos-build-native: @@ -214,8 +272,12 @@ macos-build-native: @# Ensure Frostdart macOS build script uses sed -i.bak form (GNU/BSD compatibility). @perl -0777 -i.bak -pe 's/_run\("sed",\s*\["-i"\s*,\s*"\.bak"\s*,\s*"s\/frostdart\/hrf-api\/",\s*"cargo\.toml"\]\);/_run("sed", ["-i.bak", "s\/frostdart\/hrf-api\/", "cargo.toml"]);/g' crypto_plugins/frostdart/scripts/macos/build_macos.dart 2>/dev/null || true @env $(MACOS_ENV_UNSET) $(MACOS_ENV_SET) \ - RUSTUP_HOME="$$HOME/.rustup" \ - CARGO_HOME="$$HOME/.cargo" \ + HOME="$(PROJECT_HOME)" \ + XDG_CACHE_HOME="$(PROJECT_CACHE)" \ + TMPDIR="$(PROJECT_TMP)" \ + PUB_CACHE="$(PUB_CACHE)" \ + RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" \ + CARGO_HOME="$(PROJECT_CARGO_HOME)" \ MAKEFLAGS= \ MFLAGS= \ CARGO_MAKEFLAGS= \ @@ -224,22 +286,27 @@ macos-build-native: AR="/usr/bin/ar" \ RANLIB="/usr/bin/ranlib" \ SDKROOT="$$(xcrun --sdk macosx --show-sdk-path)" \ - PATH="/opt/homebrew/opt/rustup/bin:/opt/homebrew/bin:$$HOME/.cargo/bin:$$PATH" \ + PATH="$(PROJECT_CARGO_HOME)/bin:$$PATH" \ bash scripts/macos/build_all.sh @rm -rf build/secp256k1 - @$(FLUTTER) pub run coinlib:build_macos + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + $(DART) run coinlib:build_macos @echo "--- Patching Podfile..." @sed -i.bak -e "s/platform :osx, '10.11'/platform :osx, '11.0'/g" -e "s/platform :osx, '10.15'/platform :osx, '11.0'/g" macos/Podfile 2>/dev/null || true @rm -f macos/Podfile.bak macos-build-app: @echo "--- Final Compilation..." - @rm -rf macos/Pods macos/Podfile.lock + @rm -rf macos/Runner.xcworkspace macos/Pods macos/Podfile.lock @env $(MACOS_ENV_UNSET) $(MACOS_ENV_SET) \ - RUSTUP_HOME="$$HOME/.rustup" \ - CARGO_HOME="$$HOME/.cargo" \ + HOME="$(PROJECT_HOME)" \ + XDG_CACHE_HOME="$(PROJECT_CACHE)" \ + TMPDIR="$(PROJECT_TMP)" \ + PUB_CACHE="$(PUB_CACHE)" \ + RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" \ + CARGO_HOME="$(PROJECT_CARGO_HOME)" \ RUSTUP_TOOLCHAIN=stable \ - PATH="$$(dirname "$$(/opt/homebrew/bin/rustup which rustc)"):/opt/homebrew/opt/rustup/bin:/opt/homebrew/bin:$$HOME/.cargo/bin:$$PATH" \ + PATH="$(PROJECT_CARGO_HOME)/bin:$$(dirname "$$(rustup which rustc)"):$${PATH}" \ ARCHS=arm64 EXCLUDED_ARCHS=x86_64 ONLY_ACTIVE_ARCH=YES $(FLUTTER) build macos --release diagnose-macos-env: ## Print macOS build env and tool resolution From 124ae40d1e46c69932a53b6a4cf5e3d841e04d50 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Thu, 19 Mar 2026 09:25:06 +0100 Subject: [PATCH 086/118] build(macos): harden make targets and unify req checks --- Makefile | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 958fd7a50..b9f6be674 100644 --- a/Makefile +++ b/Makefile @@ -82,22 +82,12 @@ ifeq ($(shell uname),Darwin) @echo "[OK] Xcode SDK path looks good." endif -check-reqs-macos: ## Verify macOS build tools are available in PATH +check-reqs-macos: check-reqs ## Verify macOS-specific tools are available in PATH ifeq ($(shell uname),Darwin) - @echo "Checking macOS toolchain in PATH..." - @command -v $(FLUTTER) >/dev/null 2>&1 || { echo >&2 "[ERROR] Flutter not installed."; exit 1; } - @command -v $(DART) >/dev/null 2>&1 || { echo >&2 "[ERROR] Dart not installed."; exit 1; } - @command -v rustup >/dev/null 2>&1 || { echo >&2 "[ERROR] rustup not installed."; exit 1; } - @command -v cargo >/dev/null 2>&1 || { echo >&2 "[ERROR] cargo not installed."; exit 1; } - @command -v cmake >/dev/null 2>&1 || { echo >&2 "[ERROR] CMake not installed."; exit 1; } - @command -v meson >/dev/null 2>&1 || { echo >&2 "[ERROR] Meson not installed."; exit 1; } - @command -v ninja >/dev/null 2>&1 || { echo >&2 "[ERROR] Ninja not installed."; exit 1; } - @command -v pkg-config >/dev/null 2>&1 || { echo >&2 "[ERROR] pkg-config not installed."; exit 1; } + @echo "Checking macOS-specific tools in PATH..." @command -v pod >/dev/null 2>&1 || { echo >&2 "[ERROR] CocoaPods (pod) not installed."; exit 1; } @command -v xcodebuild >/dev/null 2>&1 || { echo >&2 "[ERROR] xcodebuild not available."; exit 1; } - @command -v autoreconf >/dev/null 2>&1 || { echo >&2 "[ERROR] autoconf/autoreconf not installed."; exit 1; } - @command -v aclocal >/dev/null 2>&1 || { echo >&2 "[ERROR] automake/aclocal not installed."; exit 1; } - @echo "[OK] macOS toolchain is available." + @echo "[OK] macOS-specific toolchain is available." else @echo "[ERROR] check-reqs-macos is macOS-only." @exit 1 @@ -181,8 +171,8 @@ macos-configure: @echo "--- Initializing submodules..." @git submodule update --init --recursive @echo "--- Bootstrapping local config files..." - @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ - cd scripts && bash prebuild.sh + @cd scripts && env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + bash prebuild.sh @if [ ! -f crypto_plugins/flutter_libepiccash/lib/git_versions.dart ] && [ -f crypto_plugins/flutter_libepiccash/lib/git_versions_example.dart ]; then \ echo "--- Creating flutter_libepiccash git_versions.dart from example..."; \ cp crypto_plugins/flutter_libepiccash/lib/git_versions_example.dart crypto_plugins/flutter_libepiccash/lib/git_versions.dart; \ @@ -208,7 +198,8 @@ macos-restore-metadata: @chmod -R u+rwX macos 2>/dev/null || true @chflags -R nouchg macos 2>/dev/null || true @# Nix-provided Flutter templates can be copied as read-only; CocoaPods must rewrite these files. - @chmod -R u+w macos/Runner.xcworkspace macos/Runner.xcodeproj macos/Flutter 2>/dev/null || true + @[ -d macos/Runner.xcodeproj ] && chmod -R u+w macos/Runner.xcodeproj 2>/dev/null || true + @[ -d macos/Flutter ] && chmod -R u+w macos/Flutter 2>/dev/null || true @# Ensure Pods includes are resolved relative to macos/Flutter/*.xcconfig. @sed -i.bak -e 's|#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner\.debug\.xcconfig"|#include? "../Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"|g' macos/Flutter/Flutter-Debug.xcconfig 2>/dev/null || true @sed -i.bak -e 's|#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner\.release\.xcconfig"|#include? "../Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"|g' macos/Flutter/Flutter-Release.xcconfig 2>/dev/null || true From 3e0bc9f6b42d1f14bdfd0a081b5507908a9687be Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Thu, 19 Mar 2026 09:25:37 +0100 Subject: [PATCH 087/118] docs(build): split nix vs non-nix flow and clarify bootstrap roles --- Makefile | 4 ++++ README.md | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/Makefile b/Makefile index b9f6be674..71818d54b 100644 --- a/Makefile +++ b/Makefile @@ -95,6 +95,10 @@ endif bootstrap-macos: ## Install required macOS build tools via Homebrew helper script ifeq ($(shell uname),Darwin) + @if [ -n "$$IN_NIX_SHELL" ] || [ -n "$$NIX_BUILD_TOP" ]; then \ + echo "[WARN] Nix environment detected; bootstrap-macos skipped (use nix/flake-provided toolchain)."; \ + exit 0; \ + fi @bash scripts/install_macos_build_tools.sh @rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain stable >/dev/null 2>&1 || true @rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain 1.85.1 >/dev/null 2>&1 || true diff --git a/README.md b/README.md index 70bf3f836..cc20ec9e9 100644 --- a/README.md +++ b/README.md @@ -48,3 +48,24 @@ Highlights include: ## Building You can look at the [build instructions](docs/building.md) for more details. + +### macOS with Nix or direnv (preferred) + +Use one shared toolchain path for both `nix develop` and `direnv`. + +1. Enable direnv for this repo (optional convenience): + - `.envrc` uses `use flake` + - run `direnv allow` +2. Enter the flake environment (if not using direnv): + - `nix develop` +3. Run build: + - `make build-macos` + +### macOS without Nix (Homebrew host setup) + +Use this only when you are not building through Nix/flake. + +1. Install host tools: + - `make bootstrap-macos` +2. Run build: + - `make build-macos` From 86d2cf433e5dc7e7e34ee262879f157793c59fe2 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Thu, 19 Mar 2026 10:07:43 +0100 Subject: [PATCH 088/118] macos: auto-enable desktop support in local build home --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 71818d54b..a3d2049d4 100644 --- a/Makefile +++ b/Makefile @@ -196,6 +196,8 @@ macos-configure: macos-restore-metadata: @echo "--- Restoring metadata..." + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + $(FLUTTER) config --enable-macos-desktop >/dev/null @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ $(FLUTTER) create --platforms=macos . > /dev/null @rm -rf macos/Runner.xcworkspace macos/Pods macos/Podfile.lock From aa19dab34202911e6caa132c0f04f7e663607d54 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Thu, 19 Mar 2026 10:19:40 +0100 Subject: [PATCH 089/118] build(macos): use .build-home and reassert desktop metadata before final build --- Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a3d2049d4..bf2a975ad 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ DART := $(DART_BIN) APP_PROJECT_ROOT_DIR := $(CURDIR) PUB_CACHE ?= $(APP_PROJECT_ROOT_DIR)/.pub-cache PROTOC_PATH := $(shell which protoc 2>/dev/null) -PROJECT_HOME := $(APP_PROJECT_ROOT_DIR)/.nix-home +PROJECT_HOME := $(APP_PROJECT_ROOT_DIR)/.build-home PROJECT_CACHE := $(APP_PROJECT_ROOT_DIR)/.cache PROJECT_TMP := $(APP_PROJECT_ROOT_DIR)/.tmp PROJECT_CARGO_HOME := $(APP_PROJECT_ROOT_DIR)/.cargo-home @@ -295,6 +295,11 @@ macos-build-native: macos-build-app: @echo "--- Final Compilation..." @rm -rf macos/Runner.xcworkspace macos/Pods macos/Podfile.lock + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + $(FLUTTER) config --enable-macos-desktop >/dev/null + @# Reassert macOS platform metadata in the same local HOME used for the final build. + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + $(FLUTTER) create --platforms=macos . --no-pub >/dev/null @env $(MACOS_ENV_UNSET) $(MACOS_ENV_SET) \ HOME="$(PROJECT_HOME)" \ XDG_CACHE_HOME="$(PROJECT_CACHE)" \ From d47dcee1c47ea0bf75535b79503eb9d178e8ea99 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Thu, 19 Mar 2026 10:30:03 +0100 Subject: [PATCH 090/118] changing rust version requs --- scripts/rust_version.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/rust_version.sh b/scripts/rust_version.sh index b48750952..f4870ff6e 100755 --- a/scripts/rust_version.sh +++ b/scripts/rust_version.sh @@ -1,20 +1,19 @@ -#!/bin/sh - +#!/usr/bin/env bash set_rust_to_everything_else() { - if rustup toolchain list | grep -q "1.85.1"; then - rustup default 1.89.0 + if rustup toolchain list | grep -q "1.94.0"; then + rustup default 1.94.0 else - echo "Rust version 1.89.0 is not installed. Please install it using 'rustup install 1.89.0'." >&2 + echo "Rust version 1.94.0 is not installed. Please install it using 'rustup install 1.94.0'." >&2 echo "Bypassed by Nix" fi } set_rust_version_for_libepiccash() { - if rustup toolchain list | grep -q "1.89.0"; then - rustup default 1.89.0 + if rustup toolchain list | grep -q "1.85.1"; then + rustup default 1.85.1 else - echo "Rust version 1.89.0 is not installed. Please install it using 'rustup install 1.89.0'." >&2 + echo "Rust version 1.85.1 is not installed. Please install it using 'rustup install 1.85.1'." >&2 echo "Bypassed by Nix" fi } @@ -26,4 +25,5 @@ set_rust_version_for_libmwc() { echo "Rust version 1.85.1 is not installed. Please install it using 'rustup install 1.85.1'." >&2 echo "Bypassed by Nix" fi -} \ No newline at end of file +} + From b027d40f4df9613a01fda74945a69d558a8609d3 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Thu, 19 Mar 2026 10:31:16 +0100 Subject: [PATCH 091/118] build(macos): use Rust 1.94.0 for final pod/flutter compile --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bf2a975ad..9a58d33af 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ PROJECT_CACHE := $(APP_PROJECT_ROOT_DIR)/.cache PROJECT_TMP := $(APP_PROJECT_ROOT_DIR)/.tmp PROJECT_CARGO_HOME := $(APP_PROJECT_ROOT_DIR)/.cargo-home PROJECT_RUSTUP_HOME := $(APP_PROJECT_ROOT_DIR)/.rustup-home +MACOS_FINAL_RUST_TOOLCHAIN ?= 1.94.0 MACOS_ENV_UNSET = -u LD -u LDFLAGS -u NIX_LDFLAGS -u NIX_CFLAGS_LINK \ -u CFLAGS -u CXXFLAGS -u CPPFLAGS \ -u SDKROOT -u BINDGEN_EXTRA_CLANG_ARGS \ @@ -307,7 +308,7 @@ macos-build-app: PUB_CACHE="$(PUB_CACHE)" \ RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" \ CARGO_HOME="$(PROJECT_CARGO_HOME)" \ - RUSTUP_TOOLCHAIN=stable \ + RUSTUP_TOOLCHAIN="$(MACOS_FINAL_RUST_TOOLCHAIN)" \ PATH="$(PROJECT_CARGO_HOME)/bin:$$(dirname "$$(rustup which rustc)"):$${PATH}" \ ARCHS=arm64 EXCLUDED_ARCHS=x86_64 ONLY_ACTIVE_ARCH=YES $(FLUTTER) build macos --release From f5f3ae5b8a66652f3563c715505cf5651ba42de1 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Thu, 19 Mar 2026 10:33:38 +0100 Subject: [PATCH 092/118] build(rust): align flake and macOS bootstrap to Rust 1.94.0 --- flake.nix | 6 +++--- scripts/install_macos_build_tools.sh | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.nix b/flake.nix index 3bfd7bad8..273676d0e 100644 --- a/flake.nix +++ b/flake.nix @@ -63,10 +63,10 @@ # ========================================== # RUST TOOLCHAIN AUTOMATION # ========================================== - if ! rustup toolchain list | grep -q "1.89.0"; then + if ! rustup toolchain list | grep -q "1.94.0"; then echo "Initializing Rust toolchains (this happens only once)..." - rustup install 1.89.0 1.85.1 stable - rustup default 1.89.0 + rustup install 1.94.0 1.85.1 stable + rustup default 1.94.0 if [[ "${system}" == *"darwin"* ]]; then rustup target add aarch64-apple-darwin aarch64-apple-ios diff --git a/scripts/install_macos_build_tools.sh b/scripts/install_macos_build_tools.sh index 276a863a9..5d73c8d4c 100755 --- a/scripts/install_macos_build_tools.sh +++ b/scripts/install_macos_build_tools.sh @@ -31,11 +31,11 @@ fi echo "Ensuring Rust toolchains are installed..." rustup toolchain install stable rustup default stable -rustup toolchain install 1.89.0 1.85.1 -rustup default 1.89.0 +rustup toolchain install 1.94.0 1.85.1 +rustup default 1.94.0 rustup target add aarch64-apple-darwin x86_64-apple-darwin aarch64-apple-ios --toolchain stable >/dev/null 2>&1 || true rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain 1.85.1 >/dev/null 2>&1 || true -rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain 1.89.0 >/dev/null 2>&1 || true +rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain 1.94.0 >/dev/null 2>&1 || true echo "Installing Rust CLI build tools..." cargo install cargo-lipo cbindgen || true From 5b2b8e68add55e19287adf2f242f35456b745155 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Thu, 19 Mar 2026 10:40:30 +0100 Subject: [PATCH 093/118] build(macos): ensure local stable rust toolchain is updated before flutter build --- Makefile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Makefile b/Makefile index 9a58d33af..a10174c22 100644 --- a/Makefile +++ b/Makefile @@ -301,6 +301,16 @@ macos-build-app: @# Reassert macOS platform metadata in the same local HOME used for the final build. @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ $(FLUTTER) create --platforms=macos . --no-pub >/dev/null + @# Cargokit calls `rustup run stable cargo ...`; ensure local `stable` is new enough. + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" CARGO_HOME="$(PROJECT_CARGO_HOME)" \ + rustup toolchain install stable "$(MACOS_FINAL_RUST_TOOLCHAIN)" >/dev/null + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" CARGO_HOME="$(PROJECT_CARGO_HOME)" \ + rustup default "$(MACOS_FINAL_RUST_TOOLCHAIN)" >/dev/null + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" CARGO_HOME="$(PROJECT_CARGO_HOME)" \ + rustup run stable rustc -V @env $(MACOS_ENV_UNSET) $(MACOS_ENV_SET) \ HOME="$(PROJECT_HOME)" \ XDG_CACHE_HOME="$(PROJECT_CACHE)" \ From a893a56c723fa7d69c77a6d31b359a5db976a113 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Thu, 19 Mar 2026 17:03:56 +0100 Subject: [PATCH 094/118] build(macos): switch defaults to stable and initialize local rustup for nix builds --- Makefile | 15 +++++++++++---- flake.nix | 6 +++--- scripts/install_macos_build_tools.sh | 5 ++--- scripts/rust_version.sh | 7 +++---- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index a10174c22..e4a1c4849 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ PROJECT_CACHE := $(APP_PROJECT_ROOT_DIR)/.cache PROJECT_TMP := $(APP_PROJECT_ROOT_DIR)/.tmp PROJECT_CARGO_HOME := $(APP_PROJECT_ROOT_DIR)/.cargo-home PROJECT_RUSTUP_HOME := $(APP_PROJECT_ROOT_DIR)/.rustup-home -MACOS_FINAL_RUST_TOOLCHAIN ?= 1.94.0 +MACOS_FINAL_RUST_TOOLCHAIN ?= stable MACOS_ENV_UNSET = -u LD -u LDFLAGS -u NIX_LDFLAGS -u NIX_CFLAGS_LINK \ -u CFLAGS -u CXXFLAGS -u CPPFLAGS \ -u SDKROOT -u BINDGEN_EXTRA_CLANG_ARGS \ @@ -261,6 +261,13 @@ macos-restore-metadata: macos-build-native: @echo "--- Building native dependencies..." + @# Ensure local rustup home has a usable default toolchain for native plugin scripts. + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" CARGO_HOME="$(PROJECT_CARGO_HOME)" \ + rustup toolchain install stable 1.85.1 >/dev/null + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" CARGO_HOME="$(PROJECT_CARGO_HOME)" \ + rustup default stable >/dev/null @echo "--- Applying local patch for flutter_libepiccash macOS build script..." @cp scripts/patches/flutter_libepiccash_macos_build_all.sh crypto_plugins/flutter_libepiccash/scripts/macos/build_all.sh @chmod +x crypto_plugins/flutter_libepiccash/scripts/macos/build_all.sh @@ -301,13 +308,13 @@ macos-build-app: @# Reassert macOS platform metadata in the same local HOME used for the final build. @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ $(FLUTTER) create --platforms=macos . --no-pub >/dev/null - @# Cargokit calls `rustup run stable cargo ...`; ensure local `stable` is new enough. + @# Cargokit calls `rustup run stable cargo ...`; ensure local `stable` exists and is selected. @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" CARGO_HOME="$(PROJECT_CARGO_HOME)" \ - rustup toolchain install stable "$(MACOS_FINAL_RUST_TOOLCHAIN)" >/dev/null + rustup toolchain install stable >/dev/null @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" CARGO_HOME="$(PROJECT_CARGO_HOME)" \ - rustup default "$(MACOS_FINAL_RUST_TOOLCHAIN)" >/dev/null + rustup default stable >/dev/null @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" CARGO_HOME="$(PROJECT_CARGO_HOME)" \ rustup run stable rustc -V diff --git a/flake.nix b/flake.nix index 273676d0e..ac000a52b 100644 --- a/flake.nix +++ b/flake.nix @@ -63,10 +63,10 @@ # ========================================== # RUST TOOLCHAIN AUTOMATION # ========================================== - if ! rustup toolchain list | grep -q "1.94.0"; then + if ! rustup toolchain list | grep -q "stable"; then echo "Initializing Rust toolchains (this happens only once)..." - rustup install 1.94.0 1.85.1 stable - rustup default 1.94.0 + rustup install 1.85.1 stable + rustup default stable if [[ "${system}" == *"darwin"* ]]; then rustup target add aarch64-apple-darwin aarch64-apple-ios diff --git a/scripts/install_macos_build_tools.sh b/scripts/install_macos_build_tools.sh index 5d73c8d4c..4c905e1d8 100755 --- a/scripts/install_macos_build_tools.sh +++ b/scripts/install_macos_build_tools.sh @@ -31,11 +31,10 @@ fi echo "Ensuring Rust toolchains are installed..." rustup toolchain install stable rustup default stable -rustup toolchain install 1.94.0 1.85.1 -rustup default 1.94.0 +rustup toolchain install 1.85.1 +rustup default stable rustup target add aarch64-apple-darwin x86_64-apple-darwin aarch64-apple-ios --toolchain stable >/dev/null 2>&1 || true rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain 1.85.1 >/dev/null 2>&1 || true -rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain 1.94.0 >/dev/null 2>&1 || true echo "Installing Rust CLI build tools..." cargo install cargo-lipo cbindgen || true diff --git a/scripts/rust_version.sh b/scripts/rust_version.sh index f4870ff6e..e72224d66 100755 --- a/scripts/rust_version.sh +++ b/scripts/rust_version.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash set_rust_to_everything_else() { - if rustup toolchain list | grep -q "1.94.0"; then - rustup default 1.94.0 + if rustup toolchain list | grep -q "stable"; then + rustup default stable else - echo "Rust version 1.94.0 is not installed. Please install it using 'rustup install 1.94.0'." >&2 + echo "Rust stable toolchain is not installed. Please install it using 'rustup toolchain install stable'." >&2 echo "Bypassed by Nix" fi } @@ -26,4 +26,3 @@ set_rust_version_for_libmwc() { echo "Bypassed by Nix" fi } - From 538ea1537f4afbd67500a7c85da3416b0ddbbd8d Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Fri, 20 Mar 2026 02:52:37 +0100 Subject: [PATCH 095/118] build: run coinlib via flutter dart to honor Flutter SDK constraints --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index e4a1c4849..d3ac0151d 100644 --- a/Makefile +++ b/Makefile @@ -295,7 +295,7 @@ macos-build-native: bash scripts/macos/build_all.sh @rm -rf build/secp256k1 @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ - $(DART) run coinlib:build_macos + $(FLUTTER) dart run coinlib:build_macos @echo "--- Patching Podfile..." @sed -i.bak -e "s/platform :osx, '10.11'/platform :osx, '11.0'/g" -e "s/platform :osx, '10.15'/platform :osx, '11.0'/g" macos/Podfile 2>/dev/null || true @rm -f macos/Podfile.bak @@ -385,7 +385,7 @@ build-linux: check-reqs init patch-submodules ## Build Linux Release 'Cflags: -I$${includedir} -I$${includedir}/_build' \ > scripts/linux/pc/libsecret-1.pc @if command -v podman >/dev/null 2>&1 || command -v docker >/dev/null 2>&1; then \ - $(DART) run coinlib:build_linux; \ + $(FLUTTER) dart run coinlib:build_linux; \ else \ echo "[WARN] podman/docker not found; skipping coinlib:build_linux"; \ fi From 568d13570efd43e0bedec04e8487ae12994d38a7 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 11 May 2026 08:12:15 +0200 Subject: [PATCH 096/118] updating .gitignore: toolchain/state dirs --- .gitignore | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index 05f3ede79..3880f3a1c 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,15 @@ Microsoft.Windows* /build/ android/app/.cxx +# Nix / direnv / project-local toolchain state +.direnv/ +.build-home/ +.cargo-home/ +.rustup-home/ +.nix-bin/ +.tmp/ +.cache/ + # Web related lib/generated_plugin_registrant.dart From 94ee7695186d781d34eef7c38a869042c1e458e8 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 11 May 2026 08:14:06 +0200 Subject: [PATCH 097/118] adding rust default stable, drop 1.89.0 --- scripts/install_nixos_build_tools.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/install_nixos_build_tools.sh b/scripts/install_nixos_build_tools.sh index 5a6e133cd..1709457cd 100755 --- a/scripts/install_nixos_build_tools.sh +++ b/scripts/install_nixos_build_tools.sh @@ -34,13 +34,14 @@ nix --extra-experimental-features "nix-command flakes" profile add \ nixpkgs#clang || true echo "Ensuring Rust toolchains are installed..." -rustup toolchain install stable +# Two toolchains are required: +# - stable: used for frostdart, coinlib, secp256k1, and everything else +# - 1.85.1: pinned for flutter_libepiccash / flutter_libmwc (older Rust dialect) +# See scripts/rust_version.sh and flake.nix. +rustup toolchain install --no-self-update stable 1.85.1 rustup default stable -rustup toolchain install 1.89.0 1.85.1 -rustup default 1.89.0 rustup target add aarch64-unknown-linux-gnu x86_64-unknown-linux-gnu --toolchain stable >/dev/null 2>&1 || true rustup target add aarch64-unknown-linux-gnu x86_64-unknown-linux-gnu --toolchain 1.85.1 >/dev/null 2>&1 || true -rustup target add aarch64-unknown-linux-gnu x86_64-unknown-linux-gnu --toolchain 1.89.0 >/dev/null 2>&1 || true echo "Installing Rust CLI build tools..." cargo install cargo-ndk cbindgen cargo-lipo || true From 2c529c4784e5584e5d355451794372aebf71472d Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 11 May 2026 08:16:51 +0200 Subject: [PATCH 098/118] adding information on building: macos, nixos, linux --- docs/building.md | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/docs/building.md b/docs/building.md index dff508079..377141fa6 100644 --- a/docs/building.md +++ b/docs/building.md @@ -2,6 +2,23 @@ Here you will find instructions on how to install the necessary tools for building and running the app. +## Nix / direnv (recommended for macOS and Linux) + +A `flake.nix` and `.envrc` provide a reproducible development environment on macOS (Determinate Nix on macOS Tahoe ARM tested), NixOS, and other Linux distributions. + +``` +# enter the dev shell +nix develop # or: direnv allow + +# build +make build-macos # on macOS +make build-linux # on Linux +``` + +The Makefile is the single entry point for all builds. Two Rust toolchains are provisioned by the flake: `stable` (default, used for frostdart / coinlib / secp256k1 / etc.) and `1.85.1` (pinned for `flutter_libepiccash` and `flutter_libmwc`). The bootstrap scripts `scripts/install_macos_build_tools.sh` and `scripts/install_nixos_build_tools.sh` install equivalent host toolchains for non-Nix setups. + +The legacy per-platform instructions below remain valid for developers who do not want to use Nix. + ## Prerequisites - The only OS supported for building Android and Linux desktop is Ubuntu 24.04. Windows builds require using Ubuntu 24.04 on WSL2. macOS builds for itself and iOS. Advanced users may also be able to build on other Debian-based distributions like Linux Mint. @@ -51,8 +68,8 @@ Install [Rust](https://www.rust-lang.org/tools/install) via [rustup.rs](https:// ``` curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source ~/.bashrc -rustup install 1.89.0 1.85.1 -rustup default 1.89.0 +rustup toolchain install stable 1.85.1 +rustup default stable cargo install cargo-ndk ``` @@ -198,12 +215,12 @@ brew install brotli cairo coreutils gdbm gettext glib gmp libevent libidn2 libng ``` -Download and install [Rust](https://www.rust-lang.org/tools/install). [Rustup](https://rustup.rs/) is recommended for Rust setup. Use `rustc` to confirm successful installation. Install toolchains 1.85.1 and 1.89.0 as well as `cbindgen` and `cargo-lipo` too. You will also have to add the platform target(s) `aarch64-apple-ios` and/or `aarch64-apple-darwin`. You can use the command(s): +Download and install [Rust](https://www.rust-lang.org/tools/install). [Rustup](https://rustup.rs/) is recommended for Rust setup. Use `rustc` to confirm successful installation. Install the `stable` toolchain and the `1.85.1` toolchain (pinned for libepiccash/libmwc), as well as `cbindgen` and `cargo-lipo`. You will also have to add the platform target(s) `aarch64-apple-ios` and/or `aarch64-apple-darwin`. You can use the command(s): ``` curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source ~/.bashrc -rustup install 1.89.0 1.85.1 -rustup default 1.89.0 +rustup toolchain install stable 1.85.1 +rustup default stable cargo install cargo-ndk cargo install cbindgen cargo-lipo rustup target add aarch64-apple-ios aarch64-apple-darwin @@ -283,10 +300,11 @@ Install Flutter 3.38.5 on your Windows host (not in WSL2) by [following their gu ### Rust Install [Rust](https://www.rust-lang.org/tools/install) on the Windows host (not in WSL2). Download the installer from [rustup.rs](https://rustup.rs), make sure it works on the commandline (you may need to open a new terminal), and install the following versions: ``` -rustup install 1.89.0 1.85.1 -rustup default 1.89.0 +rustup toolchain install stable 1.85.1 +rustup default stable cargo install cargo-ndk ``` +Note: the frostdart Windows build scripts additionally require Rust `1.71.0-x86_64-pc-windows-msvc` (and the `gnu` variant for cross-compiles). Install with `rustup toolchain install 1.71.0-x86_64-pc-windows-msvc` if you build on or for Windows. ### Windows SDK and Developer Mode Install the Windows SDK: https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/ You may need to install the [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/), which can be installed [by Visual Studio](https://stackoverflow.com/a/73923899) (`Tools > Get Tools and Features... > Modify > Individual Components > Windows 10 SDK`). From b4f75657c90f480bc088110e0a075e6acb51adcd Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 11 May 2026 08:22:22 +0200 Subject: [PATCH 099/118] gitignore: ignore generated CodexOverrides.xcconfig and flutter-create boilerplate --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 3880f3a1c..af144d8dd 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,9 @@ android/app/.cxx # Web related lib/generated_plugin_registrant.dart +# Flutter create boilerplate that gets regenerated on `flutter create --platforms=macos .` +test/widget_test.dart + # testing data test/services/coins/bitcoin/bitcoin_wallet_test_parameters.dart test/services/coins/firo/firo_wallet_test_parameters.dart @@ -100,6 +103,7 @@ pubspec.yaml /linux/my_application.cc /macos/Runner/Configs/AppInfo.xcconfig +/macos/Runner/Configs/CodexOverrides.xcconfig /macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme /macos/Runner.xcodeproj/project.pbxproj /macos/Runner/Assets.xcassets/AppIcon.appiconset/*.png From 6b72f09c2423b7a3cb50d2031d489570953dca1f Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 11 May 2026 08:22:35 +0200 Subject: [PATCH 100/118] build(macos): remove flutter-create boilerplate test after platform regeneration --- Makefile | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index d3ac0151d..c037fe270 100644 --- a/Makefile +++ b/Makefile @@ -43,12 +43,13 @@ help: ## Show available commands check-reqs: ## Verify essential build tools @echo "Checking core prerequisites..." - @command -v $(FLUTTER) >/dev/null 2>&1 || { echo >&2 "[ERROR] Flutter not installed."; exit 1; } - @command -v $(DART) >/dev/null 2>&1 || { echo >&2 "[ERROR] Dart not installed."; exit 1; } + @[ -n "$(FLUTTER)" ] && command -v "$(FLUTTER)" >/dev/null 2>&1 || { echo >&2 "[ERROR] Flutter not installed."; exit 1; } + @[ -n "$(DART)" ] && command -v "$(DART)" >/dev/null 2>&1 || { echo >&2 "[ERROR] Dart not installed."; exit 1; } @command -v rustup >/dev/null 2>&1 || { echo >&2 "[ERROR] rustup not installed."; exit 1; } @rustup which rustc >/dev/null 2>&1 || { echo >&2 "[ERROR] rustc toolchain not available via rustup."; exit 1; } @rustup which cargo >/dev/null 2>&1 || { echo >&2 "[ERROR] cargo toolchain not available via rustup."; exit 1; } @rustup run stable rustc -vV >/dev/null 2>&1 || { echo >&2 "[ERROR] rustup stable toolchain not available."; exit 1; } + @rustup run 1.85.1 rustc -vV >/dev/null 2>&1 || { echo >&2 "[ERROR] rustup 1.85.1 toolchain not available."; exit 1; } @command -v go >/dev/null 2>&1 || { echo >&2 "[ERROR] Go not installed."; exit 1; } @command -v cmake >/dev/null 2>&1 || { echo >&2 "[ERROR] CMake not installed."; exit 1; } @command -v meson >/dev/null 2>&1 || { \ @@ -201,6 +202,8 @@ macos-restore-metadata: $(FLUTTER) config --enable-macos-desktop >/dev/null @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ $(FLUTTER) create --platforms=macos . > /dev/null + @# `flutter create` synthesizes a counter-app widget test that doesn't apply to this app. + @rm -f test/widget_test.dart @rm -rf macos/Runner.xcworkspace macos/Pods macos/Podfile.lock @chmod -R u+rwX macos 2>/dev/null || true @chflags -R nouchg macos 2>/dev/null || true @@ -264,7 +267,7 @@ macos-build-native: @# Ensure local rustup home has a usable default toolchain for native plugin scripts. @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" CARGO_HOME="$(PROJECT_CARGO_HOME)" \ - rustup toolchain install stable 1.85.1 >/dev/null + rustup toolchain install --no-self-update stable 1.85.1 >/dev/null @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" CARGO_HOME="$(PROJECT_CARGO_HOME)" \ rustup default stable >/dev/null @@ -283,6 +286,7 @@ macos-build-native: PUB_CACHE="$(PUB_CACHE)" \ RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" \ CARGO_HOME="$(PROJECT_CARGO_HOME)" \ + CARGO_TARGET_AARCH64_APPLE_DARWIN_LINKER="/usr/bin/clang" \ MAKEFLAGS= \ MFLAGS= \ CARGO_MAKEFLAGS= \ @@ -295,7 +299,7 @@ macos-build-native: bash scripts/macos/build_all.sh @rm -rf build/secp256k1 @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ - $(FLUTTER) dart run coinlib:build_macos + $(FLUTTER) pub run coinlib:build_macos @echo "--- Patching Podfile..." @sed -i.bak -e "s/platform :osx, '10.11'/platform :osx, '11.0'/g" -e "s/platform :osx, '10.15'/platform :osx, '11.0'/g" macos/Podfile 2>/dev/null || true @rm -f macos/Podfile.bak @@ -308,16 +312,21 @@ macos-build-app: @# Reassert macOS platform metadata in the same local HOME used for the final build. @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ $(FLUTTER) create --platforms=macos . --no-pub >/dev/null + @# `flutter create` synthesizes a counter-app widget test that doesn't apply to this app. + @rm -f test/widget_test.dart + @chmod -R u+w macos/Runner.xcworkspace macos/Runner.xcodeproj 2>/dev/null || true @# Cargokit calls `rustup run stable cargo ...`; ensure local `stable` exists and is selected. @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" CARGO_HOME="$(PROJECT_CARGO_HOME)" \ - rustup toolchain install stable >/dev/null + rustup toolchain install --no-self-update stable >/dev/null @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" CARGO_HOME="$(PROJECT_CARGO_HOME)" \ rustup default stable >/dev/null @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" CARGO_HOME="$(PROJECT_CARGO_HOME)" \ rustup run stable rustc -V + @echo "--- Cleaning stale Spark Mobile framework from local pub cache..." + @find "$(PUB_CACHE)/git" -path '*/flutter_libsparkmobile-*/macos/flutter_libsparkmobile.framework' -prune -exec rm -rf {} + 2>/dev/null || true @env $(MACOS_ENV_UNSET) $(MACOS_ENV_SET) \ HOME="$(PROJECT_HOME)" \ XDG_CACHE_HOME="$(PROJECT_CACHE)" \ @@ -326,6 +335,7 @@ macos-build-app: RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" \ CARGO_HOME="$(PROJECT_CARGO_HOME)" \ RUSTUP_TOOLCHAIN="$(MACOS_FINAL_RUST_TOOLCHAIN)" \ + CARGO_TARGET_AARCH64_APPLE_DARWIN_LINKER="/usr/bin/clang" \ PATH="$(PROJECT_CARGO_HOME)/bin:$$(dirname "$$(rustup which rustc)"):$${PATH}" \ ARCHS=arm64 EXCLUDED_ARCHS=x86_64 ONLY_ACTIVE_ARCH=YES $(FLUTTER) build macos --release @@ -385,7 +395,7 @@ build-linux: check-reqs init patch-submodules ## Build Linux Release 'Cflags: -I$${includedir} -I$${includedir}/_build' \ > scripts/linux/pc/libsecret-1.pc @if command -v podman >/dev/null 2>&1 || command -v docker >/dev/null 2>&1; then \ - $(FLUTTER) dart run coinlib:build_linux; \ + $(FLUTTER) pub run coinlib:build_linux; \ else \ echo "[WARN] podman/docker not found; skipping coinlib:build_linux"; \ fi From 0f17367312868fd1f59cf22641234986b1f06b69 Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 11 May 2026 08:23:19 +0200 Subject: [PATCH 101/118] flake(nix): pin Rust to stable + 1.85.1 and ensure clang symlinks --- flake.nix | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/flake.nix b/flake.nix index ac000a52b..d26ce9944 100644 --- a/flake.nix +++ b/flake.nix @@ -63,14 +63,16 @@ # ========================================== # RUST TOOLCHAIN AUTOMATION # ========================================== - if ! rustup toolchain list | grep -q "stable"; then + if ! rustup toolchain list | grep -q "stable" || ! rustup toolchain list | grep -q "1.85.1"; then echo "Initializing Rust toolchains (this happens only once)..." - rustup install 1.85.1 stable - rustup default stable - - if [[ "${system}" == *"darwin"* ]]; then - rustup target add aarch64-apple-darwin aarch64-apple-ios - fi + rustup toolchain install --no-self-update stable 1.85.1 + fi + + rustup default stable + + if [[ "${system}" == *"darwin"* ]]; then + rustup target add aarch64-apple-darwin aarch64-apple-ios --toolchain stable + rustup target add aarch64-apple-darwin --toolchain 1.85.1 fi if ! command -v cbindgen >/dev/null 2>&1 || ! command -v cargo-lipo >/dev/null 2>&1; then @@ -109,6 +111,8 @@ export BINDGEN_EXTRA_CLANG_ARGS="-isysroot $SDKROOT" mkdir -p .nix-bin + ln -sf /usr/bin/clang .nix-bin/cc + ln -sf /usr/bin/clang++ .nix-bin/c++ ln -sf /usr/bin/xcodebuild .nix-bin/xcodebuild ln -sf /usr/bin/clang .nix-bin/clang ln -sf /usr/bin/clang++ .nix-bin/clang++ From 94e10ecc1495d71d7726ecd236b683fce813ab3f Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 11 May 2026 14:10:36 +0200 Subject: [PATCH 102/118] add MWC FFI integration smoke test and make test-mwc target --- Makefile | 16 +- integration_test/mwc_ffi_test.dart | 16 + integration_test/mwc_ffi_test_service.dart | 995 +++++++++++++++++++++ integration_test/mwc_test_result.dart | 28 + 4 files changed, 1054 insertions(+), 1 deletion(-) create mode 100644 integration_test/mwc_ffi_test.dart create mode 100644 integration_test/mwc_ffi_test_service.dart create mode 100644 integration_test/mwc_test_result.dart diff --git a/Makefile b/Makefile index c037fe270..6f0f65dee 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,8 @@ export PUB_CACHE .PHONY: help check-reqs check-reqs-macos check-reqs-windows check-macos-sdk bootstrap-macos macos-local-state init clean prebuild-unix prebuild-windows deps-linux patch-submodules \ build-linux build-macos build-ios build-android build-windows \ - macos-prepare macos-configure macos-restore-metadata macos-build-native macos-build-app diagnose-macos-env + macos-prepare macos-configure macos-restore-metadata macos-build-native macos-build-app diagnose-macos-env \ + test-mwc help: ## Show available commands @echo "Available targets:" @@ -339,6 +340,19 @@ macos-build-app: PATH="$(PROJECT_CARGO_HOME)/bin:$$(dirname "$$(rustup which rustc)"):$${PATH}" \ ARCHS=arm64 EXCLUDED_ARCHS=x86_64 ONLY_ACTIVE_ARCH=YES $(FLUTTER) build macos --release +test-mwc: ## Run MWC FFI integration test on macOS (assumes prior `make build-macos`) + @# Flutter's first-launch helper rewrites MACOSX_DEPLOYMENT_TARGET=10.15; reassert 11.0. + @sed -i.bak -e "s/MACOSX_DEPLOYMENT_TARGET = 10\\.15;/MACOSX_DEPLOYMENT_TARGET = 11.0;/g" macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true + @rm -f macos/Runner.xcodeproj/project.pbxproj.bak + @env $(MACOS_ENV_UNSET) $(MACOS_ENV_SET) \ + HOME="$(PROJECT_HOME)" \ + XDG_CACHE_HOME="$(PROJECT_CACHE)" \ + TMPDIR="$(PROJECT_TMP)" \ + PUB_CACHE="$(PUB_CACHE)" \ + RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" \ + CARGO_HOME="$(PROJECT_CARGO_HOME)" \ + $(FLUTTER) test integration_test/mwc_ffi_test.dart -d macos + diagnose-macos-env: ## Print macOS build env and tool resolution @echo "--- Toolchain diagnostics ---" @echo "flutter: $$(command -v $(FLUTTER) || echo missing)" diff --git a/integration_test/mwc_ffi_test.dart b/integration_test/mwc_ffi_test.dart new file mode 100644 index 000000000..7c1abd75b --- /dev/null +++ b/integration_test/mwc_ffi_test.dart @@ -0,0 +1,16 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'mwc_ffi_test_service.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + testWidgets('MWC FFI smoke', (tester) async { + await FFITestService.initialize(); + final ok = await FFITestService.runAllTests(); + expect(ok, isTrue, + reason: FFITestService.testResults + .where((r) => !r.passed) + .map((r) => '${r.name}: ${r.error}') + .join('\n')); + }); +} diff --git a/integration_test/mwc_ffi_test_service.dart b/integration_test/mwc_ffi_test_service.dart new file mode 100644 index 000000000..953a3e6b6 --- /dev/null +++ b/integration_test/mwc_ffi_test_service.dart @@ -0,0 +1,995 @@ +import 'dart:io'; +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter_libmwc/lib.dart'; +import 'package:flutter_libmwc/mwc.dart' as lib_mwc; +import 'package:path_provider/path_provider.dart'; +import 'mwc_test_result.dart'; + +/// Comprehensive FFI integration test service. +class FFITestService { + static final List _testResults = []; + static bool _isInitialized = false; + + /// Initialize the test framework. + static Future initialize() async { + if (_isInitialized) return; + + _logInfo('FFI Test Service initialized successfully'); + _isInitialized = true; + } + + /// Get all test results. + static List get testResults => List.unmodifiable(_testResults); + + /// Clear all test results. + static void clearResults() { + _testResults.clear(); + _logInfo('Test results cleared'); + } + + /// Run all FFI integration tests. + static Future runAllTests() async { + if (!_isInitialized) { + throw StateError('FFI Test Service not initialized'); + } + + clearResults(); + _logInfo('Starting comprehensive FFI integration test suite'); + + bool allPassed = true; + + // Phase 1: Environment and pre-flight validation. + allPassed &= await _runEnvironmentTests(); + + // Phase 2: Basic FFI functionality. + allPassed &= await _runBasicFFITests(); + + // Phase 3: Wallet management tests. + allPassed &= await _runWalletManagementTests(); + + // Phase 4: Transaction functionality tests. + allPassed &= await _runTransactionTests(); + + // Phase 5: Basic slatepack functionality tests. + allPassed &= await _runSlatepackTests(); + + // Phase 6: MWCMQS listener functionality tests. + allPassed &= await _runMWCMQSTests(); + + _logInfo('Test suite completed. Overall result: ${allPassed ? "PASS" : "FAIL"}'); + return allPassed; + } + + /// Run environment validation tests. + static Future _runEnvironmentTests() async { + bool allPassed = true; + + // Test 1: Platform detection. + allPassed &= await _runTest( + 'Platform Detection', + 'Verify current platform is correctly detected', + () async { + final platform = Platform.operatingSystem; + final supportedPlatforms = ['linux', 'windows', 'macos', 'android', 'ios']; + + if (!supportedPlatforms.contains(platform)) { + throw TestException('Unsupported platform: $platform'); + } + + return 'Platform: $platform (supported)'; + } + ); + + // Test 2: Library loading. + allPassed &= await _runTest( + 'Library Loading', + 'Verify native library can be loaded', + () async { + try { + final mnemonic = Libmwc.getMnemonic(); + if (mnemonic.isEmpty) { + throw TestException('Library loaded but basic function returned empty result'); + } + return 'Library loaded successfully, basic function operational'; + } catch (e) { + throw TestException('Failed to load or call native library: $e'); + } + } + ); + + return allPassed; + } + + /// Run basic FFI functionality tests. + static Future _runBasicFFITests() async { + bool allPassed = true; + + // Test 1: Mnemonic generation. + allPassed &= await _runTest( + 'Mnemonic Generation', + 'Test FFI mnemonic generation function', + () async { + final mnemonic = Libmwc.getMnemonic(); + final words = mnemonic.split(' '); + + if (words.length != 24) { + throw TestException('Invalid mnemonic length: ${words.length} (expected 24)'); + } + + return 'Generated 24-word mnemonic successfully'; + } + ); + + // Test 2: Address validation. + allPassed &= await _runTest( + 'Address Validation', + 'Test FFI address validation function', + () async { + // Test with known invalid address. + final invalidResult = Libmwc.validateSendAddress(address: 'invalid_address'); + if (invalidResult) { + throw TestException('Invalid address incorrectly validated as valid'); + } + + return 'Address validation working correctly'; + } + ); + + return allPassed; + } + + /// Run wallet management integration tests. + static Future _runWalletManagementTests() async { + bool allPassed = true; + + // Test 1: Wallet configuration validation. + allPassed &= await _runTest( + 'Wallet Configuration', + 'Test wallet configuration creation and validation', + () async { + final testConfig = await _getTestWalletConfig(); + if (testConfig.isEmpty) { + throw TestException('Failed to create test wallet configuration'); + } + + // Validate config contains required fields. + final configData = {'wallet_dir': '', 'check_node_api_http_addr': '', 'chain': ''}; + for (final key in configData.keys) { + if (!testConfig.contains(key)) { + throw TestException('Missing required config field: $key'); + } + } + + return 'Test wallet configuration created and validated successfully'; + } + ); + + // Test 2: Wallet initialization. + allPassed &= await _runTest( + 'Wallet Initialization', + 'Test new wallet creation via FFI', + () async { + final testMnemonic = Libmwc.getMnemonic(); + final testConfig = await _getTestWalletConfig(); + final testPassword = 'test_password_123'; + final walletName = 'ffi_test_wallet_${DateTime.now().millisecondsSinceEpoch}'; + + try { + final result = await Libmwc.initializeNewWallet( + config: testConfig, + mnemonic: testMnemonic, + password: testPassword, + name: walletName, + ); + + if (result.toUpperCase().contains('ERROR')) { + throw TestException('Wallet initialization failed: $result'); + } + + return 'New wallet initialized successfully: $walletName'; + + } catch (e) { + // Expected to potentially fail if wallet already exists or other issues. + if (e.toString().contains('already exists')) { + return 'Wallet initialization handled existing wallet correctly'; + } + rethrow; + } + } + ); + + // Test 3: Wallet recovery. + allPassed &= await _runTest( + 'Wallet Recovery', + 'Test wallet recovery from mnemonic via FFI', + () async { + final testMnemonic = Libmwc.getMnemonic(); + final testConfig = await _getTestWalletConfig(); + final testPassword = 'recovery_test_123'; + final walletName = 'ffi_recovery_test_${DateTime.now().millisecondsSinceEpoch}'; + + try { + await Libmwc.recoverWallet( + config: testConfig, + password: testPassword, + mnemonic: testMnemonic, + name: walletName, + ); + + return 'Wallet recovery from mnemonic completed successfully'; + + } catch (e) { + // Expected to potentially fail in test environment. + if (e.toString().contains('directory') || e.toString().contains('permission')) { + return 'Wallet recovery handled filesystem constraints correctly'; + } + throw TestException('Unexpected error in wallet recovery: $e'); + } + } + ); + + // Test 4: Chain height retrieval. + allPassed &= await _runTest( + 'Chain Height Query', + 'Test chain height retrieval via FFI using remote MWC node', + () async { + final testConfig = await _getTestWalletConfig(); + + try { + final height = await Libmwc.getChainHeight(config: testConfig); + + if (height < 0) { + throw TestException('Invalid chain height returned: $height'); + } + + // Mainnet should have a reasonable height (over 1 million blocks as of 2024). + if (height < 1000000) { + throw TestException('Chain height seems too low for mainnet: $height'); + } + + return 'Chain height retrieved successfully: $height (mainnet)'; + + } catch (e) { + final errorStr = e.toString(); + + // Handle specific error types with more detail. + if (errorStr.contains('FormatException') || errorStr.contains('Invalid radix-10')) { + throw TestException('Failed to parse chain height response: node may have returned an error message instead of height'); + } else if (errorStr.contains('connection') || errorStr.contains('network') || errorStr.contains('timeout')) { + throw TestException('Network connection issue with remote node: ${errorStr.substring(0, 100)}...'); + } else if (errorStr.contains('Cannot m')) { + throw TestException('Remote node connection failed - possibly network or SSL issue'); + } + + // Re-throw with more context. + throw TestException('Chain height query failed: ${errorStr.substring(0, 100)}...'); + } + } + ); + + return allPassed; + } + + static Future _runTransactionTests() async { + bool allPassed = true; + + // Test 1: Transaction function availability. + allPassed &= await _runTest( + 'Transaction Function Availability', + 'Verify transaction functions are available via FFI', + () async { + // Test that transaction functions exist and can be called. + // This validates the FFI bindings are working without requiring an actual wallet. + + try { + // First test: Validate address format function (should not panic). + final isValid = Libmwc.validateSendAddress(address: 'test@example.com'); + + // This should return false for a test address, but validates the function works. + if (isValid == true || isValid == false) { + return 'Transaction functions available: address validation working (result: $isValid)'; + } + + throw TestException('Address validation returned unexpected result'); + + } catch (e) { + final errorStr = e.toString(); + + // Any error here indicates a problem with the FFI bindings themselves. + throw TestException('Transaction function availability test failed: ${errorStr.substring(0, 100)}...'); + } + } + ); + + // Test 2: Transaction API Structure Validation. + allPassed &= await _runTest( + 'Transaction API Structure', + 'Validate transaction-related API structure and types', + () async { + try { + // Test that we can create test configuration without errors. + final testConfig = await _getTestWalletConfig(); + + if (!testConfig.contains('wallet_dir') || + !testConfig.contains('check_node_api_http_addr') || + !testConfig.contains('chain')) { + throw TestException('Test configuration missing required fields'); + } + + // Test basic type validation. + const testAmount = 1000000; + const minConfirmations = 10; + + if (testAmount <= 0 || minConfirmations <= 0) { + throw TestException('Transaction parameter validation failed'); + } + + return 'Transaction API structure validation passed: config format and parameter types correct'; + + } catch (e) { + throw TestException('Transaction API structure test failed: ${e.toString().substring(0, 100)}...'); + } + } + ); + + // Test 3: Transaction Model Validation. + allPassed &= await _runTest( + 'Transaction Model Validation', + 'Validate transaction data models and type safety', + () async { + try { + // Test transaction model structure by creating instances. + // This validates the Dart-side transaction types without calling FFI. + + final testAmount = 1500000; // 0.0015 MWC. + final testAddress = 'test_user@mwcmqs.example.com'; + final testNote = 'FFI integration test transaction'; + + // Validate parameter constraints. + if (testAmount <= 0) { + throw TestException('Transaction amount validation failed'); + } + + if (testAddress.isEmpty || !testAddress.contains('@')) { + throw TestException('Transaction address validation failed'); + } + + if (testNote.length > 500) { + throw TestException('Transaction note length validation failed'); + } + + return 'Transaction model validation passed: amount=$testAmount, address format validated, note length OK'; + + } catch (e) { + throw TestException('Transaction model validation failed: ${e.toString().substring(0, 100)}...'); + } + } + ); + + // Test 4: Transaction Error Code Validation. + allPassed &= await _runTest( + 'Transaction Error Handling', + 'Validate transaction error handling patterns', + () async { + try { + // Test error message patterns that should be handled by transaction functions. + final expectedErrors = [ + 'wallet is not open', + 'WALLET_IS_NOT_OPEN', + 'insufficient funds', + 'invalid address', + 'network error', + 'connection timeout' + ]; + + // Validate we have error handling patterns for common issues. + for (final errorPattern in expectedErrors) { + if (errorPattern.isEmpty) { + throw TestException('Empty error pattern in validation list'); + } + } + + // Test amount boundary validation. + const minAmount = 1; + const maxAmount = 21000000 * 1000000000; // Max MWC supply in nanograms. + + if (minAmount >= maxAmount) { + throw TestException('Transaction amount boundary validation failed'); + } + + return 'Transaction error handling validation passed: ${expectedErrors.length} error patterns validated, amount boundaries correct'; + + } catch (e) { + throw TestException('Transaction error handling validation failed: ${e.toString().substring(0, 100)}...'); + } + } + ); + + return allPassed; + } + + /// Run basic slatepack functionality integration tests. + static Future _runSlatepackTests() async { + bool allPassed = true; + + // Test 1: Slatepack API Structure Validation. + allPassed &= await _runTest( + 'Slatepack API Structure', + 'Validate slatepack API structure and parameter types', + () async { + try { + // Test basic slatepack parameter validation. + const testSlateJson = '{"id":"test","tx":{"body":{"inputs":[],"outputs":[],"kernels":[]}}}'; + const testSlatepack = 'BEGINSLATEPACK. test slatepack data .ENDSLATEPACK'; + const testRecipientAddress = 'test_user@mwcmqs.example.com'; + + // Validate parameter constraints for encoding. + if (testSlateJson.isEmpty) { + throw TestException('Slate JSON validation failed'); + } + + if (!testSlateJson.contains('id')) { + throw TestException('Slate JSON structure validation failed'); + } + + // Validate slatepack format structure. + if (!testSlatepack.contains('BEGINSLATEPACK') || !testSlatepack.contains('ENDSLATEPACK')) { + throw TestException('Slatepack format validation failed'); + } + + // Validate address format. + if (testRecipientAddress.isEmpty || !testRecipientAddress.contains('@')) { + throw TestException('Recipient address format validation failed'); + } + + return 'Slatepack API structure validation passed: slate format, slatepack format, and address format correct'; + + } catch (e) { + throw TestException('Slatepack API structure test failed: ${e.toString().substring(0, 100)}...'); + } + } + ); + + // Test 2: Slatepack Format Validation. + allPassed &= await _runTest( + 'Slatepack Format Validation', + 'Validate slatepack format patterns and structure', + () async { + try { + // Test various slatepack format patterns. + final validFormats = [ + 'BEGINSLATEPACK. test data .ENDSLATEPACK', + 'BEGINSLATEPACK.\nencoded_data_here\n.ENDSLATEPACK', + 'BEGINSLATEPACK. VGVzdCBkYXRh .ENDSLATEPACK', // Base64-like. + ]; + + final invalidFormats = [ + 'INVALID FORMAT', + 'BEGINSLATEPACK without end', + 'missing begin ENDSLATEPACK', + '', + 'BEGINSLATE PACK. test .ENDSLATEPACK', // Wrong format. + ]; + + // Validate all valid formats pass basic structure check. + for (final format in validFormats) { + if (!format.contains('BEGINSLATEPACK') || !format.contains('ENDSLATEPACK')) { + throw TestException('Valid slatepack format failed validation: $format'); + } + } + + // Validate all invalid formats fail basic structure check. + for (final format in invalidFormats) { + if (format.contains('BEGINSLATEPACK') && format.contains('ENDSLATEPACK')) { + throw TestException('Invalid slatepack format passed validation: $format'); + } + } + + return 'Slatepack format validation passed: ${validFormats.length} valid formats recognized, ${invalidFormats.length} invalid formats rejected'; + + } catch (e) { + throw TestException('Slatepack format validation failed: ${e.toString().substring(0, 100)}...'); + } + } + ); + + // Test 3: Slatepack Roundtrip (compact, unencrypted). + allPassed &= await _runTest( + 'Slatepack Roundtrip (compact)', + 'Encode compact slate JSON to slatepack and decode back via FFI', + () async { + try { + // Construct a minimal compact slate JSON. + // Use version 3 + compact_slate flag to satisfy current lib expectations. + const compactSlateJson = '{\n' + ' "version_info": {\n' + ' "orig_version": 3,\n' + ' "version": 3,\n' + ' "block_header_version": 1\n' + ' },\n' + ' "id": "0436430c-2b02-624c-2032-570501212b00",\n' + ' "sta": "S1",\n' + ' "num_participants": 2,\n' + ' "amount": "1000000000",\n' + ' "fee": "1000000",\n' + ' "height": "0",\n' + ' "lock_height": "0",\n' + ' "ttl_cutoff_height": "1440",\n' + ' "payment_proof": null,\n' + ' "compact_slate": true,\n' + ' "participant_data": []\n' + '}'; + + // Encode to slatepack (unencrypted) — recipientAddress null. + final enc = await Libmwc.encodeSlatepack( + slateJson: compactSlateJson, + recipientAddress: null, + encrypt: false, + ); + + // Basic format assertions. + if (!enc.slatepack.contains('BEGINSLATEPACK') || + !enc.slatepack.contains('ENDSLATEPACK')) { + throw TestException('Encoded slatepack missing BEGIN/END markers'); + } + if (enc.wasEncrypted) { + throw TestException('Unencrypted encode reported as encrypted'); + } + + // Decode back to JSON. + final dec = await Libmwc.decodeSlatepack(slatepack: enc.slatepack); + final decoded = jsonDecode(dec.slateJson) as Map; + final decodedId = decoded['id'] as String?; + final versionInfo = decoded['version_info'] as Map?; + if (decodedId != '0436430c-2b02-624c-2032-570501212b00') { + throw TestException('Decoded slate id mismatch or missing: $decodedId'); + } + if (versionInfo == null || versionInfo['version'] != 3) { + throw TestException('Decoded slate version is not v3'); + } + + // Verify encryption detection helper. + final isEncrypted = await Libmwc.isSlatepackEncrypted(enc.slatepack); + if (isEncrypted) { + throw TestException('isSlatepackEncrypted returned true for unencrypted slatepack'); + } + + return 'Roundtrip succeeded; id=$decodedId; v4 compact; markers present; not encrypted'; + } catch (e) { + throw TestException('Slatepack roundtrip (compact) failed: $e'); + } + }, + ); + + // Test 4: Slatepack Encryption Requirements (expected failure without wallet context). + allPassed &= await _runTest( + 'Slatepack Encryption Requirements', + 'Verify encrypted encode requires wallet context and recipient', + () async { + try { + bool threw = false; + try { + await Libmwc.encodeSlatepack( + slateJson: '{"id":"abc","version_info":{"version":3,"block_header_version":1}}', + recipientAddress: 'dummy@mwcmqs.mwc.mw', + encrypt: true, + wallet: null, // No wallet context in test environment + ); + } catch (e) { + threw = true; + final msg = e.toString(); + if (!msg.toLowerCase().contains('wallet') || + !msg.toLowerCase().contains('required')) { + throw TestException('Unexpected error for encrypted encode without wallet: $msg'); + } + } + if (!threw) { + throw TestException('Encrypted encode did not throw without wallet context'); + } + return 'Encrypted encode correctly requires wallet context'; + } catch (e) { + throw TestException('Encryption requirement validation failed: $e'); + } + }, + ); + + // Test 5: Slatepack Decode Invalid Format Handling. + allPassed &= await _runTest( + 'Slatepack Decode Invalid Format', + 'Decode invalid slatepack and validate graceful handling', + () async { + try { + final bogus = 'NOT_A_SLATEPACK'; + try { + final dec = await Libmwc.decodeSlatepack(slatepack: bogus); + // High-level API may not throw; validate empty slate JSON returned. + if (dec.slateJson.isNotEmpty) { + throw TestException('Invalid slatepack returned non-empty slate JSON'); + } + return 'Invalid slatepack handled gracefully (empty slate JSON)'; + } catch (e) { + // If it throws, that's also acceptable as graceful failure. + final es = e.toString(); + final trunc = es.substring(0, es.length < 80 ? es.length : 80); + return 'Invalid slatepack decode threw as expected: $trunc...'; + } + } catch (e) { + throw TestException('Invalid format handling failed: $e'); + } + }, + ); + + // Test 3: Slatepack Encoding Parameter Validation. + allPassed &= await _runTest( + 'Slatepack Encoding Parameters', + 'Validate slatepack encoding parameter handling', + () async { + try { + // Test encoding parameter validation without calling actual FFI. + final testCases = [ + { + 'name': 'basic slate', + 'slateJson': '{"id":"test-123","version_info":{"version":3,"block_header_version":1}}', + 'encrypt': false, + 'recipientAddress': null, + }, + { + 'name': 'encrypted slate', + 'slateJson': '{"id":"test-456","version_info":{"version":3,"block_header_version":1}}', + 'encrypt': true, + 'recipientAddress': 'user@mwcmqs.example.com', + }, + ]; + + for (final testCase in testCases) { + final slateJson = testCase['slateJson'] as String; + final encrypt = testCase['encrypt'] as bool; + final recipientAddress = testCase['recipientAddress'] as String?; + + // Validate slate JSON structure. + if (!slateJson.contains('id')) { + throw TestException('Test case ${testCase['name']} missing required slate ID'); + } + + // Validate encryption parameters. + if (encrypt && (recipientAddress == null || recipientAddress.isEmpty)) { + throw TestException('Test case ${testCase['name']} encryption requires recipient address'); + } + + // Validate address format if provided. + if (recipientAddress != null && !recipientAddress.contains('@')) { + throw TestException('Test case ${testCase['name']} invalid recipient address format'); + } + } + + return 'Slatepack encoding parameter validation passed: ${testCases.length} test cases validated'; + + } catch (e) { + throw TestException('Slatepack encoding parameter validation failed: ${e.toString().substring(0, 100)}...'); + } + } + ); + + // Test 4: Slatepack Decoding Parameter Validation. + allPassed &= await _runTest( + 'Slatepack Decoding Parameters', + 'Validate slatepack decoding parameter handling and response structure', + () async { + try { + // Test decoding parameter validation and expected response structure. + final testSlatepack = 'BEGINSLATEPACK. dGVzdCBkYXRh .ENDSLATEPACK'; + + // Validate slatepack format. + if (!testSlatepack.contains('BEGINSLATEPACK') || !testSlatepack.contains('ENDSLATEPACK')) { + throw TestException('Test slatepack format validation failed'); + } + + // Define expected decode response structure. + final expectedFields = [ + 'slate_json', + 'sender', // nullable. + 'recipient', // nullable. + ]; + + // Validate we have proper validation for expected response fields. + for (final field in expectedFields) { + if (field.isEmpty) { + throw TestException('Empty expected field in validation list'); + } + } + + // Test decoding error scenarios. + final errorTestCases = [ + { + 'input': '', + 'expectedError': 'empty slatepack', + }, + { + 'input': 'INVALID FORMAT', + 'expectedError': 'invalid format', + }, + { + 'input': 'BEGINSLATEPACK. corrupted_data .ENDSLATEPACK', + 'expectedError': 'decoding error', + }, + ]; + + // Validate error cases are properly structured. + for (final testCase in errorTestCases) { + final input = testCase['input'] as String; + final expectedError = testCase['expectedError'] as String; + + if (input.isEmpty && expectedError != 'empty slatepack') { + throw TestException('Error test case mismatch: empty input should expect empty slatepack error'); + } + } + + return 'Slatepack decoding parameter validation passed: ${expectedFields.length} response fields validated, ${errorTestCases.length} error cases structured'; + + } catch (e) { + throw TestException('Slatepack decoding parameter validation failed: ${e.toString().substring(0, 100)}...'); + } + } + ); + + return allPassed; + } + + /// Run MWCMQS listener functionality integration tests. + static Future _runMWCMQSTests() async { + bool allPassed = true; + + // Test 1: MWCMQS API Function Availability. + allPassed &= await _runTest( + 'MWCMQS API Function Availability', + 'Verify MWCMQS FFI functions are properly loaded and accessible', + () async { + try { + // Test that we can access the MWCMQS FFI functions through the native library. + // Try to call the FFI functions with test parameters to verify they're accessible. + + // Verify the mwcMqsListenerStart function exists by trying to call it. + try { + final testWallet = '[test_handle]'; + final testConfig = '{"test":"config"}'; + // This will likely fail but confirms the function is accessible. + lib_mwc.mwcMqsListenerStart(testWallet, testConfig); + return 'MWCMQS FFI functions verified: mwcMqsListenerStart accessible and callable'; + } catch (functionError) { + // Expected to fail with invalid parameters, but function should be accessible. + if (functionError.toString().contains('NoSuchMethodError')) { + throw TestException('MWCMQS start function not available: ${functionError.toString()}'); + } + return 'MWCMQS FFI functions verified: mwcMqsListenerStart accessible (failed with expected error: ${functionError.toString().substring(0, 50)}...)'; + } + } catch (e) { + throw TestException('MWCMQS API function availability test failed: ${e.toString()}'); + } + } + ); + + // Test 2: MWCMQS Listener Configuration. + allPassed &= await _runTest( + 'MWCMQS Listener Configuration', + 'Test MWCMQS configuration JSON creation and validation', + () async { + try { + // Create a MWCMQS configuration. + final mwcmqsConfig = jsonEncode({ + 'mwcmqs_domain': 'mqs.mwc.mw', + 'mwcmqs_port': 443, + 'mwcmqs_use_ssl': true, + }); + + // Validate configuration can be parsed. + final configData = jsonDecode(mwcmqsConfig); + if (configData['mwcmqs_domain'] != 'mqs.mwc.mw' || + configData['mwcmqs_port'] != 443 || + configData['mwcmqs_use_ssl'] != true) { + throw TestException('MWCMQS configuration validation failed'); + } + + return 'MWCMQS configuration created and validated: $mwcmqsConfig'; + } catch (e) { + throw TestException('MWCMQS configuration test failed: ${e.toString()}'); + } + } + ); + + // Test 3: MWCMQS Listener Start/Stop API. + allPassed &= await _runTest( + 'MWCMQS Listener Start/Stop API', + 'Test MWCMQS listener API accessibility and parameter validation', + () async { + try { + // Test that the MWCMQS functions are accessible and accept parameters correctly. + // We'll test with invalid parameters to avoid network calls that might crash. + + // Test listener start function accessibility. + try { + // Use clearly invalid parameters that should trigger a controlled error. + final invalidWallet = 'invalid_wallet_handle'; + final invalidConfig = '{"invalid": "config"}'; + + // This should fail gracefully with a parameter error, not crash. + final result = lib_mwc.mwcMqsListenerStart(invalidWallet, invalidConfig); + + // If we get a result without crashing, that's unexpected but good. + return 'MWCMQS listener API accessible: start function callable, returned pointer ${result.address}'; + + } catch (apiError) { + // We expect this to fail with invalid parameters, which is good. + // Check that it's a controlled error, not a crash. + final errorString = apiError.toString(); + + if (errorString.contains('invalid') || + errorString.contains('parameter') || + errorString.contains('format') || + errorString.contains('parse') || + errorString.contains('wallet') || + errorString.contains('config')) { + return 'MWCMQS listener API validated: start function accessible and properly validates parameters (error: ${errorString.substring(0, 60)}...)'; + } + + // If it's some other error, that's still validation that the function exists. + return 'MWCMQS listener API accessible: start function exists and callable (failed with: ${errorString.substring(0, 60)}...)'; + } + + } catch (e) { + throw TestException('MWCMQS listener API test failed: ${e.toString()}'); + } + } + ); + + // Test 4: MWCMQS High-Level API Integration. + allPassed &= await _runTest( + 'MWCMQS High-Level API Integration', + 'Test high-level ListenerManager API for MWCMQS functionality', + () async { + try { + // Test that Libmwc MWCMQS functions are accessible. + // We can't check if methods are null, so we'll try to call them. + try { + // Try to access the methods - this will throw if they don't exist. + final startMethod = Libmwc.startMwcMqsListener; + final stopMethod = Libmwc.stopMwcMqsListener; + + // If we get here, methods exist. + } catch (methodError) { + throw TestException('Libmwc MWCMQS methods not available: ${methodError.toString()}'); + } + + // Test high-level API call structure. + try { + // This should fail gracefully since we don't have a real wallet/server. + Libmwc.startMwcMqsListener( + wallet: '[test_wallet_handle]', + mwcmqsConfig: jsonEncode({ + 'mwcmqs_domain': 'mqs.mwc.mw', + 'mwcmqs_port': 443, + 'mwcmqs_use_ssl': true, + }), + ); + + // If we get here, the API call structure is correct. + return 'MWCMQS high-level API integration validated: Libmwc methods accessible and callable'; + + } catch (apiError) { + // Expected to fail without real wallet, but validates API structure. + if (apiError.toString().contains('handle') || + apiError.toString().contains('wallet') || + apiError.toString().contains('connection') || + apiError.toString().contains('invalid')) { + return 'MWCMQS high-level API structure validated (expected failure without real wallet): ${apiError.toString().substring(0, 80)}...'; + } + throw apiError; + } + + } catch (e) { + throw TestException('MWCMQS high-level API integration test failed: ${e.toString()}'); + } + } + ); + + return allPassed; + } + + /// Get test wallet configuration. + static Future _getTestWalletConfig() async { + final walletDir = await _getTestWalletDir(); + final config = { + 'wallet_dir': walletDir, + 'check_node_api_http_addr': 'https://mwc713.mwc.mw:443', // Working remote node. + 'chain': 'mainnet', // Use mainnet since remote node is mainnet. + 'account': 'default', + }; + + return '{"wallet_dir":"${config['wallet_dir']}","check_node_api_http_addr":"${config['check_node_api_http_addr']}","chain":"${config['chain']}","account":"${config['account']}"}'; + } + + /// Run a single test with proper error handling and result tracking. + static Future _runTest( + String name, + String description, + Future Function() testFunction, + ) async { + _logInfo('Running test: $name'); + + final stopwatch = Stopwatch()..start(); + + try { + final result = await testFunction(); + stopwatch.stop(); + + _testResults.add(TestResult( + name: name, + description: description, + passed: true, + duration: stopwatch.elapsed, + result: result, + )); + + _logInfo('Test PASSED: $name (${stopwatch.elapsedMilliseconds}ms)'); + return true; + + } catch (e, stackTrace) { + stopwatch.stop(); + + _testResults.add(TestResult( + name: name, + description: description, + passed: false, + duration: stopwatch.elapsed, + error: e.toString(), + stackTrace: stackTrace.toString(), + )); + + _logError('Test FAILED: $name - $e'); + return false; + } + } + + /// Log info message. + static void _logInfo(String message) { + final timestamp = DateTime.now().toIso8601String(); + debugPrint('[$timestamp] [INFO] $message'); + } + + /// Log error message. + static void _logError(String message) { + final timestamp = DateTime.now().toIso8601String(); + debugPrint('[$timestamp] [ERROR] $message'); + } + + /// Get appropriate test wallet directory for current platform. + static Future _getTestWalletDir() async { + if (Platform.isAndroid) { + return '/data/data/com.example.flutter_libmwc_example/files/ffi_test_wallets/'; + } else if (Platform.isIOS) { + // Use proper iOS Application Support directory instead of hardcoded path + final appSupportDir = await getApplicationSupportDirectory(); + return '${appSupportDir.path}/ffi_test_wallets/'; + } else if (Platform.isLinux) { + return '/tmp/flutter_libmwc_ffi_test_wallets/'; + } else if (Platform.isWindows) { + return r'C:\temp\flutter_libmwc_ffi_test_wallets\'; + } else if (Platform.isMacOS) { + return '/tmp/flutter_libmwc_ffi_test_wallets/'; + } else { + return '/tmp/flutter_libmwc_ffi_test_wallets/'; + } + } +} + +/// Exception thrown during testing. +class TestException implements Exception { + final String message; + + const TestException(this.message); + + @override + String toString() => 'TestException: $message'; +} diff --git a/integration_test/mwc_test_result.dart b/integration_test/mwc_test_result.dart new file mode 100644 index 000000000..1768a8ce1 --- /dev/null +++ b/integration_test/mwc_test_result.dart @@ -0,0 +1,28 @@ +/// Represents the result of a single FFI integration test. +class TestResult { + final String name; + final String description; + final bool passed; + final Duration duration; + final String? result; + final String? error; + final String? stackTrace; + final DateTime timestamp; + + TestResult({ + required this.name, + required this.description, + required this.passed, + required this.duration, + this.result, + this.error, + this.stackTrace, + }) : timestamp = DateTime.now(); + + /// Get a summary string for this test result. + String get summary { + final status = passed ? 'PASS' : 'FAIL'; + final durationMs = duration.inMilliseconds; + return '$status: $name (${durationMs}ms)'; + } +} From 59975f2bd776819dc2d9fa2461c632c606c62d3b Mon Sep 17 00:00:00 2001 From: Lunar Dev Date: Mon, 11 May 2026 14:19:46 +0200 Subject: [PATCH 103/118] add MWC FFI integration smoke test and make test-mwc target (2) --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 6f0f65dee..ff860061d 100644 --- a/Makefile +++ b/Makefile @@ -344,6 +344,9 @@ test-mwc: ## Run MWC FFI integration test on macOS (assumes prior `make build-ma @# Flutter's first-launch helper rewrites MACOSX_DEPLOYMENT_TARGET=10.15; reassert 11.0. @sed -i.bak -e "s/MACOSX_DEPLOYMENT_TARGET = 10\\.15;/MACOSX_DEPLOYMENT_TARGET = 11.0;/g" macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true @rm -f macos/Runner.xcodeproj/project.pbxproj.bak + @# `flutter test` re-runs pod install which re-prepares flutter_libsparkmobile; remove stale framework so the prepare step can write. + @find "$(PUB_CACHE)/git" -path '*/flutter_libsparkmobile-*/macos/flutter_libsparkmobile.framework' -prune -exec rm -rf {} + 2>/dev/null || true + @chmod -R u+w macos/Runner.xcodeproj macos 2>/dev/null || true @env $(MACOS_ENV_UNSET) $(MACOS_ENV_SET) \ HOME="$(PROJECT_HOME)" \ XDG_CACHE_HOME="$(PROJECT_CACHE)" \ From dba97dc72b274856235cf7628e5eb39c9bb9c032 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Mon, 11 May 2026 23:24:14 -0500 Subject: [PATCH 104/118] fix(macos): bundle GNU rsync in flake to fix release_unpack_macos --- flake.nix | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index d26ce9944..af4a75349 100644 --- a/flake.nix +++ b/flake.nix @@ -23,8 +23,9 @@ pkg-config gnumake gnused - (python3.withPackages (ps: with ps; [ - pip toml tomli jinja2 markdown markupsafe pygments typogrify + rsync + (python3.withPackages (ps: with ps; [ + pip toml tomli jinja2 markdown markupsafe pygments typogrify ])) ]; From cac32a151c68d0414b77f713187d5d86f62d91c4 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Tue, 12 May 2026 13:29:48 -0500 Subject: [PATCH 105/118] build(macos): commit CodexOverrides.xcconfig include lines --- macos/Runner/Configs/Debug.xcconfig | 2 ++ macos/Runner/Configs/Release.xcconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/macos/Runner/Configs/Debug.xcconfig b/macos/Runner/Configs/Debug.xcconfig index 3bc8b00f1..dca4bc3ad 100644 --- a/macos/Runner/Configs/Debug.xcconfig +++ b/macos/Runner/Configs/Debug.xcconfig @@ -1,3 +1,5 @@ #include "../../Flutter/Flutter-Debug.xcconfig" #include "AppInfo.xcconfig" #include "Warnings.xcconfig" + +#include "CodexOverrides.xcconfig" diff --git a/macos/Runner/Configs/Release.xcconfig b/macos/Runner/Configs/Release.xcconfig index 71202c7d6..8702630bf 100644 --- a/macos/Runner/Configs/Release.xcconfig +++ b/macos/Runner/Configs/Release.xcconfig @@ -1,3 +1,5 @@ #include "../../Flutter/Flutter-Release.xcconfig" #include "AppInfo.xcconfig" #include "Warnings.xcconfig" + +#include "CodexOverrides.xcconfig" From bbf41dcac85079a531a9f227bc661fe4ae6257b1 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Tue, 12 May 2026 13:30:54 -0500 Subject: [PATCH 106/118] build(nix): pin nixpkgs rev for reproducible toolchain --- flake.lock | 2 +- flake.nix | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/flake.lock b/flake.lock index 1f675e1ee..12a8f2291 100644 --- a/flake.lock +++ b/flake.lock @@ -29,8 +29,8 @@ }, "original": { "owner": "NixOS", - "ref": "nixos-unstable", "repo": "nixpkgs", + "rev": "5b2c2d84341b2afb5647081c1386a80d7a8d8605", "type": "github" } }, diff --git a/flake.nix b/flake.nix index af4a75349..66a2f2cbc 100644 --- a/flake.nix +++ b/flake.nix @@ -2,7 +2,10 @@ description = "Stack Wallet Build Environment"; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + # Pinned to a specific nixpkgs rev for reproducible Flutter/Rust toolchain + # versions. Update via `nix flake lock --update-input nixpkgs` and re-test + # `make build-macos` and `make build-linux` before bumping. + nixpkgs.url = "github:NixOS/nixpkgs/5b2c2d84341b2afb5647081c1386a80d7a8d8605"; flake-utils.url = "github:numtide/flake-utils"; }; From 936192b1b149e929c37a17c870c2efc6ab4361e9 Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Wed, 13 May 2026 13:05:17 -0700 Subject: [PATCH 107/118] Add a Select Xcode step before the build that finds /Applications/Xcode*.app and switches xcode-select to it, so the CI runner uses the full Xcode SDK instead of CLI tools. --- .github/workflows/test.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index defb31451..1e306c2f0 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -102,5 +102,15 @@ jobs: - name: Install macOS build dependencies run: ./scripts/install_macos_build_tools.sh + - name: Select Xcode + run: | + XCODE_PATH=$(find /Applications -maxdepth 1 -name 'Xcode*.app' -type d | head -1) + if [ -n "$XCODE_PATH" ]; then + sudo xcode-select --switch "$XCODE_PATH" + echo "Using Xcode at: $XCODE_PATH" + else + echo "Xcode not found" && exit 1 + fi + - name: Fresh clone smoke build (macOS) run: make build-macos VERSION=0.0.1 BUILD_NUM=1 From 594d23030cea2753b35d3bfd3f6975e64a3709b1 Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Wed, 13 May 2026 13:07:16 -0700 Subject: [PATCH 108/118] CI: Change check-macos-sdk to validating that xcrun --sdk macosx --show-sdk-path actually resolves --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index ff860061d..0351220a7 100644 --- a/Makefile +++ b/Makefile @@ -79,10 +79,10 @@ endif check-macos-sdk: ## Verify XCode on macOS ifeq ($(shell uname),Darwin) @echo "Checking macOS SDK requirements..." - @xcode-select -p | grep -q "Xcode.app" || ( \ - echo "[ERROR] Full Xcode installation not detected! Path: /Applications/Xcode.app"; \ + @xcrun --sdk macosx --show-sdk-path >/dev/null 2>&1 || ( \ + echo "[ERROR] macOS SDK not available. Install Xcode or run: sudo xcode-select --switch /Applications/Xcode.app"; \ exit 1) - @echo "[OK] Xcode SDK path looks good." + @echo "[OK] macOS SDK available at: $$(xcrun --sdk macosx --show-sdk-path)" endif check-reqs-macos: check-reqs ## Verify macOS-specific tools are available in PATH From 75ed4bc7ee09b8bd33969032de8f4fa64a9b68ee Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Wed, 13 May 2026 13:09:30 -0700 Subject: [PATCH 109/118] Update dart formatting for libmwc integration tests --- integration_test/mwc_ffi_test.dart | 13 +- integration_test/mwc_ffi_test_service.dart | 585 ++++++++++++--------- integration_test/mwc_test_result.dart | 4 +- 3 files changed, 346 insertions(+), 256 deletions(-) diff --git a/integration_test/mwc_ffi_test.dart b/integration_test/mwc_ffi_test.dart index 7c1abd75b..becb22154 100644 --- a/integration_test/mwc_ffi_test.dart +++ b/integration_test/mwc_ffi_test.dart @@ -7,10 +7,13 @@ void main() { testWidgets('MWC FFI smoke', (tester) async { await FFITestService.initialize(); final ok = await FFITestService.runAllTests(); - expect(ok, isTrue, - reason: FFITestService.testResults - .where((r) => !r.passed) - .map((r) => '${r.name}: ${r.error}') - .join('\n')); + expect( + ok, + isTrue, + reason: FFITestService.testResults + .where((r) => !r.passed) + .map((r) => '${r.name}: ${r.error}') + .join('\n'), + ); }); } diff --git a/integration_test/mwc_ffi_test_service.dart b/integration_test/mwc_ffi_test_service.dart index 953a3e6b6..9e6b3965a 100644 --- a/integration_test/mwc_ffi_test_service.dart +++ b/integration_test/mwc_ffi_test_service.dart @@ -12,77 +12,85 @@ import 'mwc_test_result.dart'; class FFITestService { static final List _testResults = []; static bool _isInitialized = false; - + /// Initialize the test framework. static Future initialize() async { if (_isInitialized) return; - + _logInfo('FFI Test Service initialized successfully'); _isInitialized = true; } - + /// Get all test results. static List get testResults => List.unmodifiable(_testResults); - + /// Clear all test results. static void clearResults() { _testResults.clear(); _logInfo('Test results cleared'); } - + /// Run all FFI integration tests. static Future runAllTests() async { if (!_isInitialized) { throw StateError('FFI Test Service not initialized'); } - + clearResults(); _logInfo('Starting comprehensive FFI integration test suite'); - + bool allPassed = true; - + // Phase 1: Environment and pre-flight validation. allPassed &= await _runEnvironmentTests(); - + // Phase 2: Basic FFI functionality. allPassed &= await _runBasicFFITests(); - + // Phase 3: Wallet management tests. allPassed &= await _runWalletManagementTests(); - + // Phase 4: Transaction functionality tests. allPassed &= await _runTransactionTests(); - + // Phase 5: Basic slatepack functionality tests. allPassed &= await _runSlatepackTests(); - + // Phase 6: MWCMQS listener functionality tests. allPassed &= await _runMWCMQSTests(); - - _logInfo('Test suite completed. Overall result: ${allPassed ? "PASS" : "FAIL"}'); + + _logInfo( + 'Test suite completed. Overall result: ${allPassed ? "PASS" : "FAIL"}', + ); return allPassed; } - + /// Run environment validation tests. static Future _runEnvironmentTests() async { bool allPassed = true; - + // Test 1: Platform detection. allPassed &= await _runTest( 'Platform Detection', 'Verify current platform is correctly detected', () async { final platform = Platform.operatingSystem; - final supportedPlatforms = ['linux', 'windows', 'macos', 'android', 'ios']; - + final supportedPlatforms = [ + 'linux', + 'windows', + 'macos', + 'android', + 'ios', + ]; + if (!supportedPlatforms.contains(platform)) { throw TestException('Unsupported platform: $platform'); } - + return 'Platform: $platform (supported)'; - } + }, ); - + // Test 2: Library loading. allPassed &= await _runTest( 'Library Loading', @@ -91,22 +99,24 @@ class FFITestService { try { final mnemonic = Libmwc.getMnemonic(); if (mnemonic.isEmpty) { - throw TestException('Library loaded but basic function returned empty result'); + throw TestException( + 'Library loaded but basic function returned empty result', + ); } return 'Library loaded successfully, basic function operational'; } catch (e) { throw TestException('Failed to load or call native library: $e'); } - } + }, ); - + return allPassed; } - + /// Run basic FFI functionality tests. static Future _runBasicFFITests() async { bool allPassed = true; - + // Test 1: Mnemonic generation. allPassed &= await _runTest( 'Mnemonic Generation', @@ -114,37 +124,41 @@ class FFITestService { () async { final mnemonic = Libmwc.getMnemonic(); final words = mnemonic.split(' '); - + if (words.length != 24) { - throw TestException('Invalid mnemonic length: ${words.length} (expected 24)'); + throw TestException( + 'Invalid mnemonic length: ${words.length} (expected 24)', + ); } - + return 'Generated 24-word mnemonic successfully'; - } + }, ); - + // Test 2: Address validation. allPassed &= await _runTest( 'Address Validation', 'Test FFI address validation function', () async { // Test with known invalid address. - final invalidResult = Libmwc.validateSendAddress(address: 'invalid_address'); + final invalidResult = Libmwc.validateSendAddress( + address: 'invalid_address', + ); if (invalidResult) { throw TestException('Invalid address incorrectly validated as valid'); } - + return 'Address validation working correctly'; - } + }, ); - + return allPassed; } - + /// Run wallet management integration tests. static Future _runWalletManagementTests() async { bool allPassed = true; - + // Test 1: Wallet configuration validation. allPassed &= await _runTest( 'Wallet Configuration', @@ -154,19 +168,23 @@ class FFITestService { if (testConfig.isEmpty) { throw TestException('Failed to create test wallet configuration'); } - + // Validate config contains required fields. - final configData = {'wallet_dir': '', 'check_node_api_http_addr': '', 'chain': ''}; + final configData = { + 'wallet_dir': '', + 'check_node_api_http_addr': '', + 'chain': '', + }; for (final key in configData.keys) { if (!testConfig.contains(key)) { throw TestException('Missing required config field: $key'); } } - + return 'Test wallet configuration created and validated successfully'; - } + }, ); - + // Test 2: Wallet initialization. allPassed &= await _runTest( 'Wallet Initialization', @@ -175,8 +193,9 @@ class FFITestService { final testMnemonic = Libmwc.getMnemonic(); final testConfig = await _getTestWalletConfig(); final testPassword = 'test_password_123'; - final walletName = 'ffi_test_wallet_${DateTime.now().millisecondsSinceEpoch}'; - + final walletName = + 'ffi_test_wallet_${DateTime.now().millisecondsSinceEpoch}'; + try { final result = await Libmwc.initializeNewWallet( config: testConfig, @@ -184,13 +203,12 @@ class FFITestService { password: testPassword, name: walletName, ); - + if (result.toUpperCase().contains('ERROR')) { throw TestException('Wallet initialization failed: $result'); } - + return 'New wallet initialized successfully: $walletName'; - } catch (e) { // Expected to potentially fail if wallet already exists or other issues. if (e.toString().contains('already exists')) { @@ -198,9 +216,9 @@ class FFITestService { } rethrow; } - } + }, ); - + // Test 3: Wallet recovery. allPassed &= await _runTest( 'Wallet Recovery', @@ -209,8 +227,9 @@ class FFITestService { final testMnemonic = Libmwc.getMnemonic(); final testConfig = await _getTestWalletConfig(); final testPassword = 'recovery_test_123'; - final walletName = 'ffi_recovery_test_${DateTime.now().millisecondsSinceEpoch}'; - + final walletName = + 'ffi_recovery_test_${DateTime.now().millisecondsSinceEpoch}'; + try { await Libmwc.recoverWallet( config: testConfig, @@ -218,92 +237,107 @@ class FFITestService { mnemonic: testMnemonic, name: walletName, ); - + return 'Wallet recovery from mnemonic completed successfully'; - } catch (e) { // Expected to potentially fail in test environment. - if (e.toString().contains('directory') || e.toString().contains('permission')) { + if (e.toString().contains('directory') || + e.toString().contains('permission')) { return 'Wallet recovery handled filesystem constraints correctly'; } throw TestException('Unexpected error in wallet recovery: $e'); } - } + }, ); - + // Test 4: Chain height retrieval. allPassed &= await _runTest( 'Chain Height Query', 'Test chain height retrieval via FFI using remote MWC node', () async { final testConfig = await _getTestWalletConfig(); - + try { final height = await Libmwc.getChainHeight(config: testConfig); - + if (height < 0) { throw TestException('Invalid chain height returned: $height'); } - + // Mainnet should have a reasonable height (over 1 million blocks as of 2024). if (height < 1000000) { - throw TestException('Chain height seems too low for mainnet: $height'); + throw TestException( + 'Chain height seems too low for mainnet: $height', + ); } - + return 'Chain height retrieved successfully: $height (mainnet)'; - } catch (e) { final errorStr = e.toString(); - + // Handle specific error types with more detail. - if (errorStr.contains('FormatException') || errorStr.contains('Invalid radix-10')) { - throw TestException('Failed to parse chain height response: node may have returned an error message instead of height'); - } else if (errorStr.contains('connection') || errorStr.contains('network') || errorStr.contains('timeout')) { - throw TestException('Network connection issue with remote node: ${errorStr.substring(0, 100)}...'); + if (errorStr.contains('FormatException') || + errorStr.contains('Invalid radix-10')) { + throw TestException( + 'Failed to parse chain height response: node may have returned an error message instead of height', + ); + } else if (errorStr.contains('connection') || + errorStr.contains('network') || + errorStr.contains('timeout')) { + throw TestException( + 'Network connection issue with remote node: ${errorStr.substring(0, 100)}...', + ); } else if (errorStr.contains('Cannot m')) { - throw TestException('Remote node connection failed - possibly network or SSL issue'); + throw TestException( + 'Remote node connection failed - possibly network or SSL issue', + ); } - + // Re-throw with more context. - throw TestException('Chain height query failed: ${errorStr.substring(0, 100)}...'); + throw TestException( + 'Chain height query failed: ${errorStr.substring(0, 100)}...', + ); } - } + }, ); - + return allPassed; } - + static Future _runTransactionTests() async { bool allPassed = true; - - // Test 1: Transaction function availability. + + // Test 1: Transaction function availability. allPassed &= await _runTest( 'Transaction Function Availability', 'Verify transaction functions are available via FFI', () async { // Test that transaction functions exist and can be called. // This validates the FFI bindings are working without requiring an actual wallet. - + try { // First test: Validate address format function (should not panic). - final isValid = Libmwc.validateSendAddress(address: 'test@example.com'); - + final isValid = Libmwc.validateSendAddress( + address: 'test@example.com', + ); + // This should return false for a test address, but validates the function works. if (isValid == true || isValid == false) { return 'Transaction functions available: address validation working (result: $isValid)'; } - + throw TestException('Address validation returned unexpected result'); - } catch (e) { final errorStr = e.toString(); - + // Any error here indicates a problem with the FFI bindings themselves. - throw TestException('Transaction function availability test failed: ${errorStr.substring(0, 100)}...'); + throw TestException( + 'Transaction function availability test failed: ${errorStr.substring(0, 100)}...', + ); } - } + }, ); - + // Test 2: Transaction API Structure Validation. allPassed &= await _runTest( 'Transaction API Structure', @@ -312,29 +346,30 @@ class FFITestService { try { // Test that we can create test configuration without errors. final testConfig = await _getTestWalletConfig(); - - if (!testConfig.contains('wallet_dir') || + + if (!testConfig.contains('wallet_dir') || !testConfig.contains('check_node_api_http_addr') || !testConfig.contains('chain')) { throw TestException('Test configuration missing required fields'); } - + // Test basic type validation. const testAmount = 1000000; const minConfirmations = 10; - + if (testAmount <= 0 || minConfirmations <= 0) { throw TestException('Transaction parameter validation failed'); } - + return 'Transaction API structure validation passed: config format and parameter types correct'; - } catch (e) { - throw TestException('Transaction API structure test failed: ${e.toString().substring(0, 100)}...'); + throw TestException( + 'Transaction API structure test failed: ${e.toString().substring(0, 100)}...', + ); } - } + }, ); - + // Test 3: Transaction Model Validation. allPassed &= await _runTest( 'Transaction Model Validation', @@ -343,32 +378,33 @@ class FFITestService { try { // Test transaction model structure by creating instances. // This validates the Dart-side transaction types without calling FFI. - + final testAmount = 1500000; // 0.0015 MWC. final testAddress = 'test_user@mwcmqs.example.com'; final testNote = 'FFI integration test transaction'; - + // Validate parameter constraints. if (testAmount <= 0) { throw TestException('Transaction amount validation failed'); } - + if (testAddress.isEmpty || !testAddress.contains('@')) { throw TestException('Transaction address validation failed'); } - + if (testNote.length > 500) { throw TestException('Transaction note length validation failed'); } - + return 'Transaction model validation passed: amount=$testAmount, address format validated, note length OK'; - } catch (e) { - throw TestException('Transaction model validation failed: ${e.toString().substring(0, 100)}...'); + throw TestException( + 'Transaction model validation failed: ${e.toString().substring(0, 100)}...', + ); } - } + }, ); - + // Test 4: Transaction Error Code Validation. allPassed &= await _runTest( 'Transaction Error Handling', @@ -378,43 +414,47 @@ class FFITestService { // Test error message patterns that should be handled by transaction functions. final expectedErrors = [ 'wallet is not open', - 'WALLET_IS_NOT_OPEN', + 'WALLET_IS_NOT_OPEN', 'insufficient funds', 'invalid address', 'network error', - 'connection timeout' + 'connection timeout', ]; - + // Validate we have error handling patterns for common issues. for (final errorPattern in expectedErrors) { if (errorPattern.isEmpty) { throw TestException('Empty error pattern in validation list'); } } - + // Test amount boundary validation. const minAmount = 1; - const maxAmount = 21000000 * 1000000000; // Max MWC supply in nanograms. - + const maxAmount = + 21000000 * 1000000000; // Max MWC supply in nanograms. + if (minAmount >= maxAmount) { - throw TestException('Transaction amount boundary validation failed'); + throw TestException( + 'Transaction amount boundary validation failed', + ); } - + return 'Transaction error handling validation passed: ${expectedErrors.length} error patterns validated, amount boundaries correct'; - } catch (e) { - throw TestException('Transaction error handling validation failed: ${e.toString().substring(0, 100)}...'); + throw TestException( + 'Transaction error handling validation failed: ${e.toString().substring(0, 100)}...', + ); } - } + }, ); - + return allPassed; } - + /// Run basic slatepack functionality integration tests. static Future _runSlatepackTests() async { bool allPassed = true; - + // Test 1: Slatepack API Structure Validation. allPassed &= await _runTest( 'Slatepack API Structure', @@ -422,37 +462,42 @@ class FFITestService { () async { try { // Test basic slatepack parameter validation. - const testSlateJson = '{"id":"test","tx":{"body":{"inputs":[],"outputs":[],"kernels":[]}}}'; - const testSlatepack = 'BEGINSLATEPACK. test slatepack data .ENDSLATEPACK'; + const testSlateJson = + '{"id":"test","tx":{"body":{"inputs":[],"outputs":[],"kernels":[]}}}'; + const testSlatepack = + 'BEGINSLATEPACK. test slatepack data .ENDSLATEPACK'; const testRecipientAddress = 'test_user@mwcmqs.example.com'; - + // Validate parameter constraints for encoding. if (testSlateJson.isEmpty) { throw TestException('Slate JSON validation failed'); } - + if (!testSlateJson.contains('id')) { throw TestException('Slate JSON structure validation failed'); } - + // Validate slatepack format structure. - if (!testSlatepack.contains('BEGINSLATEPACK') || !testSlatepack.contains('ENDSLATEPACK')) { + if (!testSlatepack.contains('BEGINSLATEPACK') || + !testSlatepack.contains('ENDSLATEPACK')) { throw TestException('Slatepack format validation failed'); } - + // Validate address format. - if (testRecipientAddress.isEmpty || !testRecipientAddress.contains('@')) { + if (testRecipientAddress.isEmpty || + !testRecipientAddress.contains('@')) { throw TestException('Recipient address format validation failed'); } - + return 'Slatepack API structure validation passed: slate format, slatepack format, and address format correct'; - } catch (e) { - throw TestException('Slatepack API structure test failed: ${e.toString().substring(0, 100)}...'); + throw TestException( + 'Slatepack API structure test failed: ${e.toString().substring(0, 100)}...', + ); } - } + }, ); - + // Test 2: Slatepack Format Validation. allPassed &= await _runTest( 'Slatepack Format Validation', @@ -465,7 +510,7 @@ class FFITestService { 'BEGINSLATEPACK.\nencoded_data_here\n.ENDSLATEPACK', 'BEGINSLATEPACK. VGVzdCBkYXRh .ENDSLATEPACK', // Base64-like. ]; - + final invalidFormats = [ 'INVALID FORMAT', 'BEGINSLATEPACK without end', @@ -473,27 +518,34 @@ class FFITestService { '', 'BEGINSLATE PACK. test .ENDSLATEPACK', // Wrong format. ]; - + // Validate all valid formats pass basic structure check. for (final format in validFormats) { - if (!format.contains('BEGINSLATEPACK') || !format.contains('ENDSLATEPACK')) { - throw TestException('Valid slatepack format failed validation: $format'); + if (!format.contains('BEGINSLATEPACK') || + !format.contains('ENDSLATEPACK')) { + throw TestException( + 'Valid slatepack format failed validation: $format', + ); } } - + // Validate all invalid formats fail basic structure check. for (final format in invalidFormats) { - if (format.contains('BEGINSLATEPACK') && format.contains('ENDSLATEPACK')) { - throw TestException('Invalid slatepack format passed validation: $format'); + if (format.contains('BEGINSLATEPACK') && + format.contains('ENDSLATEPACK')) { + throw TestException( + 'Invalid slatepack format passed validation: $format', + ); } } - + return 'Slatepack format validation passed: ${validFormats.length} valid formats recognized, ${invalidFormats.length} invalid formats rejected'; - } catch (e) { - throw TestException('Slatepack format validation failed: ${e.toString().substring(0, 100)}...'); + throw TestException( + 'Slatepack format validation failed: ${e.toString().substring(0, 100)}...', + ); } - } + }, ); // Test 3: Slatepack Roundtrip (compact, unencrypted). @@ -504,7 +556,8 @@ class FFITestService { try { // Construct a minimal compact slate JSON. // Use version 3 + compact_slate flag to satisfy current lib expectations. - const compactSlateJson = '{\n' + const compactSlateJson = + '{\n' ' "version_info": {\n' ' "orig_version": 3,\n' ' "version": 3,\n' @@ -545,7 +598,9 @@ class FFITestService { final decodedId = decoded['id'] as String?; final versionInfo = decoded['version_info'] as Map?; if (decodedId != '0436430c-2b02-624c-2032-570501212b00') { - throw TestException('Decoded slate id mismatch or missing: $decodedId'); + throw TestException( + 'Decoded slate id mismatch or missing: $decodedId', + ); } if (versionInfo == null || versionInfo['version'] != 3) { throw TestException('Decoded slate version is not v3'); @@ -554,7 +609,9 @@ class FFITestService { // Verify encryption detection helper. final isEncrypted = await Libmwc.isSlatepackEncrypted(enc.slatepack); if (isEncrypted) { - throw TestException('isSlatepackEncrypted returned true for unencrypted slatepack'); + throw TestException( + 'isSlatepackEncrypted returned true for unencrypted slatepack', + ); } return 'Roundtrip succeeded; id=$decodedId; v4 compact; markers present; not encrypted'; @@ -573,7 +630,8 @@ class FFITestService { bool threw = false; try { await Libmwc.encodeSlatepack( - slateJson: '{"id":"abc","version_info":{"version":3,"block_header_version":1}}', + slateJson: + '{"id":"abc","version_info":{"version":3,"block_header_version":1}}', recipientAddress: 'dummy@mwcmqs.mwc.mw', encrypt: true, wallet: null, // No wallet context in test environment @@ -583,11 +641,15 @@ class FFITestService { final msg = e.toString(); if (!msg.toLowerCase().contains('wallet') || !msg.toLowerCase().contains('required')) { - throw TestException('Unexpected error for encrypted encode without wallet: $msg'); + throw TestException( + 'Unexpected error for encrypted encode without wallet: $msg', + ); } } if (!threw) { - throw TestException('Encrypted encode did not throw without wallet context'); + throw TestException( + 'Encrypted encode did not throw without wallet context', + ); } return 'Encrypted encode correctly requires wallet context'; } catch (e) { @@ -607,7 +669,9 @@ class FFITestService { final dec = await Libmwc.decodeSlatepack(slatepack: bogus); // High-level API may not throw; validate empty slate JSON returned. if (dec.slateJson.isNotEmpty) { - throw TestException('Invalid slatepack returned non-empty slate JSON'); + throw TestException( + 'Invalid slatepack returned non-empty slate JSON', + ); } return 'Invalid slatepack handled gracefully (empty slate JSON)'; } catch (e) { @@ -632,116 +696,124 @@ class FFITestService { final testCases = [ { 'name': 'basic slate', - 'slateJson': '{"id":"test-123","version_info":{"version":3,"block_header_version":1}}', + 'slateJson': + '{"id":"test-123","version_info":{"version":3,"block_header_version":1}}', 'encrypt': false, 'recipientAddress': null, }, { 'name': 'encrypted slate', - 'slateJson': '{"id":"test-456","version_info":{"version":3,"block_header_version":1}}', + 'slateJson': + '{"id":"test-456","version_info":{"version":3,"block_header_version":1}}', 'encrypt': true, 'recipientAddress': 'user@mwcmqs.example.com', }, ]; - + for (final testCase in testCases) { final slateJson = testCase['slateJson'] as String; final encrypt = testCase['encrypt'] as bool; final recipientAddress = testCase['recipientAddress'] as String?; - + // Validate slate JSON structure. if (!slateJson.contains('id')) { - throw TestException('Test case ${testCase['name']} missing required slate ID'); + throw TestException( + 'Test case ${testCase['name']} missing required slate ID', + ); } - + // Validate encryption parameters. - if (encrypt && (recipientAddress == null || recipientAddress.isEmpty)) { - throw TestException('Test case ${testCase['name']} encryption requires recipient address'); + if (encrypt && + (recipientAddress == null || recipientAddress.isEmpty)) { + throw TestException( + 'Test case ${testCase['name']} encryption requires recipient address', + ); } - + // Validate address format if provided. if (recipientAddress != null && !recipientAddress.contains('@')) { - throw TestException('Test case ${testCase['name']} invalid recipient address format'); + throw TestException( + 'Test case ${testCase['name']} invalid recipient address format', + ); } } - + return 'Slatepack encoding parameter validation passed: ${testCases.length} test cases validated'; - } catch (e) { - throw TestException('Slatepack encoding parameter validation failed: ${e.toString().substring(0, 100)}...'); + throw TestException( + 'Slatepack encoding parameter validation failed: ${e.toString().substring(0, 100)}...', + ); } - } + }, ); - + // Test 4: Slatepack Decoding Parameter Validation. allPassed &= await _runTest( - 'Slatepack Decoding Parameters', + 'Slatepack Decoding Parameters', 'Validate slatepack decoding parameter handling and response structure', () async { try { // Test decoding parameter validation and expected response structure. final testSlatepack = 'BEGINSLATEPACK. dGVzdCBkYXRh .ENDSLATEPACK'; - + // Validate slatepack format. - if (!testSlatepack.contains('BEGINSLATEPACK') || !testSlatepack.contains('ENDSLATEPACK')) { + if (!testSlatepack.contains('BEGINSLATEPACK') || + !testSlatepack.contains('ENDSLATEPACK')) { throw TestException('Test slatepack format validation failed'); } - + // Define expected decode response structure. final expectedFields = [ 'slate_json', 'sender', // nullable. 'recipient', // nullable. ]; - + // Validate we have proper validation for expected response fields. for (final field in expectedFields) { if (field.isEmpty) { throw TestException('Empty expected field in validation list'); } } - + // Test decoding error scenarios. final errorTestCases = [ - { - 'input': '', - 'expectedError': 'empty slatepack', - }, - { - 'input': 'INVALID FORMAT', - 'expectedError': 'invalid format', - }, + {'input': '', 'expectedError': 'empty slatepack'}, + {'input': 'INVALID FORMAT', 'expectedError': 'invalid format'}, { 'input': 'BEGINSLATEPACK. corrupted_data .ENDSLATEPACK', 'expectedError': 'decoding error', }, ]; - + // Validate error cases are properly structured. for (final testCase in errorTestCases) { final input = testCase['input'] as String; final expectedError = testCase['expectedError'] as String; - + if (input.isEmpty && expectedError != 'empty slatepack') { - throw TestException('Error test case mismatch: empty input should expect empty slatepack error'); + throw TestException( + 'Error test case mismatch: empty input should expect empty slatepack error', + ); } } - + return 'Slatepack decoding parameter validation passed: ${expectedFields.length} response fields validated, ${errorTestCases.length} error cases structured'; - } catch (e) { - throw TestException('Slatepack decoding parameter validation failed: ${e.toString().substring(0, 100)}...'); + throw TestException( + 'Slatepack decoding parameter validation failed: ${e.toString().substring(0, 100)}...', + ); } - } + }, ); - + return allPassed; } - + /// Run MWCMQS listener functionality integration tests. static Future _runMWCMQSTests() async { bool allPassed = true; - + // Test 1: MWCMQS API Function Availability. allPassed &= await _runTest( 'MWCMQS API Function Availability', @@ -750,7 +822,7 @@ class FFITestService { try { // Test that we can access the MWCMQS FFI functions through the native library. // Try to call the FFI functions with test parameters to verify they're accessible. - + // Verify the mwcMqsListenerStart function exists by trying to call it. try { final testWallet = '[test_handle]'; @@ -761,16 +833,20 @@ class FFITestService { } catch (functionError) { // Expected to fail with invalid parameters, but function should be accessible. if (functionError.toString().contains('NoSuchMethodError')) { - throw TestException('MWCMQS start function not available: ${functionError.toString()}'); + throw TestException( + 'MWCMQS start function not available: ${functionError.toString()}', + ); } return 'MWCMQS FFI functions verified: mwcMqsListenerStart accessible (failed with expected error: ${functionError.toString().substring(0, 50)}...)'; } } catch (e) { - throw TestException('MWCMQS API function availability test failed: ${e.toString()}'); + throw TestException( + 'MWCMQS API function availability test failed: ${e.toString()}', + ); } - } + }, ); - + // Test 2: MWCMQS Listener Configuration. allPassed &= await _runTest( 'MWCMQS Listener Configuration', @@ -783,7 +859,7 @@ class FFITestService { 'mwcmqs_port': 443, 'mwcmqs_use_ssl': true, }); - + // Validate configuration can be parsed. final configData = jsonDecode(mwcmqsConfig); if (configData['mwcmqs_domain'] != 'mqs.mwc.mw' || @@ -791,14 +867,16 @@ class FFITestService { configData['mwcmqs_use_ssl'] != true) { throw TestException('MWCMQS configuration validation failed'); } - + return 'MWCMQS configuration created and validated: $mwcmqsConfig'; } catch (e) { - throw TestException('MWCMQS configuration test failed: ${e.toString()}'); + throw TestException( + 'MWCMQS configuration test failed: ${e.toString()}', + ); } - } + }, ); - + // Test 3: MWCMQS Listener Start/Stop API. allPassed &= await _runTest( 'MWCMQS Listener Start/Stop API', @@ -807,25 +885,27 @@ class FFITestService { try { // Test that the MWCMQS functions are accessible and accept parameters correctly. // We'll test with invalid parameters to avoid network calls that might crash. - + // Test listener start function accessibility. try { // Use clearly invalid parameters that should trigger a controlled error. final invalidWallet = 'invalid_wallet_handle'; final invalidConfig = '{"invalid": "config"}'; - + // This should fail gracefully with a parameter error, not crash. - final result = lib_mwc.mwcMqsListenerStart(invalidWallet, invalidConfig); - + final result = lib_mwc.mwcMqsListenerStart( + invalidWallet, + invalidConfig, + ); + // If we get a result without crashing, that's unexpected but good. return 'MWCMQS listener API accessible: start function callable, returned pointer ${result.address}'; - } catch (apiError) { // We expect this to fail with invalid parameters, which is good. // Check that it's a controlled error, not a crash. final errorString = apiError.toString(); - - if (errorString.contains('invalid') || + + if (errorString.contains('invalid') || errorString.contains('parameter') || errorString.contains('format') || errorString.contains('parse') || @@ -833,17 +913,18 @@ class FFITestService { errorString.contains('config')) { return 'MWCMQS listener API validated: start function accessible and properly validates parameters (error: ${errorString.substring(0, 60)}...)'; } - + // If it's some other error, that's still validation that the function exists. return 'MWCMQS listener API accessible: start function exists and callable (failed with: ${errorString.substring(0, 60)}...)'; } - } catch (e) { - throw TestException('MWCMQS listener API test failed: ${e.toString()}'); + throw TestException( + 'MWCMQS listener API test failed: ${e.toString()}', + ); } - } + }, ); - + // Test 4: MWCMQS High-Level API Integration. allPassed &= await _runTest( 'MWCMQS High-Level API Integration', @@ -856,12 +937,14 @@ class FFITestService { // Try to access the methods - this will throw if they don't exist. final startMethod = Libmwc.startMwcMqsListener; final stopMethod = Libmwc.stopMwcMqsListener; - + // If we get here, methods exist. } catch (methodError) { - throw TestException('Libmwc MWCMQS methods not available: ${methodError.toString()}'); + throw TestException( + 'Libmwc MWCMQS methods not available: ${methodError.toString()}', + ); } - + // Test high-level API call structure. try { // This should fail gracefully since we don't have a real wallet/server. @@ -873,13 +956,12 @@ class FFITestService { 'mwcmqs_use_ssl': true, }), ); - + // If we get here, the API call structure is correct. return 'MWCMQS high-level API integration validated: Libmwc methods accessible and callable'; - } catch (apiError) { // Expected to fail without real wallet, but validates API structure. - if (apiError.toString().contains('handle') || + if (apiError.toString().contains('handle') || apiError.toString().contains('wallet') || apiError.toString().contains('connection') || apiError.toString().contains('invalid')) { @@ -887,29 +969,31 @@ class FFITestService { } throw apiError; } - } catch (e) { - throw TestException('MWCMQS high-level API integration test failed: ${e.toString()}'); + throw TestException( + 'MWCMQS high-level API integration test failed: ${e.toString()}', + ); } - } + }, ); - + return allPassed; } - + /// Get test wallet configuration. static Future _getTestWalletConfig() async { final walletDir = await _getTestWalletDir(); final config = { 'wallet_dir': walletDir, - 'check_node_api_http_addr': 'https://mwc713.mwc.mw:443', // Working remote node. + 'check_node_api_http_addr': + 'https://mwc713.mwc.mw:443', // Working remote node. 'chain': 'mainnet', // Use mainnet since remote node is mainnet. 'account': 'default', }; return '{"wallet_dir":"${config['wallet_dir']}","check_node_api_http_addr":"${config['check_node_api_http_addr']}","chain":"${config['chain']}","account":"${config['account']}"}'; } - + /// Run a single test with proper error handling and result tracking. static Future _runTest( String name, @@ -917,53 +1001,56 @@ class FFITestService { Future Function() testFunction, ) async { _logInfo('Running test: $name'); - + final stopwatch = Stopwatch()..start(); - + try { final result = await testFunction(); stopwatch.stop(); - - _testResults.add(TestResult( - name: name, - description: description, - passed: true, - duration: stopwatch.elapsed, - result: result, - )); - + + _testResults.add( + TestResult( + name: name, + description: description, + passed: true, + duration: stopwatch.elapsed, + result: result, + ), + ); + _logInfo('Test PASSED: $name (${stopwatch.elapsedMilliseconds}ms)'); return true; - } catch (e, stackTrace) { stopwatch.stop(); - - _testResults.add(TestResult( - name: name, - description: description, - passed: false, - duration: stopwatch.elapsed, - error: e.toString(), - stackTrace: stackTrace.toString(), - )); - + + _testResults.add( + TestResult( + name: name, + description: description, + passed: false, + duration: stopwatch.elapsed, + error: e.toString(), + stackTrace: stackTrace.toString(), + ), + ); + _logError('Test FAILED: $name - $e'); return false; } } - + /// Log info message. static void _logInfo(String message) { final timestamp = DateTime.now().toIso8601String(); debugPrint('[$timestamp] [INFO] $message'); } - + /// Log error message. static void _logError(String message) { final timestamp = DateTime.now().toIso8601String(); debugPrint('[$timestamp] [ERROR] $message'); } - + /// Get appropriate test wallet directory for current platform. static Future _getTestWalletDir() async { if (Platform.isAndroid) { @@ -987,9 +1074,9 @@ class FFITestService { /// Exception thrown during testing. class TestException implements Exception { final String message; - + const TestException(this.message); - + @override String toString() => 'TestException: $message'; } diff --git a/integration_test/mwc_test_result.dart b/integration_test/mwc_test_result.dart index 1768a8ce1..27dbc2e1d 100644 --- a/integration_test/mwc_test_result.dart +++ b/integration_test/mwc_test_result.dart @@ -8,7 +8,7 @@ class TestResult { final String? error; final String? stackTrace; final DateTime timestamp; - + TestResult({ required this.name, required this.description, @@ -18,7 +18,7 @@ class TestResult { this.error, this.stackTrace, }) : timestamp = DateTime.now(); - + /// Get a summary string for this test result. String get summary { final status = passed ? 'PASS' : 'FAIL'; From 411f4dcc706da12f32238644f2727da0fb47c5f4 Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Wed, 13 May 2026 14:35:49 -0700 Subject: [PATCH 110/118] Run MWC integration tests --- .github/workflows/test.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 1e306c2f0..2a4c5eb7c 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -114,3 +114,6 @@ jobs: - name: Fresh clone smoke build (macOS) run: make build-macos VERSION=0.0.1 BUILD_NUM=1 + + - name: MWC FFI integration test + run: make test-mwc From 8ad98dbf37ea001c9119d86a46883f5a9be8aedc Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Wed, 13 May 2026 15:23:17 -0700 Subject: [PATCH 111/118] fix: add Rust toolchain to test-mwc target and port build.yaml macos job to Makefile make build-macos now drives the full macOS release build via the Makefile, replacing the old build_app.sh -d -s download path with source compilation. build.yaml: remove redundant Configure/GetDeps/GitVersions/Build steps now handled by make build-macos. Add dtolnay/rust-toolchain@stable + 1.85.1 install so check-reqs passes. Makefile: test-mwc now ensures local stable rustup toolchain is installed and defaulted before flutter test -d macos, fixing missing flutter_libsparkmobile framework linker error when Cargokit rebuilds for Debug mode. --- .github/workflows/build.yaml | 28 ++++++---------------------- Makefile | 8 ++++++++ 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 01ec83304..ea2694b5d 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -322,29 +322,13 @@ jobs: with: go-version: '1.24.13' - - name: Configure app - run: | - cd scripts - echo "yes" | ./build_app.sh \ - -v "${{ steps.ver.outputs.version }}" \ - -b "${{ steps.ver.outputs.build_number }}" \ - -p macos -a stack_wallet -d -s + - uses: dtolnay/rust-toolchain@stable - - name: Get dependencies - run: flutter pub get - - - name: Create git_versions.dart stubs + - name: Install required Rust toolchains run: | - mkdir -p crypto_plugins/flutter_libepiccash/lib - mkdir -p crypto_plugins/flutter_libmwc/lib - - EPIC_TAG=$(git -C crypto_plugins/flutter_libepiccash describe --tags --exact-match HEAD 2>/dev/null || echo "dev") - MWC_TAG=$(git -C crypto_plugins/flutter_libmwc describe --tags --exact-match HEAD 2>/dev/null || echo "dev") - - printf 'String getPluginVersion() => "%s";\n' "$EPIC_TAG" \ - > crypto_plugins/flutter_libepiccash/lib/git_versions.dart - printf 'String getPluginVersion() => "%s";\n' "$MWC_TAG" \ - > crypto_plugins/flutter_libmwc/lib/git_versions.dart + rustup toolchain install 1.85.1 + rustup target add aarch64-apple-darwin --toolchain stable + rustup target add aarch64-apple-darwin --toolchain 1.85.1 - name: Decode secrets env: @@ -352,7 +336,7 @@ jobs: run: echo "$CHANGE_NOW" | base64 --decode > lib/external_api_keys.dart - name: Build - run: flutter build macos --release + run: make build-macos VERSION="${{ steps.ver.outputs.version }}" BUILD_NUM="${{ steps.ver.outputs.build_number }}" - name: Package run: | diff --git a/Makefile b/Makefile index 0351220a7..493948016 100644 --- a/Makefile +++ b/Makefile @@ -344,6 +344,13 @@ test-mwc: ## Run MWC FFI integration test on macOS (assumes prior `make build-ma @# Flutter's first-launch helper rewrites MACOSX_DEPLOYMENT_TARGET=10.15; reassert 11.0. @sed -i.bak -e "s/MACOSX_DEPLOYMENT_TARGET = 10\\.15;/MACOSX_DEPLOYMENT_TARGET = 11.0;/g" macos/Runner.xcodeproj/project.pbxproj 2>/dev/null || true @rm -f macos/Runner.xcodeproj/project.pbxproj.bak + @# Cargokit calls `rustup run stable cargo ...`; ensure local `stable` exists and is selected. + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" CARGO_HOME="$(PROJECT_CARGO_HOME)" \ + rustup toolchain install --no-self-update stable >/dev/null + @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ + RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" CARGO_HOME="$(PROJECT_CARGO_HOME)" \ + rustup default stable >/dev/null @# `flutter test` re-runs pod install which re-prepares flutter_libsparkmobile; remove stale framework so the prepare step can write. @find "$(PUB_CACHE)/git" -path '*/flutter_libsparkmobile-*/macos/flutter_libsparkmobile.framework' -prune -exec rm -rf {} + 2>/dev/null || true @chmod -R u+w macos/Runner.xcodeproj macos 2>/dev/null || true @@ -354,6 +361,7 @@ test-mwc: ## Run MWC FFI integration test on macOS (assumes prior `make build-ma PUB_CACHE="$(PUB_CACHE)" \ RUSTUP_HOME="$(PROJECT_RUSTUP_HOME)" \ CARGO_HOME="$(PROJECT_CARGO_HOME)" \ + PATH="$(PROJECT_CARGO_HOME)/bin:$$PATH" \ $(FLUTTER) test integration_test/mwc_ffi_test.dart -d macos diagnose-macos-env: ## Print macOS build env and tool resolution From 6d9566a84b9b972b257b2ac49f99a1cf4f5f845c Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Wed, 13 May 2026 20:21:00 -0700 Subject: [PATCH 112/118] fix(linux): reconcile secp256k1 build script with staging --- scripts/linux/build_secp256k1.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/linux/build_secp256k1.sh b/scripts/linux/build_secp256k1.sh index 5e3be13bd..187489d72 100755 --- a/scripts/linux/build_secp256k1.sh +++ b/scripts/linux/build_secp256k1.sh @@ -12,9 +12,10 @@ cd secp256k1 git checkout 68b55209f1ba3e6c0417789598f5f75649e9c14c git reset --hard +rm -rf build mkdir -p build cd build -cmake .. +cmake .. -DSECP256K1_ENABLE_MODULE_RECOVERY=ON cmake --build . SECP_SO="$(find lib -maxdepth 1 -type f -name 'libsecp256k1.so*' | sort | head -n1)" From 54e9ea056bf782aac43c4b243f3d3f1aa3c8045b Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Wed, 13 May 2026 21:00:07 -0700 Subject: [PATCH 113/118] Use nix flake for macos builds --- .github/workflows/build.yaml | 20 ++++---------------- .github/workflows/test.yaml | 27 +++++---------------------- 2 files changed, 9 insertions(+), 38 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index ea2694b5d..6c4a2faef 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -313,22 +313,10 @@ jobs: echo "version=${VERSION}" >> $GITHUB_OUTPUT echo "build_number=${BUILD_NUMBER}" >> $GITHUB_OUTPUT - - uses: subosito/flutter-action@v2 - with: - flutter-version: '3.38.1' - channel: 'stable' - - - uses: actions/setup-go@v5 + - uses: cachix/install-nix-action@v27 with: - go-version: '1.24.13' - - - uses: dtolnay/rust-toolchain@stable - - - name: Install required Rust toolchains - run: | - rustup toolchain install 1.85.1 - rustup target add aarch64-apple-darwin --toolchain stable - rustup target add aarch64-apple-darwin --toolchain 1.85.1 + extra_nix_config: | + experimental-features = nix-command flakes - name: Decode secrets env: @@ -336,7 +324,7 @@ jobs: run: echo "$CHANGE_NOW" | base64 --decode > lib/external_api_keys.dart - name: Build - run: make build-macos VERSION="${{ steps.ver.outputs.version }}" BUILD_NUM="${{ steps.ver.outputs.build_number }}" + run: nix develop --command make build-macos VERSION="${{ steps.ver.outputs.version }}" BUILD_NUM="${{ steps.ver.outputs.build_number }}" - name: Package run: | diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2a4c5eb7c..ef9053a2c 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -90,30 +90,13 @@ jobs: with: submodules: recursive - - name: Install Flutter - uses: subosito/flutter-action@v2 + - uses: cachix/install-nix-action@v27 with: - flutter-version: '3.38.1' - channel: 'stable' - - - name: Setup Rust - uses: dtolnay/rust-toolchain@stable - - - name: Install macOS build dependencies - run: ./scripts/install_macos_build_tools.sh - - - name: Select Xcode - run: | - XCODE_PATH=$(find /Applications -maxdepth 1 -name 'Xcode*.app' -type d | head -1) - if [ -n "$XCODE_PATH" ]; then - sudo xcode-select --switch "$XCODE_PATH" - echo "Using Xcode at: $XCODE_PATH" - else - echo "Xcode not found" && exit 1 - fi + extra_nix_config: | + experimental-features = nix-command flakes - name: Fresh clone smoke build (macOS) - run: make build-macos VERSION=0.0.1 BUILD_NUM=1 + run: nix develop --command make build-macos VERSION=0.0.1 BUILD_NUM=1 - name: MWC FFI integration test - run: make test-mwc + run: nix develop --command make test-mwc From 477745211a6bebd22e45ae9be8a23b0a7c24c013 Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Wed, 13 May 2026 21:37:47 -0700 Subject: [PATCH 114/118] Add protobuf to common packages and export PROTOC on macOS in nix flake --- flake.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 66a2f2cbc..c34aafd70 100644 --- a/flake.nix +++ b/flake.nix @@ -27,6 +27,7 @@ gnumake gnused rsync + protobuf (python3.withPackages (ps: with ps; [ pip toml tomli jinja2 markdown markupsafe pygments typogrify ])) @@ -36,7 +37,6 @@ gtk3 glib openssl xz clang libgcrypt gobject-introspection llvmPackages.libclang llvmPackages.clang - protobuf opencv sysprof libsysprof-capture @@ -113,6 +113,7 @@ export STRIP=/usr/bin/strip export BINDGEN_EXTRA_CLANG_ARGS="-isysroot $SDKROOT" + export PROTOC="${pkgs.protobuf}/bin/protoc" mkdir -p .nix-bin ln -sf /usr/bin/clang .nix-bin/cc From a84d5ad62356d302696d566b6711cbf2f33e85b1 Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Thu, 14 May 2026 08:41:42 -0700 Subject: [PATCH 115/118] Forward PROTOC into macos-build-native env --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 493948016..994732df4 100644 --- a/Makefile +++ b/Makefile @@ -296,6 +296,7 @@ macos-build-native: AR="/usr/bin/ar" \ RANLIB="/usr/bin/ranlib" \ SDKROOT="$$(xcrun --sdk macosx --show-sdk-path)" \ + PROTOC="$(PROTOC_PATH)" \ PATH="$(PROJECT_CARGO_HOME)/bin:$$PATH" \ bash scripts/macos/build_all.sh @rm -rf build/secp256k1 From f680859bfa0d5120c92a23fa0a16ebdb9804f93d Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 14 May 2026 11:25:52 -0500 Subject: [PATCH 116/118] fix(make): always regenerate pubspec.yaml from template in macos-configure this can be reverted/dropped after the legacy build scripts are deprecated --- Makefile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 994732df4..c73790ea6 100644 --- a/Makefile +++ b/Makefile @@ -188,10 +188,8 @@ macos-configure: echo "--- Creating flutter_libmwc git_versions.dart from example..."; \ cp crypto_plugins/flutter_libmwc/lib/git_versions_example.dart crypto_plugins/flutter_libmwc/lib/git_versions.dart; \ fi - @if [ ! -f pubspec.yaml ]; then \ - echo "--- pubspec.yaml missing; generating from template..."; \ - cp scripts/app_config/templates/pubspec.template.yaml pubspec.yaml; \ - fi + @echo "--- Regenerating pubspec.yaml from template..." + @cp scripts/app_config/templates/pubspec.template.yaml pubspec.yaml @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ ./scripts/app_config/configure_stack_wallet.sh macos @env HOME="$(PROJECT_HOME)" XDG_CACHE_HOME="$(PROJECT_CACHE)" TMPDIR="$(PROJECT_TMP)" PUB_CACHE="$(PUB_CACHE)" \ From 8b0e24c1af4c13eb67de64b64f51ba479adfc3ea Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 14 May 2026 11:26:01 -0500 Subject: [PATCH 117/118] chore(deps): refresh pubspec.lock against updated bip47 ref --- pubspec.lock | 70 ++++++++++++++-------------------------------------- 1 file changed, 19 insertions(+), 51 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index b321a3354..862f92877 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -96,8 +96,8 @@ packages: dependency: "direct main" description: path: "." - ref: "3ef6b94375d7b4d972b0bc0bd9597532381a88ec" - resolved-ref: "3ef6b94375d7b4d972b0bc0bd9597532381a88ec" + ref: bdc0c0788d1d6dfb04863a793955f848ba1624a8 + resolved-ref: bdc0c0788d1d6dfb04863a793955f848ba1624a8 url: "https://github.com/cypherstack/bip47.git" source: git version: "2.1.0" @@ -285,10 +285,10 @@ packages: dependency: transitive description: name: characters - sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.0" charcode: dependency: transitive description: @@ -329,14 +329,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.2" - code_assets: - dependency: transitive - description: - name: code_assets - sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" - url: "https://pub.dev" - source: hosted - version: "1.0.0" code_builder: dependency: transitive description: @@ -1201,7 +1193,7 @@ packages: path: "crypto_plugins/frostdart" relative: true source: path - version: "0.0.1" + version: "0.2.0" fuchsia_remote_debug_protocol: dependency: transitive description: flutter @@ -1312,14 +1304,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" - hooks: - dependency: transitive - description: - name: hooks - sha256: e79ed1e8e1929bc6ecb6ec85f0cb519c887aa5b423705ded0d0f2d9226def388 - url: "https://pub.dev" - source: hosted - version: "1.0.2" html: dependency: transitive description: @@ -1578,18 +1562,18 @@ packages: dependency: transitive description: name: matcher - sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.19" + version: "0.12.17" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.13.0" + version: "0.11.1" memoize: dependency: transitive description: @@ -1689,14 +1673,6 @@ packages: url: "https://github.com/cypherstack/nanodart" source: git version: "2.0.1" - native_toolchain_c: - dependency: transitive - description: - name: native_toolchain_c - sha256: "6ba77bb18063eebe9de401f5e6437e95e1438af0a87a3a39084fbd37c90df572" - url: "https://pub.dev" - source: hosted - version: "0.17.6" nm: dependency: transitive description: @@ -1713,14 +1689,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" - objective_c: - dependency: transitive - description: - name: objective_c - sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" - url: "https://pub.dev" - source: hosted - version: "9.3.0" on_chain: dependency: "direct main" description: @@ -1789,10 +1757,10 @@ packages: dependency: transitive description: name: path_provider_foundation - sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" + sha256: "6d13aece7b3f5c5a9731eaf553ff9dcbc2eff41087fd2df587fd0fed9a3eb0c4" url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.5.1" path_provider_linux: dependency: transitive description: @@ -2276,26 +2244,26 @@ packages: dependency: transitive description: name: test - sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7" + sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7" url: "https://pub.dev" source: hosted - version: "1.30.0" + version: "1.26.3" test_api: dependency: transitive description: name: test_api - sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 url: "https://pub.dev" source: hosted - version: "0.7.10" + version: "0.7.7" test_core: dependency: transitive description: name: test_core - sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51" + sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0" url: "https://pub.dev" source: hosted - version: "0.6.16" + version: "0.6.12" tezart: dependency: "direct main" description: @@ -2710,5 +2678,5 @@ packages: source: hosted version: "0.2.4" sdks: - dart: ">=3.10.3 <4.0.0" - flutter: ">=3.38.4 <4.0.0" + dart: ">=3.10.0 <4.0.0" + flutter: ">=3.38.1 <4.0.0" From 2aaeef5a4a4f8e90e0e4d4940664466e48b245a4 Mon Sep 17 00:00:00 2001 From: Matthias Tarasiewicz Date: Tue, 19 May 2026 20:17:32 +0200 Subject: [PATCH 118/118] Commented out PROTOC export in build script Commented out the PROTOC environment variable export (which was referencing PROTOC from brew) to make NixOS build work. --- scripts/patches/flutter_libmwc_macos_build_all.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/patches/flutter_libmwc_macos_build_all.sh b/scripts/patches/flutter_libmwc_macos_build_all.sh index c7fc2541c..7e2315612 100644 --- a/scripts/patches/flutter_libmwc_macos_build_all.sh +++ b/scripts/patches/flutter_libmwc_macos_build_all.sh @@ -20,7 +20,7 @@ cp -r ../../rust build/rust cd build/rust # some people need this apparently -export PROTOC=/opt/homebrew/bin/protoc +# export PROTOC=/opt/homebrew/bin/protoc unset MAKEFLAGS MFLAGS CARGO_MAKEFLAGS MAKELEVEL MAKE_TERMOUT MAKE_TERMERR export MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-11.0}"