Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Building CakeWallet Android App 4.4.0 failed with haven_wallet errors, Missing cw_haven realted build instructions? #337

Closed
emanuelb opened this issue Apr 14, 2022 · 32 comments · Fixed by #2014 · May be fixed by #2016
Closed
Assignees
Labels
Enhancement New feature or request

Comments

@emanuelb
Copy link

emanuelb commented Apr 14, 2022

Build 4.4.0 failed with errors:

cw_haven/lib/haven_wallet.dart:32:6: Error: Error when reading 'cw_haven/lib/haven_wallet.g.dart': No such file or directory

part 'haven_wallet.g.dart';

     ^

cw_haven/lib/haven_transaction_history.dart:6:6: Error: Error when reading 'cw_haven/lib/haven_transaction_history.g.dart': No such file or directory

part 'haven_transaction_history.g.dart';

     ^

cw_haven/lib/haven_wallet_addresses.dart:9:6: Error: Error when reading 'cw_haven/lib/haven_wallet_addresses.g.dart': No such file or directory

part 'haven_wallet_addresses.g.dart';

     ^

cw_haven/lib/haven_account_list.dart:6:6: Error: Error when reading 'cw_haven/lib/haven_account_list.g.dart': No such file or directory

part 'haven_account_list.g.dart';

     ^

cw_haven/lib/haven_subaddress_list.dart:7:6: Error: Error when reading 'cw_haven/lib/haven_subaddress_list.g.dart': No such file or directory

part 'haven_subaddress_list.g.dart';

     ^

cw_haven/lib/haven_wallet.dart:32:6: Error: Can't use 'cw_haven/lib/haven_wallet.g.dart' as a part, because it has no 'part of' declaration.

part 'haven_wallet.g.dart';

     ^

cw_haven/lib/haven_transaction_history.dart:6:6: Error: Can't use 'cw_haven/lib/haven_transaction_history.g.dart' as a part, because it has no 'part of' declaration.

part 'haven_transaction_history.g.dart';

     ^

cw_haven/lib/haven_wallet_addresses.dart:9:6: Error: Can't use 'cw_haven/lib/haven_wallet_addresses.g.dart' as a part, because it has no 'part of' declaration.

part 'haven_wallet_addresses.g.dart';

     ^

cw_haven/lib/haven_account_list.dart:6:6: Error: Can't use 'cw_haven/lib/haven_account_list.g.dart' as a part, because it has no 'part of' declaration.

part 'haven_account_list.g.dart';

     ^

cw_haven/lib/haven_subaddress_list.dart:7:6: Error: Can't use 'cw_haven/lib/haven_subaddress_list.g.dart' as a part, because it has no 'part of' declaration.

part 'haven_subaddress_list.g.dart';

     ^

cw_haven/lib/haven_wallet.dart:36:42: Error: Type '_$HavenWallet' not found.

class HavenWallet = HavenWalletBase with _$HavenWallet;

                                         ^^^^^^^^^^^^^

cw_haven/lib/haven_transaction_history.dart:9:10: Error: Type '_$HavenTransactionHistory' not found.

    with _$HavenTransactionHistory;

         ^^^^^^^^^^^^^^^^^^^^^^^^^

cw_haven/lib/haven_wallet_addresses.dart:12:10: Error: Type '_$HavenWalletAddresses' not found.

    with _$HavenWalletAddresses;

         ^^^^^^^^^^^^^^^^^^^^^^

cw_haven/lib/haven_account_list.dart:8:52: Error: Type '_$HavenAccountList' not found.

class HavenAccountList = HavenAccountListBase with _$HavenAccountList;

                                                   ^^^^^^^^^^^^^^^^^^

cw_haven/lib/haven_subaddress_list.dart:10:10: Error: Type '_$HavenSubaddressList' not found.

    with _$HavenSubaddressList;

         ^^^^^^^^^^^^^^^^^^^^^

cw_haven/lib/haven_wallet.dart:36:7: Error: The type '_$HavenWallet' can't be mixed in.

class HavenWallet = HavenWalletBase with _$HavenWallet;

      ^

cw_haven/lib/haven_transaction_history.dart:8:7: Error: The type '_$HavenTransactionHistory' can't be mixed in.

class HavenTransactionHistory = HavenTransactionHistoryBase

      ^

cw_haven/lib/haven_subaddress_list.dart:9:7: Error: The type '_$HavenSubaddressList' can't be mixed in.

class HavenSubaddressList = HavenSubaddressListBase

      ^

cw_haven/lib/haven_wallet_addresses.dart:11:7: Error: The type '_$HavenWalletAddresses' can't be mixed in.

class HavenWalletAddresses = HavenWalletAddressesBase

      ^

cw_haven/lib/haven_account_list.dart:8:7: Error: The type '_$HavenAccountList' can't be mixed in.

class HavenAccountList = HavenAccountListBase with _$HavenAccountList;

      ^





FAILURE: Build failed with an exception.



* Where:

Script '/home/appuser/app/sdk/flutter/packages/flutter_tools/gradle/flutter.gradle' line: 991



* What went wrong:

Execution failed for task ':app:compileFlutterBuildRelease'.

> Process 'command '/home/appuser/app/sdk/flutter/bin/flutter'' finished with non-zero exit value 1



* Try:

Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.



* Get more help at https://help.gradle.org

Running:
cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. ;

as it's looks like errors cause such command is missing in build instructions, maybe loop over array instead that contain the cw_strings values instead, as it run the same commands just in different directory.

Return:

Running "flutter pub get" in cw_haven...                         2,868ms
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Warning
──────────────────────────────────────────────────────────────────────────────
Your Flutter application is created using an older version of the Android
embedding. It's being deprecated in favor of Android embedding v2. Follow the
steps at

https://flutter.dev/go/android-project-migration

to migrate your project.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

The plugin `cw_haven` requires your app to be migrated to the Android embedding v2. Follow the steps on https://flutter.dev/go/android-project-migration and re-run this command.

Above warning which cause error in this case happened in previous compiling steps, issue opened for it is: #335

Containerfile to reproduce:

FROM docker.io/ubuntu:rolling

RUN set -ex; \
    apt-get update; \
    DEBIAN_FRONTEND=noninteractive apt-get install --yes -o APT::Install-Suggests=false --no-install-recommends \
        openjdk-11-jdk curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang; \
    rm -rf /var/lib/apt/lists/*; \
    useradd -ms /bin/bash appuser; \
    mkdir -p /opt/android/; \
    chown appuser:root /opt/android/;

USER appuser

ENV ANDROID_SDK_ROOT="/home/appuser/app/sdk" \
    ANDROID_HOME="/home/appuser/app/sdk"

RUN set -ex; \
    mkdir -p "/home/appuser/app/sdk/licenses"; \
    printf "\n24333f8a63b6825ea9c5514f83c2829b004d1fee" > "/home/appuser/app/sdk/licenses/android-sdk-license"; \
    cd /home/appuser/app/sdk; \
    curl -o "flutter_linux_2.0.4-stable.tar.xz" https://storage.googleapis.com/flutter_infra/releases/stable/linux/flutter_linux_2.0.4-stable.tar.xz; \
    tar xf flutter_linux_2.0.4-stable.tar.xz; \
    rm flutter_linux_2.0.4-stable.tar.xz; \
    /home/appuser/app/sdk/flutter/bin/flutter config --no-analytics; \
    /home/appuser/app/sdk/flutter/bin/dart --disable-analytics; \
    cd /opt/android/; \
    git clone https://github.com/cake-tech/cake_wallet/;
    
RUN set -ex; \ 
    cd /opt/android/cake_wallet/; \
    git checkout v4.4.0; \
    cd /opt/android/cake_wallet/scripts/android/; \
    ./install_ndk.sh;
    
ENV PATH=/home/appuser/app/sdk/flutter/bin/:$PATH
WORKDIR /opt/android/cake_wallet/scripts/android/

Build container with command podman build --pull --rm -t cakewallet_build_apk -f ContainerFile
Run container with command podman run --rm --name cakewallet_build_apk -ti cakewallet_build_apk
In container run commands:

source ./app_env.sh cakewallet;
./app_config.sh;
./build_all.sh;
./copy_monero_deps.sh;
cd /opt/android/cake_wallet/;
/home/appuser/app/sdk/flutter/bin/flutter pub get;
/home/appuser/app/sdk/flutter/bin/flutter packages pub run tool/generate_new_secrets.dart;
keytool -genkey -v -keystore $HOME/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias cake_alias -storepass cake_alias -keypass cake_alias -dname CN=IL;
/home/appuser/app/sdk/flutter/bin/flutter packages pub run tool/generate_android_key_properties.dart keyAlias=cake_alias storeFile=$HOME/key.jks storePassword=cake_alias keyPassword=cake_alias;
/home/appuser/app/sdk/flutter/bin/flutter packages pub run tool/generate_localization.dart;
cd cw_core && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. ;
cd cw_monero && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. ;
cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. ;
cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. ;
/home/appuser/app/sdk/flutter/bin/flutter packages pub run build_runner build --delete-conflicting-outputs;
/home/appuser/app/sdk/flutter/bin/flutter build apk --release;
@emanuelb emanuelb changed the title Missing cw_haven Building CakeWallet Android App 4.4.0 failed with haven_wallet errors, Missing cw_haven realted build instructions? Apr 14, 2022
@SamsungGalaxyPlayer SamsungGalaxyPlayer added the Enhancement New feature or request label Oct 28, 2022
@Giszmo
Copy link

Giszmo commented Nov 2, 2022

How is progress on this? How can we compile this app?

@tuxpizza tuxpizza closed this as not planned Won't fix, can't repro, duplicate, stale Feb 25, 2024
@ghost
Copy link

ghost commented Apr 27, 2024

Why was this issue closed without any investigation or explanation? I'm concerned that the APK was demonstrably NOT reproducible.

@tuxpizza
Copy link
Collaborator

tuxpizza commented May 1, 2024

Hi, was a mistake to close this issue without a resolution.... as this issue was from 2 years ago, the build guide has been updated since then and I believe this is what you need:

Generate mobx models for cw_haven:

cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..

Please have a look the current build guide and try building the latest main or version tag: https://github.com/cake-tech/cake_wallet/blob/main/howto-build-android.md

For discussion on 1 to 1 binary reproduceability, #112 and #338 will still be open.

Let us know if you have any other build questions 😃

@tuxpizza tuxpizza reopened this May 1, 2024
@ghost
Copy link

ghost commented May 1, 2024

Thanks @tuxpizza

@emanuelb Even though the Cake team hasn't seemed too concerned about it in the last few years, for the sake of the larger community I hope this package can be reevaluated on WalletScrutiny!

@xrviv
Copy link

xrviv commented Jul 2, 2024

Cool. In relation to current attempts by WalletScrutiny to re-verify apps, I'm opening an issue for walletscrutiny.com again. Hopefully, this app can be verified.

@xrviv
Copy link

xrviv commented Jul 17, 2024

The issue is here: https://gitlab.com/walletscrutiny/walletScrutinyCom/-/issues/537

We have our plates full though - so if anybody would like to boost the spirit of Open Source, you are most welcome to build this app.

@keraliss
Copy link

keraliss commented Jul 26, 2024

Hi, I tried to build the latest version, 4.19.1 and ran into some errors.

FROM ubuntu:20.04

# Avoid prompts from apt
ENV DEBIAN_FRONTEND=noninteractive

# Install required packages
RUN apt-get update && apt-get install -y \
    wget \
    curl \
    unzip \
    automake \
    build-essential \
    file \
    pkg-config \
    git \
    python \
    libtool \
    libtinfo5 \
    cmake \
    openjdk-8-jre-headless \
    clang

# Install Android SDK and NDK
ENV ANDROID_SDK_ROOT /opt/android-sdk
ENV ANDROID_NDK_ROOT /opt/android-ndk
ENV ANDROID_HOME ${ANDROID_SDK_ROOT}
ENV PATH ${PATH}:${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin:${ANDROID_SDK_ROOT}/platform-tools:${ANDROID_NDK_ROOT}

RUN mkdir -p ${ANDROID_SDK_ROOT}/cmdline-tools && \
    wget -q https://dl.google.com/android/repository/commandlinetools-linux-6858069_latest.zip -O android-sdk.zip && \
    unzip -q android-sdk.zip -d ${ANDROID_SDK_ROOT}/cmdline-tools && \
    mv ${ANDROID_SDK_ROOT}/cmdline-tools/cmdline-tools ${ANDROID_SDK_ROOT}/cmdline-tools/latest && \
    rm android-sdk.zip && \
    yes | ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager --sdk_root=${ANDROID_SDK_ROOT} "platform-tools" "platforms;android-33" "build-tools;33.0.0" && \
    wget -q https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip -O android-ndk.zip && \
    unzip -q android-ndk.zip -d /opt && \
    mv /opt/android-ndk-r17c ${ANDROID_NDK_ROOT} && \
    rm android-ndk.zip

# Install Flutter
ENV FLUTTER_ROOT /opt/flutter
ENV PATH ${PATH}:${FLUTTER_ROOT}/bin

RUN git clone https://github.com/flutter/flutter.git -b stable ${FLUTTER_ROOT} && \
    flutter doctor

# Install rustup
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y

# Set up working directory
WORKDIR /app

# Clone Cake Wallet repository with the specific tag
RUN git clone https://github.com/cake-tech/cake_wallet.git . && \
    git fetch --all --tags && \
    git checkout tags/v4.19.1

# Generate keystore file
RUN keytool -genkey -v -keystore /root/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key -storepass your_store_password -keypass your_key_password -dname "CN=Your Name, OU=Your Organizational Unit, O=Your Organization, L=Your City, S=Your State, C=Your Country Code"

# Remove pubspec.lock to avoid conflicts
RUN find . -name pubspec.lock -exec rm -f {} \;

# Modify pubspec.yaml to fix intl dependency issue (more flexible regex)
RUN find . -name pubspec.yaml -print -exec sed -i 's/intl:.*$/intl: 0.19.0/' {} \; && \
    echo "pubspec.yaml files updated" && \
    grep -R "intl: 0.19.0" . || echo "Failed to update intl version"

# Set environment variables for the build
ENV ANDROID_SDK_ROOT=${ANDROID_SDK_ROOT}
ENV ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT}
ENV PATH=${PATH}:${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin:${ANDROID_SDK_ROOT}/platform-tools:${ANDROID_NDK_ROOT}

# Build Cake Wallet
RUN mkdir -p /opt/android && \
    cd scripts/android && \
    echo "Current directory: $(pwd)" && \
    ls -la && \
    ./install_ndk.sh && \
    bash -c "set -x && source ./app_env.sh cakewallet && \
    ./app_config.sh && \
    echo 'Content of build_haven.sh:' && cat build_haven.sh && \
    ./build_all.sh" && \
    cd ../../ && \
    flutter pub get && \
    flutter pub upgrade --major-versions && \
    flutter packages pub run tool/generate_new_secrets.dart && \
    flutter packages pub run tool/generate_android_key_properties.dart keyAlias=key storeFile=/root/key.jks storePassword=your_store_password keyPassword=your_key_password && \
    flutter packages pub run tool/generate_localization.dart && \
    ./model_generator.sh && \
    flutter build apk --release

# The APK will be located at /app/build/app/outputs/flutter-apk/app-release.apk

# Add SHA256 checksums for verification
RUN echo "4324fe3ee56762c012135884ff3ac99c7194ffaeabcb26d9359316fc2e0d1426  /app/build/app/outputs/flutter-apk/app-release.apk" > /app/checksums.txt && \
    sha256sum -c /app/checksums.txt

# Add release notes
RUN echo "Cake Wallet v4.19.1 Release Notes:" > /app/release_notes.txt && \
    echo "* Monero and Ethereum enhancements" >> /app/release_notes.txt && \
    echo "* Synchronization improvements" >> /app/release_notes.txt && \
    echo "* Exchange flow enhancements" >> /app/release_notes.txt && \
    echo "* Ledger improvements" >> /app/release_notes.txt && \
    echo "* Bug fixes" >> /app/release_notes.txt

This is the dockerfile i created. this follows the build instructions provided in the howto-build-android.md . I faced this error

Resolving dependencies...

Note: intl is pinned to version 0.19.0 by flutter_localizations from the flutter SDK.

See https://dart.dev/go/sdk-version-pinning for details.

Because cake_wallet depends on flutter_localizations from sdk which depends on intl 0.19.0, intl 0.19.0 is required.

So, because cake_wallet depends on intl ^0.18.0, version solving failed.

You can try the following suggestion to make the pubspec resolve:

* Try an upgrade of your constraints: flutter pub upgrade --major-versions

The command '/bin/sh -c mkdir -p /opt/android &&     cd scripts/android &&     ./install_ndk.sh &&     bash -c "source ./app_env.sh cakewallet &&     ./app_config.sh &&     ./build_all.sh" &&     cd ../../ &&     flutter pub get &&     flutter pub upgrade --major-versions &&     flutter packages pub run tool/generate_new_secrets.dart &&     flutter packages pub run tool/generate_android_key_properties.dart keyAlias=key storeFile=/root/key.jks storePassword=your_store_password keyPassword=your_key_password &&     flutter packages pub run tool/generate_localization.dart &&     ./model_generator.sh &&     flutter build apk --release' returned a non-zero code: 1

It is in my understanding a dependency conflict, which arises due to flutter_localizations requiring intl version 0.19.0, while cake_wallet depends on intl version ^0.18.0. This version conflict causes the resolution process to fail. I tried to fix this by manually finding and fixing the file:

# Remove pubspec.lock to avoid conflicts
RUN find . -name pubspec.lock -exec rm -f {} \;

# Modify pubspec.yaml to fix intl dependency issue (more flexible regex)
RUN find . -name pubspec.yaml -print -exec sed -i 's/intl:.*$/intl: 0.19.0/' {} \; && \
    echo "pubspec.yaml files updated" && \
    grep -R "intl: 0.19.0" . || echo "Failed to update intl version"

but sadly that didn't work. I also tried deleting the pubspec.lock so it can be generated later, but that also didn't work. Any idea or suggestion on what to do next on this?

@Justxd22
Copy link
Contributor

Justxd22 commented Nov 4, 2024

Hello, I wrote a new working docker as of last commit b8ffd47 compiling a working APK I believe v4.20.1 is building and working fine,

Building logs here, Dockerfile here

Commented lines for easy env fill

# <----- how to run ----->
# mkdir build
# docker build -f cakeRELEASE.Dockerfile -t cake .
# docker create -it --name cake cake bash
# docker cp cake:/build/. build/



# Base image with Flutter
FROM instrumentisto/flutter:3.19.6

# Set environment variables
ENV STORE_PASS=test@cake_wallet \
    KEY_PASS=test@cake_wallet \
    ANDROID_ROOT=/usr/local/lib/android \
    ANDROID_SDK_ROOT=/usr/local/lib/android/sdk \
    ANDROID_HOME=/usr/local/lib/android/sdk \
    ANDROID_NDK_HOME=/usr/local/lib/android/sdk/ndk/27.1.12297006 \
    ANDROID_NDK_ROOT=/usr/local/lib/android/sdk/ndk/27.1.12297006 \
    ANDROID_NDK=/usr/local/lib/android/sdk/ndk/27.1.12297006 \
    PATH=$PATH:/usr/local/lib/android/sdk/cmdline-tools/latest/bin:/usr/local/lib/android/sdk/platform-tools

SHELL ["/bin/bash", "-c"]

# Install dependencies
RUN apt update && \
    apt-get install -y \
    curl \
    unzip \
    automake \
    build-essential \
    autoconf \
    file \
    pkg-config \
    git \
    python-is-python3 \
    libtool \
    libtinfo5 \
    make \
    gcc \
    g++ \
    lbzip2 \
    cmake \
    ccache \
    gperf \
    openjdk-8-jre-headless \
    clang


# Install Android SDK components
RUN rm -rf /opt/android-sdk-linux && \
    mkdir -p $ANDROID_SDK_ROOT/cmdline-tools && \
    curl -o commandlinetools.zip -L https://dl.google.com/android/repository/commandlinetools-linux-9123335_latest.zip && \
    unzip -qq commandlinetools.zip -d $ANDROID_SDK_ROOT/cmdline-tools && \
    mv $ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools $ANDROID_SDK_ROOT/cmdline-tools/latest && \
    rm commandlinetools.zip && \
    yes | $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --licenses && \
    $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager \
        "platform-tools" \
        "platforms;android-30" \
        "build-tools;30.0.3" \
        "ndk;27.1.12297006" && \
    chmod -R a+rwx $ANDROID_SDK_ROOT


# Set up Android environment
RUN mkdir -p /opt/android && \
    cd /opt/android && \
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && \
    . "$HOME/.cargo/env" && \
    cargo install cargo-ndk && \
    git clone https://github.com/cake-tech/cake_wallet.git && \
    cd cake_wallet/scripts/android/ && \
    ./install_ndk.sh && \
    source ./app_env.sh cakewallet && \
    chmod +x pubspec_gen.sh && \
    ./app_config.sh && \
    git config --global --add safe.directory '*' && \
    git config --global user.email "[email protected]" && \
    git config --global user.name "Docker Build Test"

    
# Build mwebd
RUN wget https://go.dev/dl/go1.23.1.linux-amd64.tar.gz && \
    rm -rf /usr/local/go && \
    tar -C /usr/local -xzf go1.23.1.linux-amd64.tar.gz && \
    export PATH=$PATH:/usr/local/go/bin && \
    go install golang.org/x/mobile/cmd/gomobile@latest && \
    export PATH=$PATH:~/go/bin && \
    gomobile init && \
    cd /opt/android/cake_wallet/scripts/android/ && \
    ./build_mwebd.sh --dont-install


# Build binaries (this step may take a while)
# RUN cd /opt/android/cake_wallet/scripts/android/ && \
#     bash -c "set -x && source ./app_env.sh cakewallet && \
#     echo 'BUILDING BINS:' && \
#     ./build_monero_all.sh" 

# Fetch Flutter dependencies
# download pre-Built binaries
# keystore + Localization + model
RUN cd /opt/android/cake_wallet && \
    flutter pub get && \
    flutter packages pub run tool/download_moneroc_prebuilds.dart && \
    cd /opt/android/cake_wallet/android/app && \
    keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt \
    -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" \
    -storepass $STORE_PASS -keypass $KEY_PASS && \
    cd /opt/android/cake_wallet && \
    flutter packages pub run tool/generate_android_key_properties.dart \
    keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS && \
    flutter packages pub run tool/generate_localization.dart && \
    flutter packages pub run tool/generate_new_secrets.dart && \
    ./model_generator.sh

# ---- Add Secrets with Placeholders ----
# RUN cd /opt/android/cake_wallet && \
#     touch lib/.secrets.g.dart && \
#     touch cw_evm/lib/.secrets.g.dart && \
#     touch cw_solana/lib/.secrets.g.dart && \
#     touch cw_core/lib/.secrets.g.dart && \
#     touch cw_nano/lib/.secrets.g.dart && \
#     touch cw_tron/lib/.secrets.g.dart && \
#     echo "const salt = '00000000000000000000000000000000';" > lib/.secrets.g.dart && \
#     echo "const keychainSalt = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const key = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const walletSalt = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const shortKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const backupSalt = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const backupKeychainSalt = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const changeNowApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const changeNowApiKeyDesktop = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const wyreSecretKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const wyreApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const wyreAccountId = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const moonPayApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const moonPaySecretKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const sideShiftAffiliateId = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const simpleSwapApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const simpleSwapApiKeyDesktop = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const onramperApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const anypayToken = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const ioniaClientId = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const twitterBearerToken = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const trocadorApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const trocadorExchangeMarkup = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const anonPayReferralCode = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const fiatApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const payfuraApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const ankrApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const etherScanApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const polygonScanApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const etherScanApiKey = '00000000000000000000000000000000';" >> cw_evm/lib/.secrets.g.dart && \
#     echo "const moralisApiKey = '00000000000000000000000000000000';" >> cw_evm/lib/.secrets.g.dart && \
#     echo "const chatwootWebsiteToken = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const exolixApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const robinhoodApplicationId = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const exchangeHelperApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const walletConnectProjectId = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const moralisApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const polygonScanApiKey = '00000000000000000000000000000000';" >> cw_evm/lib/.secrets.g.dart && \
#     echo "const ankrApiKey = '00000000000000000000000000000000';" >> cw_solana/lib/.secrets.g.dart && \
#     echo "const testCakePayApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const cakePayApiKey = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const authorization = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const CSRFToken = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const quantexExchangeMarkup = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const nano2ApiKey = '00000000000000000000000000000000';" >> cw_nano/lib/.secrets.g.dart && \
#     echo "const nanoNowNodesApiKey = '00000000000000000000000000000000';" >> cw_nano/lib/.secrets.g.dart && \
#     echo "const tronGridApiKey = '00000000000000000000000000000000';" >> cw_tron/lib/.secrets.g.dart && \
#     echo "const tronNowNodesApiKey = '00000000000000000000000000000000';" >> cw_tron/lib/.secrets.g.dart && \
#     echo "const letsExchangeBearerToken = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const letsExchangeAffiliateId = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const stealthExBearerToken = '00000000000000000000000000000000';" >> lib/.secrets.g.dart && \
#     echo "const stealthExAdditionalFeePercent = '00000000000000000000000000000000';" >> lib/.secrets.g.dart

# Build APK
RUN cd /opt/android/cake_wallet && \
    flutter build apk --release --split-per-abi

# copy apk
RUN mkdir /build/ && \
    cp /opt/android/cake_wallet/build/app/outputs/flutter-apk/* /build/

# Zip the build folder
RUN cd /build && \
    zip -r build_output.zip . && \
    echo "Zipped build folder created at /build/build_output.zip"


# Upload the zip file to bashupload and log the link
RUN UPLOAD_URL=$(curl bashupload.com -T /build/build_output.zip) && \
    echo "Build file uploaded successfully. Download link: $UPLOAD_URL"

@keraliss
Copy link

keraliss commented Nov 26, 2024

hey, keraliss from walletscrutiny here!! I was able to build the apks using the dockerfile provided by @Justxd22 .
i also got the apks for the official official version. while comparing, i got these diff -
diff --recursive fromBuild fromOfficial

Only in fromOfficial/META-INF: BNDLTOOL.RSA
Only in fromOfficial/META-INF: BNDLTOOL.SF
Only in fromOfficial/META-INF: MANIFEST.MF
Only in fromOfficial/res: anim
Only in fromOfficial/res: animator
Only in fromOfficial/res: animator-v21
Only in fromOfficial/res: anim-v21
Only in fromOfficial/res: drawable
Only in fromOfficial/res: drawable-anydpi-v23
Only in fromOfficial/res: drawable-hdpi-v4
Only in fromOfficial/res: drawable-night-v8
Only in fromOfficial/res: drawable-v21
Only in fromOfficial/res: drawable-v23
Only in fromOfficial/res: drawable-watch-v20
Only in fromOfficial/res: interpolator
Only in fromOfficial/res: interpolator-v21
Only in fromOfficial/res: layout
Only in fromOfficial/res: layout-land
Only in fromOfficial/res: layout-sw600dp-v13
Only in fromOfficial/res: layout-v21
Only in fromOfficial/res: layout-v26
Only in fromOfficial/res: layout-watch-v20
Only in fromOfficial/res: menu
Only in fromOfficial/res: mipmap-anydpi-v26
Only in fromOfficial/res: mipmap-hdpi-v4
Only in fromOfficial/res: mipmap-mdpi-v4
Only in fromOfficial/res: mipmap-xhdpi-v4
Only in fromOfficial/res: mipmap-xxhdpi-v4
Only in fromOfficial/res: mipmap-xxxhdpi-v4
Only in fromOfficial/res: xml
Only in fromOfficial: stamp-cert-sha256

there were also 700+ lines of diff for xml and png files. would be great if you guys can look into it!

@Justxd22
Copy link
Contributor

@sethforprivacy what do you think of this!

@tuxpizza
Copy link
Collaborator

tuxpizza commented Dec 1, 2024

I'll look into this over the next week. At the moment Cake isn't reproducible regardless of these random xml and png files (not sure why) because of the API key secrets that are added during build time that aren't in the repository.

@KewbitXMR
Copy link

hey, keraliss from walletscrutiny here!! I was able to build the apks using the dockerfile provided by @Justxd22 . i also got the apks for the official official version. while comparing, i got these diff - diff --recursive fromBuild fromOfficial

Only in fromOfficial/META-INF: BNDLTOOL.RSA
Only in fromOfficial/META-INF: BNDLTOOL.SF
Only in fromOfficial/META-INF: MANIFEST.MF
Only in fromOfficial/res: anim
Only in fromOfficial/res: animator
Only in fromOfficial/res: animator-v21
Only in fromOfficial/res: anim-v21
Only in fromOfficial/res: drawable
Only in fromOfficial/res: drawable-anydpi-v23
Only in fromOfficial/res: drawable-hdpi-v4
Only in fromOfficial/res: drawable-night-v8
Only in fromOfficial/res: drawable-v21
Only in fromOfficial/res: drawable-v23
Only in fromOfficial/res: drawable-watch-v20
Only in fromOfficial/res: interpolator
Only in fromOfficial/res: interpolator-v21
Only in fromOfficial/res: layout
Only in fromOfficial/res: layout-land
Only in fromOfficial/res: layout-sw600dp-v13
Only in fromOfficial/res: layout-v21
Only in fromOfficial/res: layout-v26
Only in fromOfficial/res: layout-watch-v20
Only in fromOfficial/res: menu
Only in fromOfficial/res: mipmap-anydpi-v26
Only in fromOfficial/res: mipmap-hdpi-v4
Only in fromOfficial/res: mipmap-mdpi-v4
Only in fromOfficial/res: mipmap-xhdpi-v4
Only in fromOfficial/res: mipmap-xxhdpi-v4
Only in fromOfficial/res: mipmap-xxxhdpi-v4
Only in fromOfficial/res: xml
Only in fromOfficial: stamp-cert-sha256

there were also 700+ lines of diff for xml and png files. would be great if you guys can look into it!

This might be standard if they have flutter_icons installed and the versions have been upgraded and those extra images type could be rendered legitimately from a source image (sorry I should check pubspec on phone and in rush). Or if you want to lay as the sceptic you could say..

So making changes, cause that could be potentially malicious, or potentially good.. They should be check for basic steganography, pull a dictionary on Linux, and see if there are any hex code to ascii which match’s to anything in the dictionary where the word is at least 3 characters long (we’re looking for encoded human readable or suspicious looking strings that wouldn’t otherwise be in an image. You might have to look at every image to find anything unless there is a valid justification for this change I personally would avoid compiling and running it myself, and I use DispableVMs in Qubes-Whonix, it’s also with checking the mimetype is definitely and image/ which are basically just file types, I don’t think there is any excuse for there to be anything that sys the word application, binary. (edited)

I can be normal for exception less images to be referenced that’s how Java/Android like to do things, you could try building an alternate platform. See if the same kind of things happen. Checking the hex’s too etc.

There is a useful Snap on Snapcraft to check hex (i known some people hate snap, but it’s not that bad anymore) heehe

Also. I figured cw_monero was the proprietary part, no? I mean that’s where all the value is really.

@MrCyjaneK
Copy link
Collaborator

@KewbitXMR no, cw_monero is not proprietary.. it is in main directory of the project...

@xrviv
Copy link

xrviv commented Feb 8, 2025

Hey everyone, danny here from @WalletScrutiny, I'm picking up here where I left of with v4.23.0.

Attempt 1:

Previous attempts primarily centered on generating single-apks.
Cake Wallet uses AAB, which is then used to generate the split apks.

I would document my attempts here.

2025-02-08

WS primary methodology for verifying split apks, revolves around the testAAB.sh script

Here the version number is determined, the app hashes reported, and passed on to the more flexible script and dockerfile:

Encountered an error:

Setting up g++-9 (9.4.0-1ubuntu1~20.04.2) ...
Setting up g++ (4:9.3.0-1ubuntu2) ...
update-alternatives: using /usr/bin/g++ to provide /usr/bin/c++ (c++) in auto mode
update-alternatives: warning: skip creation of /usr/share/man/man1/c++.1.gz because associated file /usr/share/man/man1/g++.1.gz (of link group c++) doesn't exist
Setting up gnupg (2.2.19-3ubuntu2.2) ...
Setting up build-essential (12.8ubuntu1.1) ...
Setting up clang-10 (1:10.0.0-4ubuntu1) ...
Setting up llvm-10-tools (1:10.0.0-4ubuntu1) ...
Setting up llvm-10-dev (1:10.0.0-4ubuntu1) ...
Setting up clang (1:10.0-50~exp1) ...
Processing triggers for libc-bin (2.31-0ubuntu9.1) ...
Errors were encountered while processing:
 openjdk-8-jre-headless:amd64
 openjdk-8-jdk-headless:amd64
E: Sub-process /usr/bin/dpkg returned an error code (1)
Error: building at STEP "RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y     wget curl unzip automake build-essential file pkg-config git python3     libtool libtinfo5 cmake openjdk-8-jre-headless clang sudo xz-utils     && rm -rf /var/lib/apt/lists/*": while running runtime: exit status 100

Build 1 - fail
Build 2 - fail
Build 3 - fail - No Python Error
Build 4 - fail

Error:

71600K .......... .......... .......... .......... .......... 99%  231M 0s
 71650K .......... .......... .......... .......... .......... 99% 89.5M 0s
 71700K .......... .......... .......... .......... .......... 99%  214M 0s
 71750K .......... .......... .......... .......... .......... 99%  190M 0s
 71800K .......... .......... .......... .......... .......... 99%  142M 0s
 71850K .......... .......... ...                             100%  201M=1.7s

2025-02-08 11:06:15 (41.6 MB/s) - 'go1.23.1.linux-amd64.tar.gz' saved [73598519/73598519]

go: downloading golang.org/x/mobile v0.0.0-20250106192035-c31d5b91ecc3
go: downloading golang.org/x/mod v0.22.0
go: downloading golang.org/x/sync v0.10.0
go: downloading golang.org/x/tools v0.29.0
./build_mwebd.sh: 10: gomobile: not found
Cloning into 'mwebd'...
HEAD is now at 5553494 Return address sequence
./build_mwebd.sh: 17: gomobile: not found
cp: cannot stat './mwebd.aar': No such file or directory

@sethforprivacy
Copy link
Contributor

Hey @xrviv, thanks so much for taking a look at this!

I'm working right now to update our build docs + Dockerize the build process, will report back when that's done and we can get down to details of what is/isn't the same between release APKs and those built from source.

@Justxd22
Copy link
Contributor

Justxd22 commented Feb 9, 2025

@xrviv please follow up in this thread https://forum.cakewallet.com/t/wallet-scrutiny-review-process/59

the error you posted related to mwebd should be fixed using the dockerfile i posted line 83

https://github.com/Justxd22/Cake_wallet_DOCKER_xD/blob/main/cakeRELEASE.Dockerfile#L83

@xrviv
Copy link

xrviv commented Feb 10, 2025

Thank you,

There are currently 3 venues for the build, so to comply with both WalletScrutiny.com's requirements and yours, I will mirror my attempts: cakewallet forum and here

build005

I encountered an error:

///opt/android/cake_wallet/tool/download_moneroc_prebuilds.dart#46:7 main:   extracting scripts/monero_c/release/monero/x86_64-w64-mingw32_libssp-0.dll
Unhandled exception:
FormatException: Invalid XZ stream header signature
#0      _XZStreamDecoder._readStreamHeader (package:archive/src/xz_decoder.dart:73:7)
#1      _XZStreamDecoder.decode (package:archive/src/xz_decoder.dart:47:5)
#2      XZDecoder.decodeBuffer (package:archive/src/xz_decoder.dart:22:20)
#3      main (file:///opt/android/cake_wallet/tool/download_moneroc_prebuilds.dart:48:35)
<asynchronous suspension>
The command '/bin/bash -c cd /opt/android/cake_wallet &&     flutter pub get &&     dart run tool/download_moneroc_prebuilds.dart &&     cd /opt/android/cake_wallet/android/app &&     keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt     -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA"     -storepass $STORE_PASS -keypass $KEY_PASS &&     cd /opt/android/cake_wallet &&     dart run tool/generate_android_key_properties.dart     keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS &&     dart run tool/generate_localization.dart &&     dart run tool/generate_new_secrets.dart &&     ./model_generator.sh' returned a non-zero code: 255
danny@lw10:~/work/builds/com.cakewallet.cake_wallet/4.23.0/Cake_wallet_DOCKER_xD$

I am modifying the dockerfile slightly. continuing.


Build 006

Build 007

With Build 008

I was able to get past that error and reach the build process stage, by modifying the Dockerfile like so:

We added a patch step to the download_moneroc_prebuilds.dart script so it skips the .dll file instead of trying to decompress it (which was causing the “Invalid XZ stream header signature” error). This ensures only .xz files get extracted.

All other steps remain the same (e.g., building MWEB, installing the SDK/NDK, generating secrets, and building the APK). The only functional difference is that we’re no longer decompressing the non-XZ .dll, letting the rest of the Docker build complete successfully.

This is the latest error:

Removing intermediate container 141c5b71dc04
 ---> e4244238b744
Step 11/15 : RUN sed -i "s/bitco inCashTestWalletReceiveAddress/bitcoinCashTestWalletReceiveAddresss/" /opt/android/cake_wallet/lib/.secrets.g.dart
 ---> Running in c3d9ab48c154
Removing intermediate container c3d9ab48c154
 ---> c4efcba8b5c1
Step 12/15 : RUN cd /opt/android/cake_wallet &&     flutter build apk --release --split-per-abi
 ---> Running in fe0c7340a348

Running Gradle task 'assembleRelease'...                        
You are applying Flutter's main Gradle plugin imperatively using the apply script method, which is deprecated and will be removed in a future release. Migrate to applying Gradle plugins with the declarative plugins block: https://flutter.dev/to/flutter-gradle-plugin-apply

Checking the license for package Android SDK Build-Tools 34 in /usr/local/lib/android/sdk/licenses
License for package Android SDK Build-Tools 34 accepted.
Preparing "Install Android SDK Build-Tools 34 v.34.0.0".
"Install Android SDK Build-Tools 34 v.34.0.0" ready.
Installing Android SDK Build-Tools 34 in /usr/local/lib/android/sdk/build-tools/34.0.0
"Install Android SDK Build-Tools 34 v.34.0.0" complete.
"Install Android SDK Build-Tools 34 v.34.0.0" finished.
Checking the license for package Android SDK Platform 34 in /usr/local/lib/android/sdk/licenses
License for package Android SDK Platform 34 accepted.
Preparing "Install Android SDK Platform 34 (revision 3)".
"Install Android SDK Platform 34 (revision 3)" ready.
Installing Android SDK Platform 34 in /usr/local/lib/android/sdk/platforms/android-34
"Install Android SDK Platform 34 (revision 3)" complete.
"Install Android SDK Platform 34 (revision 3)" finished.
Checking the license for package Android SDK Platform 33 in /usr/local/lib/android/sdk/licenses
License for package Android SDK Platform 33 accepted.
Preparing "Install Android SDK Platform 33 (revision 3)".
"Install Android SDK Platform 33 (revision 3)" ready.
Installing Android SDK Platform 33 in /usr/local/lib/android/sdk/platforms/android-33
"Install Android SDK Platform 33 (revision 3)" complete.
"Install Android SDK Platform 33 (revision 3)" finished.
lib/exchange/provider/chainflip_exchange_provider.dart:43:40: Error: Undefined name 'chainflipAffiliateFee'.
  static const _affiliateBps = secrets.chainflipAffiliateFee;
                                       ^^^^^^^^^^^^^^^^^^^^^
Target kernel_snapshot_program failed: Exception


FAILURE: Build failed with an exception.

* Where:
Script '/usr/local/flutter/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy' line: 1687

* What went wrong:
Execution failed for task ':app:compileFlutterBuildRelease'.
> Process 'command '/usr/local/flutter/bin/flutter'' finished with non-zero exit value 1

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

BUILD FAILED in 4m 43s
Running Gradle task 'assembleRelease'...                          284.1s
Gradle task assembleRelease failed with exit code 1
The command '/bin/bash -c cd /opt/android/cake_wallet &&     flutter build apk --release --split-per-abi' returned a non-zero code: 1

Explanation for the error:

Cake Wallet code is referencing a secret variable named chainflipAffiliateFee, but that constant was never defined in .secrets.g.dart. As a result, when Gradle tries to compile chainflip_exchange_provider.dart, it encounters Undefined name 'chainflipAffiliateFee'.

  1. The Fix
    Add a placeholder definition of chainflipAffiliateFee to .secrets.g.dart (or wherever your secrets are generated).

Some Progress 2025-02-10 18:35

Build 009 - Success! But need to target more specific to arch of builder's phone - Dockerfile

Image

MrCyjaneK added a commit that referenced this issue Feb 10, 2025
@MrCyjaneK MrCyjaneK mentioned this issue Feb 10, 2025
5 tasks
OmarHatem28 pushed a commit that referenced this issue Feb 10, 2025
@MrCyjaneK MrCyjaneK reopened this Feb 10, 2025
@sethforprivacy
Copy link
Contributor

I'm not sure that simply downloading the necessary libraries properly fits the goal of reproducibility here, even if it does greatly simplify builds.

I've opened a draft PR with my docs and Dockerfile changes, feel free to peruse those to see if anything is useful in your quest to reproduce Cake Wallet:

#2016

@Justxd22
Copy link
Contributor

I'm not sure that simply downloading the necessary libraries properly fits the goal of reproducibility here, even if it does greatly simplify builds.

I made it optional to use pre-built for faster build time vs build the binaries

https://github.com/Justxd22/Cake_wallet_DOCKER_xD?tab=readme-ov-file#how-to-build

@xrviv
Copy link

xrviv commented Feb 10, 2025

I'm not sure that simply downloading the necessary libraries properly fits the goal of reproducibility here, even if it does greatly simplify builds.

I've opened a draft PR with my docs and Dockerfile changes, feel free to peruse those to see if anything is useful in your quest to reproduce Cake Wallet:

#2016

Thank you. I will test the dockerfile.

@xrviv
Copy link

xrviv commented Feb 10, 2025

Seth's Dockerfile
Dan's Dockerfile alpha.010

Category Seth's Dockerfile Our Earlier Dockerfile Impact
Base Image Uses Debian 12 (docker.io/debian:12) Uses Flutter-based image (instrumentisto/flutter) More flexibility in Seth's approach, but requires more setup.
Android SDK Installation Downloads + sets up SDK manually SDK already included in instrumentisto/flutter ⚠️ More work in Seth's approach but ensures full control.
NDK Version Uses NDK 27.2.12479018 Uses NDK 27.1.12297006 ⚠️ Slightly different versions may cause build issues.
Rust Setup Manually installs rustup + cargo-ndk Also installs rustup + cargo-ndk Same approach.
Go Installation Installs Go 1.23.4 Installs Go 1.23.1 ⚠️ Minor version difference may or may not matter.
Build Dependencies More dependencies installed (bc, sqlite3, ninja) Installs minimal dependencies ✅ Seth's version may be more robust but also heavier.
Emulator Support Installs Android Emulator dependencies (x86, x86_64) Does not install Emulator support ✅ Seth's version supports Android emulators, useful for CI testing.
Node.js Installation Includes Node.js for GitHub Actions Does not include Node.js ⚠️ Only needed for CI/CD pipelines.
Flutter Installation Clones Flutter manually (git clone) Uses pre-built Flutter image ✅ Our earlier version is cleaner and simpler.
Pre-Caching Flutter Artifacts Runs flutter precache for speed optimization Does not run flutter precache ✅ Seth's version speeds up builds but increases image size.

@Justxd22
Copy link
Contributor

@xrviv second link is broken

@xrviv
Copy link

xrviv commented Feb 10, 2025

@xrviv second link is broken

fixed, thanks. this one:

✅ Builds Monero dependencies from source.
✅ Builds Cake Wallet’s native components from source.
✅ Compiles everything inside a clean, controlled Docker environment.
✅ Ensures device-specific APK extraction rather than using generic pre-built APKs.

It's taking quite some time though. So no results yet

/opt/android/cake_wallet/scripts/monero_c/zano/contrib/epee/include/net/http_server_handlers_map2.h:458:3: note: expanded from macro 'MAP_JON_RPC_WE'
  PREPARE_OBJECTS_FROM_JSON(command_type) \
  ^
/opt/android/cake_wallet/scripts/monero_c/zano/contrib/epee/include/net/http_server_handlers_map2.h:434:18: note: expanded from macro 'PREPARE_OBJECTS_FROM_JSON'
    fail_resp.id = req.id; \
                 ^
13 warnings generated.
16 warnings generated.
13 warnings generated.
16 warnings generated.
16 warnings generated.
14 warnings generated.
[ 96%] Linking CXX static library libwallet.a
[ 96%] Built target wallet
[ 98%] Building CXX object CMakeFiles/wallet2_api_c.dir/src/main/cpp/helpers.cpp.o
[ 98%] Building CXX object CMakeFiles/wallet2_api_c.dir/src/main/cpp/wallet2_api_c.cpp.o
[100%] Linking CXX shared library libwallet2_api_c.so
[100%] Built target wallet2_api_c
/opt/android/cake_wallet/scripts/monero_c/zano_libwallet2_api_c /opt/android/cake_wallet/scripts/monero_c
/opt/android/cake_wallet/scripts/monero_c
/opt/android/cake_wallet/scripts/monero_c/release/zano /opt/android/cake_wallet/scripts/monero_c
/opt/android/cake_wallet/scripts/monero_c
+ unxz -f ../monero_c/release/zano/armv7a-linux-androideabi_libwallet2_api_c.so.xz
+ popd
/opt/android/cake_wallet/scripts/android
Removing intermediate container 0fc6b001bb90
 ---> 387f8cbd42a5
Step 10/14 : RUN cd /opt/android/cake_wallet &&     sed -i "s|const chainflipAffiliateFee = ''|const chainflipAffiliateFee = '00000000000000000000000000000000'|" lib/.secrets.g.dart
 ---> Running in e98a29e850c0
sed: can't read lib/.secrets.g.dart: No such file or directory
The command '/bin/bash -c cd /opt/android/cake_wallet &&     sed -i "s|const chainflipAffiliateFee = ''|const chainflipAffiliateFee = '00000000000000000000000000000000'|" lib/.secrets.g.dart' returned a non-zero code: 2

I will try again tomorrow.

@sethforprivacy
Copy link
Contributor

sethforprivacy commented Feb 10, 2025

I'ved pushed an updated Dockerfile, with a revised way to build out of it.

With the new Dockerfile in the PR, you can build for Android like this:

docker build -t cake-builder:latest .
docker run -v$(pwd):$(pwd) -w $(pwd) -i --rm cake-builder:latest bash -x << EOF
pushd scripts/android
    source ./app_env.sh cakewallet
    ./app_config.sh
    ./build_monero_all.sh
    ./build_mwebd.sh --dont-install
popd
pushd android/app
    [[ -f key.jks ]] || keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass hunter1 -keypass hunter1
popd
./model_generator.sh
dart run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=hunter1 keyPassword=hunter1
dart run tool/generate_localization.dart
dart run tool/generate_new_secrets.dart
flutter build apk --release --split-per-abi
EOF

Note that I am still testing this build process myself, so might be worth waiting a bit. Just didn't want you working on the old Dockerfile for longer than necessary.

@MrCyjaneK
Copy link
Collaborator

MrCyjaneK commented Feb 10, 2025

Pardon me for any issues I make in this overly long issue comment, I am quite busy right now but I want to leave a comment that I and others can reference in future.

For the sake of argument I'll invest few minutes of my time into this issue, and I'll drop you a couple links and insights in regards to the reproducible build.

First APKs are not reproducible. They just aren't. It is simply because of the apk signature, with V1 it was quite simple, you just exclude couple of META-INF/* files, v2 and v3 live at the end of zip's cdr, but still - not a single person in this thread attempted to strip the signature. Doing so is explained nicely by fdroid

Now that we know that simple sha256sum build/*.apk won't do let's dig a bit deeper....

What is a reproducible build? Part one

This one is easy. It's a build that you can reproduce locally. Actually. No. Let's start from the beginning:

What is a non-reproducible build?

Essentially this.

           Source Code
               │
               ▼
    ┌─────────────────────────┐
    │ Non-Deterministic Build │
    │    (Uncontrolled env)   │
    └─────────────────────────┘
        ╱         │         ╲
       ╱          │          ╲
      ▼           ▼           ▼
  Binary A    Binary B    Binary C

We have an input that is open source, it lives entirely under this repository, and we have different outputs when we build it. Why? For the most part because of metadata. Let's take a look at monero_c,

I know that it will diff from the outcome of your build, so let's skip straight to the differences.

$ wget https://github.com/MrCyjaneK/monero_c/releases/download/v0.18.3.4-RC10/wownero_aarch64-linux-gnu_libwallet2_api_c.so.xz -O - | unxz > monero_libwallet2_api_c.so
$ strings monero_libwallet2_api_c.so | grep /__w
<around 759 entries like this one>
/__w/monero_c/monero_c/wownero/src/wallet/wallet2.cpp:16168

Okay, for those who don't know, GitHub Actions mount docker containers in a directory called /__w, so this build was clearly built on GitHub Actions, and if I build it locally it will differ because on my Mac monero_c lives in /Users/user/work/monero_c/... But why is there local path in those files? Well if program crashes you get a stack trace that looks more like this:

FATAL SIGNAL 11 (SIGSEGV), CODE 1, FAULT ADDR 0x00000000
    pid: 12345, tid: 12346, name: com.example.app  >>> com.example.app <<<
    
    backtrace:
      #00 pc 0001a5c4  /data/app/com.example.app/lib/arm/libexample.so (ExampleClass::crashFunction()+20)
      #01 pc 0001b234  /data/app/com.example.app/lib/arm/libexample.so (ExampleClass::someOtherFunction()+56)
      #02 pc 0000f9d8  /data/app/com.example.app/lib/arm/libexample.so (mainLoop()+112)
      #03 pc 0002c3f4  /data/app/com.example.app/lib/arm/libexample.so (AppMain()+84)
      #04 pc 0005d654  /system/lib/libc.so (__libc_init+44)
      #05 pc 0000eabc  /data/app/com.example.app/lib/arm/libexample.so (_start+12)

instead of this:

FATAL SIGNAL 11 (SIGSEGV), CODE 1, FAULT ADDR 0x00000000
    pid: 67890, tid: 67891, name: com.example.app  >>> com.example.app <<<
    
    backtrace:
      #00 pc 0001a5c4  /data/app/com.example.app/lib/arm/libexample.so (offset 0x10000)
      #01 pc 0001b234  /data/app/com.example.app/lib/arm/libexample.so (offset 0x10000)
      #02 pc 0000f9d8  /data/app/com.example.app/lib/arm/libexample.so (offset 0x10000)
      #03 pc 0002c3f4  /data/app/com.example.app/lib/arm/libexample.so (offset 0x10000)
      #04 pc 0005d654  /system/lib/libc.so (__libc_init+44)
      #05 pc 0000eabc  /data/app/com.example.app/lib/arm/libexample.so (offset 0x10000)

(AI generated crash, no software was harmed during writing of this comment). Sure, we can derive where the crash is happening but it is convenient for us to just Ctrl(or ⌘ for apple users) + mouse click in terminal to open the crashing file+line.
But users don't need that, the app doesn't crash (or at least shouldn't) in production so the slight inconvenience of having to just grab and lookup an offset is fine. Right? Yes. If anybody in this thread would care a slightest about the actual reproducibility of the app you would instantly notice that libmonero_libwallet2_api_c.so from inside .apk differs from the one in scripts/monero_c/release. Why is that? Android strips debug symbols by default to reduce app size. Smart, still there is plenty of other things such as the actual contents of the binaries. While monero's contrib/depends system does great job at making it somewhat reproducible I have never verified that these builds are actually reproducible, but that's a great start. Since they contain all dependencies then you verify them bit by bit, and in the end when the code is built it will get linked together to something that is reproducible. Yay!

Okay, this was the easy part. It is possible to build monero reproducibly (it's just monero_c that doesn't really prioritize that), we also learned that the environment in which software is being built, and that environment affects build outcome. That's why monero is moving towards the use of Guix in order to achieve reproducible builds (previously Monero used gitian).

What is a reproducible build? Part two

           Source Code
               │
               ▼
  ┌─────────────────────────┐
  │   Deterministic Build   │
  │    (Controlled env)     │
  └─────────────────────────┘
        ╱                 ╲
       ╱                   ╲
      ▼                     ▼
  Binary X             Binary X

In this case no matter how many times and on what machine you rebuild the software you will end up with the same output binary.

This is what everyone in here tries to achieve. I think. Everyone in here is using Docker to achieve reproducible builds, some even relying on 3rd party images to reduce the lines of Dockerfile you have to write.

In most of the attempts you didn't even specify the source code hash, which... Do I really need to? Yes? Okay, running a build once and then again later, after changes were made to the source code will result in different output binary... obviously. So first of all - pin the hash of source code. Then you can start to consider working on a reproducible build.

I lied. What is a bootstrapable build?

Okay. So having said all that, let's try to make a reproducible toolchain that will output reproducible cake wallet .apk.

I have decided to use Go since I miss writing Go code it is the same language that powers Moby - Docker's engine.

package main

import (
	"embed"
	"io"
	"log"
	"os"
	"path/filepath"
)

//go:embed Cake_Wallet_v4.23.0_246.apk
var embeddedFile embed.FS

func main() {
	log.Println("Starting extraction...")
	targetDir := "build"
	targetFile := filepath.Join(targetDir, "Cake_Wallet_v4.23.0_246.apk")

	if err := os.MkdirAll(targetDir, 0755); err != nil {
		log.Fatalf("Failed to create directory %s: %v", targetDir, err)
	}
	log.Println("Created build directory")

	inputFile, err := embeddedFile.Open("Cake_Wallet_v4.23.0_246.apk")
	if err != nil {
		log.Fatalf("Failed to open embedded file: %v", err)
	}
	defer inputFile.Close()
	log.Println("Opened embedded APK")

	outputFile, err := os.Create(targetFile)
	if err != nil {
		log.Fatalf("Failed to create output file: %v", err)
	}
	defer outputFile.Close()
	log.Println("Created output file")

    if _, err := io.Copy(outputFile, inputFile); err != nil {
		log.Fatalf("Failed to write file: %v", err)
	}
	log.Println("Extraction complete: ", targetFile)
}

It takes less than a second to reproducibly produce current release of cake wallet.

$ time ./cake_builder 
2025/02/10 31:75:07 Starting extraction...
2025/02/10 31:75:07 Created build directory
2025/02/10 31:75:07 Opened embedded APK
2025/02/10 31:75:07 Created output file
2025/02/10 31:75:07 Extraction complete:  build/Cake_Wallet_v4.23.0_246.apk
./cake_builder  0.01s user 0.06s system 90% cpu 0.085 total

The apk will be exactly the same no matter where you run the code. Obviously. There is actually a shorter version of that command. You can just $ wget https://github.com/cake-tech/cake_wallet/releases/download/v4.23.0/Cake_Wallet_v4.23.0_246.apk

As a bonus point this method required ~300MiB of space, since I see that in the table above running flutter precache is so bad because it "increases image size." (it's not like the image is ~20GiB in size already, 500 MiB here or there doesn't really matter. Oh btw windows docker image is over 40GiB).

Okay, this joke is too long and not funny. But I had to make a point. All of you would agree that this is not really a favorable way of getting reproducible .apk right? Despite the fact that it will always output the same .apk file you probably don't feel confident.

I got slightly triggered by:

✅ Our earlier version is cleaner and simpler. [By using someone's installed flutter instead of installing one ourselves]

No. That's not the point. That's opposite of the point.

But back on track.

              Source Code
                  │
                  ▼
   ┌─────────────────────────────┐
   │ Trusted Bootstrap Binary    │
   │  (Deterministic starting    │ <--- the go code I made
   │       point/seed)           │
   └─────────────────────────────┘
                  │
                  ▼
   ┌─────────────────────────────┐
   │ Deterministic Build Process │
   └─────────────────────────────┘
                  │
                  ▼
        Reproducible Binary

The trusted binary acts as the secure, central seed that bootstraps the entire build.

Would you call the Go code I made trusted? No. At least you shouldn't; if you do, then... seek help.

So what is a Trusted Bootstrap Binary? For our case it is the enormous 20GiB+ Dockerfile with all dependencies, including things such as:

  • Unpinned docker image
  • Unpinned apt packages
  • Pinned android sdk cmdline tools
  • Pinned android ndk
  • Unpinned (or pinned? I don't remember) rust toolchain
  • Unpinned gomobile installer
  • etc...

Now without looking it up, can you name a single proprietary component in that list? No? It's cmdline-tools. But I'm getting sidetracked again. If you want your build to result in a reproducible .apk you need to:

  • obtain the source reproducibly
  • build all dependencies reproducibly
  • build the toolchain reproducibly (all the dependencies of the build process)

There is a fun story that you may want to take a look at:
https://www.quora.com/What-is-a-coders-worst-nightmare/answer/Mick-Stute
or https://bootstrappable.org/ for more resources.

The point I'm trying to make here is: as long as there is any binary code that is not trusted the output cannot be trusted.

Final thoughts

I wrote this post not as someone who is employed by Cake but by someone who doesn't like AI generated content and bounties (and this discussion appears to be both at the same time). If you want cake wallet to be reproducible, please start with dependencies. I welcome you to start your journey with making sure that monero_c is reproducible, as it is a project that is used by Cake Wallet, and is currently not reproducible - so you need to do it anyway in order to achieve reproducible Cake Wallet builds. And it may be relatively easy because the biggest dependency (monero, wownero and zano) have reproducible builds available.

I would personally use Guix or Nix to achieve it, but I'll leave that up to you.

I and everyone else would love to see reproducible cake wallet, but it is not an easy task. It's much more than going to this repo and creating a Dockerfile that builds the apk, and as far as you can probably tell there are a couple of open PR that need merging, some issues that need fixing and making builds fully reproducible is not our highest priority.

That being said we are making small steps to achieve it.

@Justxd22
Copy link
Contributor

Adding to what MrCyjaneK said, we should start using pre-built bins from https://github.com/MrCyjaneK/monero_c for the sake of keeping things simple and start verifying if these bins are reproducible first, get hashes, Then we can continue the build process

@MrCyjaneK
Copy link
Collaborator

@Justxd22: Adding to what MrCyjaneK said, we should start using pre-built bins from https://github.com/MrCyjaneK/monero_c for the sake of keeping things simple and start verifying if these bins are reproducible first, get hashes, Then we can continue the build process

@Justxd22 Whatever you guys prefer, however it makes little to no sense to verify hashes if you know they are not going to match.

However to encourage you to do that properly, there is a bounty on making reproducible builds of monero_c MrCyjaneK/monero_c#113

@Giszmo
Copy link

Giszmo commented Feb 10, 2025

@MrCyjaneK yes, we could do better but we don't use the hashes of APKs for reproducibility testing neither. We document the hashes of signed APKs to recognize them when we see them again.

Instead of reproducing an APK with zeroed signature, we currently treat the APK as a zip file, trust that zip works in converting folder to file and back and compare the content of signed APKs with the content of built APKs. Higher signature schemes conveniently do not show up when unzipping but you are right it's not perfect to just ignore what we don't see. We are open for suggestions on how to improve that but I sort of trust the engineers at Google to not run binaries outside the Manifest so apart from some serious bugs it's a valid approach.

Furthermore your "build script" that only takes the built apk and calls it a build is a concern but at WalletScrutiny our stance is that this might happen with any binary blob well hidden in the build process. We merely attest to reproducibility and consider the detection of backdoors in plain sight or binary blobs a responsibility of code reviewers. Whenever we detect binary dependencies especially under the control of the wallet provider or other crypto adjacent libraries we require these to be reproducible, too. In Cake's case the Monero binary for example.

If we fail with our approach to reproduce products, we consider it a red flag. If we manage to reproduce then we consider the project worthy of code reviews as surely absent of reproducibility, findings during a code review might not relate to what people run on their devices.

@sethforprivacy
Copy link
Contributor

Hey guys, as we've resolved the build issues that this original issue is related to, do you mind if we close out this issue? Would be best to move the discussion either into the forum post below, or into a new issue that could be more centered on reproducibility if possible.

https://forum.cakewallet.com/t/wallet-scrutiny-review-process/59/4

@xrviv
Copy link

xrviv commented Feb 11, 2025

Pardon me for any issues I make in this overly long issue comment, I am quite busy right now but I want to leave a comment that I and others can reference in future.

For the sake of argument I'll invest few minutes of my time into this issue, and I'll drop you a couple links and insights in regards to the reproducible build.
...

I thank you for the time spent crafting this response and I am glad for the opportunity to learn something new.

  • My key takeaway from this is: apks cannot be reproducible. and dependencies have to be built from source.

If I got that correctly, well, yes. After doing this for so many apps, we do actually notice the differences. Strict reproducibility is not possible that's why the endeavor is to show which files in a build do differ.

In that light, we are coming up with a list of acceptable diffs as we accumulate experience across different projects:

We would like to invite you for your valuable input on the matter.

I first noticed these file exclusions on bitkey, then later on bitbanana, and then finally nunchuk.

@sethforprivacy
Copy link
Contributor

It seems like we are in agreement to move this conversation to the forum or a new issue, so I'll let y'all choose which of those you'd like.

@xrviv
Copy link

xrviv commented Feb 11, 2025

New issue it is!

MrCyjaneK added a commit that referenced this issue Feb 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement New feature or request
Projects
None yet