Merge remote-tracking branch 'origin/main' into electrum-sp-refactors

This commit is contained in:
Rafael Saes 2025-04-03 16:30:51 -03:00
commit 37aaa92235
207 changed files with 1862 additions and 1232 deletions

View file

@ -12,7 +12,7 @@ on:
jobs: jobs:
Automated_integration_test: Automated_integration_test:
runs-on: ubuntu-20.04 runs-on: ubuntu-24.04
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:

View file

@ -4,14 +4,14 @@ on: [pull_request]
jobs: jobs:
PR_test_build: PR_test_build:
runs-on: ubuntu-20.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Check for print() statements in dart code (use printV() instead) - name: Check for print() statements in dart code (use printV() instead)
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'
run: | run: |
GIT_GREP_OUT="$(git grep ' print(' | (grep .dart: || test $? = 1) | (grep -v print_verbose.dart || test $? = 1) || true)" GIT_GREP_OUT="$(git grep ' print(' | (grep .dart: || test $? = 1) | (grep -v print_verbose.dart || test $? = 1) | (grep -v print_verbose_dummy.dart || test $? = 1) || true)"
[[ "x$GIT_GREP_OUT" == "x" ]] && exit 0 [[ "x$GIT_GREP_OUT" == "x" ]] && exit 0
echo "$GIT_GREP_OUT" echo "$GIT_GREP_OUT"
echo "There are .dart files which use print() statements" echo "There are .dart files which use print() statements"

View file

@ -4,7 +4,7 @@ on: [pull_request]
jobs: jobs:
check_restricted_imports: check_restricted_imports:
runs-on: ubuntu-20.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4

View file

@ -9,7 +9,7 @@ jobs:
PR_test_build: PR_test_build:
runs-on: linux-amd64 runs-on: linux-amd64
container: container:
image: ghcr.io/cake-tech/cake_wallet:3.27.4-linux image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1
env: env:
STORE_PASS: test@cake_wallet STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet KEY_PASS: test@cake_wallet
@ -274,7 +274,7 @@ jobs:
- name: Build - name: Build
run: | run: |
flutter build apk --release --split-per-abi flutter build apk --dart-define=hasDevOptions=true --release --split-per-abi
- name: Rename apk file - name: Rename apk file
run: | run: |

View file

@ -9,7 +9,7 @@ jobs:
PR_test_build: PR_test_build:
runs-on: linux-amd64 runs-on: linux-amd64
container: container:
image: ghcr.io/cake-tech/cake_wallet:3.27.4-linux image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1
env: env:
STORE_PASS: test@cake_wallet STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet KEY_PASS: test@cake_wallet
@ -22,9 +22,6 @@ jobs:
- /opt/cw_cache_linux/root/.pub-cache/:/root/.pub-cache - /opt/cw_cache_linux/root/.pub-cache/:/root/.pub-cache
- /opt/cw_cache_linux/root/go/pkg:/root/go/pkg - /opt/cw_cache_linux/root/go/pkg:/root/go/pkg
- /opt/cw_cache_linux/opt/generic_cache:/opt/generic_cache - /opt/cw_cache_linux/opt/generic_cache:/opt/generic_cache
strategy:
matrix:
api-level: [29]
steps: steps:
- name: Fix github actions messing up $HOME... - name: Fix github actions messing up $HOME...
@ -228,7 +225,7 @@ jobs:
- name: Build linux - name: Build linux
run: | run: |
flutter build linux --release flutter build linux --dart-define=hasDevOptions=true --release
- name: Compress release - name: Compress release
run: | run: |

23
.gitignore vendored
View file

@ -187,3 +187,26 @@ ios/MoneroWallet.framework/MoneroWallet
ios/WowneroWallet.framework/WowneroWallet ios/WowneroWallet.framework/WowneroWallet
ios/ZanoWallet.framework/ZanoWallet ios/ZanoWallet.framework/ZanoWallet
*_libwallet2_api_c.dylib *_libwallet2_api_c.dylib
.flatpak-builder
cake_wallet.flatpak
flatpak-build/
# macOS
**/Flutter/ephemeral/
**/Pods/
**/macos/Flutter/GeneratedPluginRegistrant.swift
**/macos/Flutter/ephemeral
**/xcuserdata/
# Windows
**/windows/flutter/ephemeral/
**/windows/flutter/generated_plugin_registrant.cc
**/windows/flutter/generated_plugin_registrant.h
**/windows/flutter/generated_plugins.cmake
# Linux
**/linux/flutter/ephemeral/
**/linux/flutter/generated_plugin_registrant.cc
**/linux/flutter/generated_plugin_registrant.h
**/linux/flutter/generated_plugins.cmake

View file

@ -1,5 +1,4 @@
# docker build . -f Dockerfile -t ghcr.io/cake-tech/cake_wallet:3.27.4-linux # docker buildx build --push --pull --platform linux/amd64,linux/arm64 . -f Dockerfile -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1
# docker push ghcr.io/cake-tech/cake_wallet:3.27.4-linux
# Heavily inspired by cirrusci images # Heavily inspired by cirrusci images
# https://github.com/cirruslabs/docker-images-android/blob/master/sdk/tools/Dockerfile # https://github.com/cirruslabs/docker-images-android/blob/master/sdk/tools/Dockerfile
@ -7,13 +6,13 @@
# https://github.com/cirruslabs/docker-images-android/blob/master/sdk/34-ndk/Dockerfile # https://github.com/cirruslabs/docker-images-android/blob/master/sdk/34-ndk/Dockerfile
# https://github.com/cirruslabs/docker-images-flutter/blob/master/sdk/Dockerfile # https://github.com/cirruslabs/docker-images-flutter/blob/master/sdk/Dockerfile
FROM --platform=linux/amd64 docker.io/debian:12 FROM docker.io/debian:12
LABEL org.opencontainers.image.source=https://github.com/cake-tech/cake_wallet LABEL org.opencontainers.image.source=https://github.com/cake-tech/cake_wallet
# Set necessary environment variables # Set necessary environment variables
# Set Go version to latest known-working version # Set Go version to latest known-working version
ENV GOLANG_VERSION=1.23.4 ENV GOLANG_VERSION=1.24.1
# Pin Flutter version to latest known-working version # Pin Flutter version to latest known-working version
ENV FLUTTER_VERSION=3.27.4 ENV FLUTTER_VERSION=3.27.4
@ -60,11 +59,20 @@ RUN set -o xtrace \
ffmpeg network-manager x11-utils xvfb psmisc \ ffmpeg network-manager x11-utils xvfb psmisc \
# aarch64-linux-gnu dependencies # aarch64-linux-gnu dependencies
g++-aarch64-linux-gnu gcc-aarch64-linux-gnu \ g++-aarch64-linux-gnu gcc-aarch64-linux-gnu \
# x86_64-linux-gnu dependencies
g++-x86-64-linux-gnu gcc-x86-64-linux-gnu \
# flatpak dependencies
flatpak flatpak-builder binutils elfutils patch unzip xz-utils zstd \
&& apt clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \ && apt clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
&& sh -c 'echo "en_US.UTF-8 UTF-8" > /etc/locale.gen' \ && sh -c 'echo "en_US.UTF-8 UTF-8" > /etc/locale.gen' \
&& locale-gen \ && locale-gen \
&& update-locale LANG=en_US.UTF-8 && update-locale LANG=en_US.UTF-8
ENV FLATPAK_RUNTIME_VERSION=24.08
RUN flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo \
&& flatpak install -y flathub org.freedesktop.Platform//${FLATPAK_RUNTIME_VERSION} \
&& flatpak install -y flathub org.freedesktop.Sdk//${FLATPAK_RUNTIME_VERSION}
# Install nodejs for Github Actions # Install nodejs for Github Actions
RUN curl -fsSL https://deb.nodesource.com/setup_23.x | bash - && \ RUN curl -fsSL https://deb.nodesource.com/setup_23.x | bash - && \
apt-get install -y --no-install-recommends nodejs && \ apt-get install -y --no-install-recommends nodejs && \
@ -74,14 +82,28 @@ RUN curl -fsSL https://deb.nodesource.com/setup_23.x | bash - && \
ENV PATH=${PATH}:/usr/local/go/bin:${HOME}/go/bin ENV PATH=${PATH}:/usr/local/go/bin:${HOME}/go/bin
ENV GOROOT=/usr/local/go ENV GOROOT=/usr/local/go
ENV GOPATH=${HOME}/go ENV GOPATH=${HOME}/go
RUN wget https://go.dev/dl/go${GOLANG_VERSION}.linux-amd64.tar.gz &&\ RUN ARCH=$(uname -m) && \
rm -rf /usr/local/go &&\ if [ "$ARCH" = "x86_64" ]; then \
tar -C /usr/local -xzf go${GOLANG_VERSION}.linux-amd64.tar.gz && \ wget https://go.dev/dl/go${GOLANG_VERSION}.linux-amd64.tar.gz -O go.tar.gz; \
elif [ "$ARCH" = "aarch64" ]; then \
wget https://go.dev/dl/go${GOLANG_VERSION}.linux-arm64.tar.gz -O go.tar.gz; \
else \
echo "Unsupported architecture: $ARCH"; exit 1; \
fi && \
rm -rf /usr/local/go && \
tar -C /usr/local -xzf go.tar.gz && \
rm go.tar.gz && \
go install golang.org/x/mobile/cmd/gomobile@latest && \ go install golang.org/x/mobile/cmd/gomobile@latest && \
gomobile init gomobile init
RUN git config --global user.email "czarek@cakewallet.com" \
&& git config --global user.name "CakeWallet CI"
# Install Android SDK commandline tools and emulator # Install Android SDK commandline tools and emulator
RUN wget -q https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_TOOLS_VERSION}_latest.zip -O android-sdk-tools.zip \ RUN ARCH=$(uname -m) && \
if [ "$ARCH" != "x86_64" ]; then exit 0; fi \
&& wget -q https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_TOOLS_VERSION}_latest.zip -O android-sdk-tools.zip \
&& mkdir -p ${ANDROID_HOME}/cmdline-tools/ \ && mkdir -p ${ANDROID_HOME}/cmdline-tools/ \
&& unzip -q android-sdk-tools.zip -d ${ANDROID_HOME}/cmdline-tools/ \ && unzip -q android-sdk-tools.zip -d ${ANDROID_HOME}/cmdline-tools/ \
&& mv ${ANDROID_HOME}/cmdline-tools/cmdline-tools ${ANDROID_HOME}/cmdline-tools/latest \ && mv ${ANDROID_HOME}/cmdline-tools/cmdline-tools ${ANDROID_HOME}/cmdline-tools/latest \
@ -94,14 +116,17 @@ RUN wget -q https://dl.google.com/android/repository/commandlinetools-linux-${AN
&& sdkmanager platform-tools \ && sdkmanager platform-tools \
&& mkdir -p ${HOME}/.android \ && mkdir -p ${HOME}/.android \
&& touch ${HOME}/.android/repositories.cfg \ && touch ${HOME}/.android/repositories.cfg \
&& git config --global user.email "czarek@cakewallet.com" \
&& git config --global user.name "CakeWallet CI"
# Handle emulator not being available on linux/arm64 (https://issuetracker.google.com/issues/227219818) # Handle emulator not being available on linux/arm64 (https://issuetracker.google.com/issues/227219818)
RUN if [ $(uname -m) == "x86_64" ]; then sdkmanager emulator ; fi RUN ARCH=$(uname -m) && \
if [ "$ARCH" != "x86_64" ]; then exit 0; fi \
&& sdkmanager emulator
# Pre-install extra Android SDK dependencies in order to not have to download them for each build # Pre-install extra Android SDK dependencies in order to not have to download them for each build
RUN yes | sdkmanager \ RUN ARCH=$(uname -m) && \
if [ "$ARCH" != "x86_64" ]; then exit 0; fi \
&& yes | sdkmanager \
"platforms;android-$ANDROID_PLATFORM_VERSION" \ "platforms;android-$ANDROID_PLATFORM_VERSION" \
"build-tools;$ANDROID_BUILD_TOOLS_VERSION" \ "build-tools;$ANDROID_BUILD_TOOLS_VERSION" \
"platforms;android-33" \ "platforms;android-33" \
@ -114,12 +139,16 @@ RUN yes | sdkmanager \
# Install extra NDK dependency for sp_scanner # Install extra NDK dependency for sp_scanner
ENV ANDROID_NDK_VERSION=27.2.12479018 ENV ANDROID_NDK_VERSION=27.2.12479018
RUN yes | sdkmanager "ndk;$ANDROID_NDK_VERSION" \ RUN ARCH=$(uname -m) && \
if [ "$ARCH" != "x86_64" ]; then exit 0; fi \
&& yes | sdkmanager "ndk;$ANDROID_NDK_VERSION" \
"ndk;27.0.12077973" "ndk;27.0.12077973"
# Install dependencies for tests # Install dependencies for tests
# Comes from https://github.com/ReactiveCircus/android-emulator-runner # Comes from https://github.com/ReactiveCircus/android-emulator-runner
RUN yes | sdkmanager \ RUN ARCH=$(uname -m) && \
if [ "$ARCH" != "x86_64" ]; then exit 0; fi \
&& yes | sdkmanager \
"system-images;android-29;default;x86_64" \ "system-images;android-29;default;x86_64" \
"system-images;android-31;default;x86_64" \ "system-images;android-31;default;x86_64" \
"platforms;android-29" \ "platforms;android-29" \
@ -135,7 +164,7 @@ RUN (addgroup kvm || true) && \
ENV PATH=${HOME}/.cargo/bin:${PATH} ENV PATH=${HOME}/.cargo/bin:${PATH}
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \
cargo install cargo-ndk && \ cargo install cargo-ndk && \
for target in aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android x86_64-unknown-linux-gnu; \ for target in aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu aarch64-unknown-linux-gnu; \
do \ do \
rustup target add --toolchain stable $target; \ rustup target add --toolchain stable $target; \
done done

View file

@ -13,7 +13,7 @@
}, },
{ {
"question" : "Co oznaczają słowa „seed” i „keys”?", "question" : "Co oznaczają słowa „seed” i „keys”?",
"answer" : "Twoje klucze kodują prywatne informacje w twoim portfelu i pozwalają wydać monety i zobaczyć przychodzące transakcje.\nTwoje ziarno to tylko wersja twojego klucza prywatnego napisana w sposób, który łatwiej Ci zapisać. Wasze nasiona i klucze są w rzeczywistości takie same, tylko w różnych formach!\nNigdy nie dawaj nikomu swojego ziarna ani kluczy. Twoje fundusze zostaną skradzione, jeśli wydasz swoje nasiona lub klucze. Zapisz jednak swoje ziarno i przechowuj je w bezpiecznym miejscu (pozwoli to przywrócić portfel, jeśli zgubisz telefon).\n" "answer" : "Twoje klucze i fraza seed zawierają prywatne informacje o twoim portfelu i pozwalają wysyłać kryptowalutę oraz zobaczyć przychodzące transakcje.\nFraza „seed” to wersja twojego klucza prywatnego napisana w sposób, który łatwiej Ci zapisać. Wasze frazy seed i klucze są w rzeczywistości takie same, tylko w różnych formach zapisu!\nNigdy nie dawaj nikomu swojej frazy seed ani swoich kluczy. Twoje fundusze zostaną skradzione, jeśli upublicznisz frazę seed lub klucze. Zapisz jednak swoją frazę seed i przechowuj ją w bezpiecznym miejscu (pozwoli to przywrócić portfel, jeśli zgubisz telefon).\n"
}, },
{ {
"question" : "Ile portfeli mogę utworzyć?", "question" : "Ile portfeli mogę utworzyć?",
@ -24,11 +24,11 @@
"answer" : "Stuknij menu •••, wybierz „Portfele”, a następnie „Przywróć portfel”. Następnie wprowadź dane początkowe (lub klucze) i opcjonalnie wprowadź datę przed pierwszą transakcją w portfelu (przyspieszy to proces synchronizacji .) Może być konieczne pozostawienie aplikacji otwartej przez 15-30 minut, aby całkowicie przywrócić portfel.\n" "answer" : "Stuknij menu •••, wybierz „Portfele”, a następnie „Przywróć portfel”. Następnie wprowadź dane początkowe (lub klucze) i opcjonalnie wprowadź datę przed pierwszą transakcją w portfelu (przyspieszy to proces synchronizacji .) Może być konieczne pozostawienie aplikacji otwartej przez 15-30 minut, aby całkowicie przywrócić portfel.\n"
}, },
{ {
"question" : "Co mogę zrobić, jeśli stracę nasiona?", "question" : "Co mogę zrobić, jeśli zapomniałem frazę seed?",
"answer" : "Jeśli zapomniałeś o nasieniu, prawdopodobnie gdzieś je zapisałeś. Sprawdź swoje notatki i rozejrzyj się po komputerze. Jeśli nie możesz go nigdzie znaleźć, być może utworzono kopię zapasową Cake Wallet (w takim przypadku będziesz mógł przywrócić dane z tej kopii zapasowej). Jeśli żadna z tych czynności nie działa, niestety nic nie możemy zrobić.\n" "answer" : "Jeśli zapomniałeś swoją frazę seed, prawdopodobnie gdzieś je zapisałeś. Sprawdź swoje notatki i rozejrzyj się po komputerze. Jeśli nie możesz go nigdzie znaleźć, być może utworzono kopię zapasową Cake Wallet (w takim przypadku będziesz mógł przywrócić dane z tej kopii zapasowej). Jeśli żadna z tych czynności nie działa, niestety nic nie możemy zrobić.\n"
}, },
{ {
"question" : "Czy zbierasz jakieś informacje o moim portfelu?", "question" : "Czy zbieracie jakieś informacje o moim portfelu?",
"answer" : "Portfel Cake NIE gromadzi ani nie rejestruje żadnych informacji o Twoim portfelu. Dbamy o Twoją prywatność.\n" "answer" : "Portfel Cake NIE gromadzi ani nie rejestruje żadnych informacji o Twoim portfelu. Dbamy o Twoją prywatność.\n"
}, },
{ {
@ -37,7 +37,7 @@
}, },
{ {
"question" : "Co to są „podadresy” i jak z nich korzystać?", "question" : "Co to są „podadresy” i jak z nich korzystać?",
"answer" : "Podadres jest w zasadzie unikalnym adresem, który można wygenerować w dowolnym momencie. Monety wysłane do niego nadal będą pojawiać się w głównym portfelu, ale osoba wysyłająca monety nie może podać Twojego głównego adresu. Podadresy zawsze zaczynają się od „8”.\nMożesz utworzyć nowy podadres na ekranie Odbieranie, dotykając „+” obok przycisku Podadresy. Wprowadź nazwę podadresu i dotknij „Dodaj”. Następnie dotknij nazwy podadresu, gdy chcesz go użyć!\nJeśli jesteś paranoikiem, prawdopodobnie za każdym razem, gdy otrzymasz Monero, powinieneś utworzyć nowy podadres.\n" "answer" : "Podadres jest w unikalnym adresem, który można wygenerować w dowolnym momencie. Monety wysłane do niego nadal będą pojawiać się w głównym portfelu, ale osoba wysyłająca monety nie zna Twojego głównego adresu. Podadresy zawsze zaczynają się od „8”.\nMożesz utworzyć nowy podadres na ekranie Odbieranie, dotykając „+” obok przycisku Podadresy. Wprowadź nazwę podadresu i dotknij „Dodaj”. Następnie dotknij nazwy podadresu, gdy chcesz go użyć!\nJeśli jesteś paranoikiem, prawdopodobnie za każdym razem, gdy otrzymasz Monero, powinieneś utworzyć nowy podadres.\n"
}, },
{ {
"question" : "Co to jest ID transakcji?", "question" : "Co to jest ID transakcji?",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Before After
Before After

BIN
assets/images/cakewallet_android_icon.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Before After
Before After

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_adaptive_back"/> <background android:drawable="@mipmap/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_adaptive_fore"/> <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_adaptive_mono"/> <monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
</adaptive-icon> </adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 5 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 852 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,017 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 207 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 206 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

View file

@ -1,9 +1,9 @@
- -
uri: nano.nownodes.io uri: nano.nownodes.io
useSSL: true useSSL: true
is_default: true
- -
uri: rpc.nano.to uri: rpc.nano.to
is_default: true
useSSL: true useSSL: true
- -
uri: node.nautilus.io uri: node.nautilus.io

View file

@ -1,3 +1,5 @@
UI/UX enhancements Add background sync to Monero
Stability improvements Enhance Backup files
Improve app usability and user experience
User interface enhancements
Bug fixes Bug fixes

View file

@ -1 +1,8 @@
Update for Zano's Hard fork Add background sync to Monero
Add Decred Wallet
Remove Haven Wallet
Fix and Improve Solana Wallet
Enhance Backup files
Improve app usability and user experience
User interface enhancements
Bug fixes

View file

@ -1,6 +1,6 @@
app-id: com.cakewallet.CakeWallet app-id: com.cakewallet.CakeWallet
runtime: org.freedesktop.Platform runtime: org.freedesktop.Platform
runtime-version: '22.08' runtime-version: '24.08'
sdk: org.freedesktop.Sdk sdk: org.freedesktop.Sdk
command: cake_wallet command: cake_wallet
separate-locales: false separate-locales: false
@ -15,8 +15,6 @@ finish-args:
modules: modules:
- name: cake_wallet - name: cake_wallet
buildsystem: simple buildsystem: simple
only-arches:
- x86_64
build-commands: build-commands:
- "cp -R bundle /app/cake_wallet" - "cp -R bundle /app/cake_wallet"
- "chmod +x /app/cake_wallet/cake_wallet" - "chmod +x /app/cake_wallet/cake_wallet"
@ -28,7 +26,7 @@ modules:
- "cp com.cakewallet.CakeWallet.desktop /app/share/applications" - "cp com.cakewallet.CakeWallet.desktop /app/share/applications"
sources: sources:
- type: dir - type: dir
path: build/linux/x64/release path: build/linux/current/release
- type: file - type: file
path: assets/images/cakewallet_icon_180.png path: assets/images/cakewallet_icon_180.png
- type: file - type: file

View file

@ -69,6 +69,6 @@ class ElectrumBalance extends Balance {
'unconfirmed': unconfirmed, 'unconfirmed': unconfirmed,
'frozen': frozen, 'frozen': frozen,
'secondConfirmed': secondConfirmed, 'secondConfirmed': secondConfirmed,
'secondUnconfirmed': secondUnconfirmed 'secondUnconfirmed': secondUnconfirmed,
}); });
} }

View file

@ -110,7 +110,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
CryptoCurrency.wow, CryptoCurrency.wow,
CryptoCurrency.zano, CryptoCurrency.zano,
CryptoCurrency.ton, CryptoCurrency.ton,
CryptoCurrency.flip CryptoCurrency.flip,
CryptoCurrency.deuro
]; ];
static const havenCurrencies = [ static const havenCurrencies = [
@ -231,6 +232,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
static const ton = CryptoCurrency(title: 'TON', fullName: 'Toncoin', raw: 95, name: 'ton', iconPath: 'assets/images/ton_icon.png', decimals: 8); static const ton = CryptoCurrency(title: 'TON', fullName: 'Toncoin', raw: 95, name: 'ton', iconPath: 'assets/images/ton_icon.png', decimals: 8);
static const zano = CryptoCurrency(title: 'ZANO', tag: 'ZANO', fullName: 'Zano', raw: 96, name: 'zano', iconPath: 'assets/images/zano_icon.png', decimals: 12); static const zano = CryptoCurrency(title: 'ZANO', tag: 'ZANO', fullName: 'Zano', raw: 96, name: 'zano', iconPath: 'assets/images/zano_icon.png', decimals: 12);
static const flip = CryptoCurrency(title: 'FLIP', tag: 'ETH', fullName: 'Chainflip', raw: 97, name: 'flip', iconPath: 'assets/images/flip_icon.png', decimals: 18); static const flip = CryptoCurrency(title: 'FLIP', tag: 'ETH', fullName: 'Chainflip', raw: 97, name: 'flip', iconPath: 'assets/images/flip_icon.png', decimals: 18);
static const deuro = CryptoCurrency(title: 'DEURO', tag: 'ETH', fullName: 'Digital Euro', raw: 98, name: 'deuro', iconPath: 'assets/images/deuro_icon.png', decimals: 18);
static final Map<int, CryptoCurrency> _rawCurrencyMap = static final Map<int, CryptoCurrency> _rawCurrencyMap =
[...all, ...havenCurrencies].fold<Map<int, CryptoCurrency>>(<int, CryptoCurrency>{}, (acc, item) { [...all, ...havenCurrencies].fold<Map<int, CryptoCurrency>>(<int, CryptoCurrency>{}, (acc, item) {

View file

@ -20,6 +20,8 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
final String? iconPath; final String? iconPath;
@HiveField(6) @HiveField(6)
final String? tag; final String? tag;
@HiveField(7, defaultValue: false)
final bool isPotentialScam;
bool get enabled => _enabled; bool get enabled => _enabled;
@ -33,14 +35,17 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
bool enabled = true, bool enabled = true,
this.iconPath, this.iconPath,
this.tag, this.tag,
this.isPotentialScam = false,
}) : _enabled = enabled, }) : _enabled = enabled,
super( super(
name: symbol.toLowerCase(), name: symbol.toLowerCase(),
title: symbol.toUpperCase(), title: symbol.toUpperCase(),
fullName: name, fullName: name,
tag: tag, tag: tag,
iconPath: iconPath, iconPath: iconPath,
decimals: decimal); decimals: decimal,
isPotentialScam: isPotentialScam,
);
Erc20Token.copyWith(Erc20Token other, String? icon, String? tag) Erc20Token.copyWith(Erc20Token other, String? icon, String? tag)
: this.name = other.name, : this.name = other.name,
@ -50,6 +55,7 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
this._enabled = other.enabled, this._enabled = other.enabled,
this.tag = tag, this.tag = tag,
this.iconPath = icon, this.iconPath = icon,
this.isPotentialScam = other.isPotentialScam,
super( super(
name: other.name, name: other.name,
title: other.symbol.toUpperCase(), title: other.symbol.toUpperCase(),
@ -57,6 +63,7 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
tag: tag, tag: tag,
iconPath: icon, iconPath: icon,
decimals: other.decimal, decimals: other.decimal,
isPotentialScam: other.isPotentialScam,
); );
static const typeId = ERC20_TOKEN_TYPE_ID; static const typeId = ERC20_TOKEN_TYPE_ID;

View file

@ -1,4 +1,5 @@
import 'dart:math'; import 'dart:math';
import 'package:flutter/foundation.dart';
void printV(dynamic content) { void printV(dynamic content) {
CustomTrace programInfo = CustomTrace(StackTrace.current); CustomTrace programInfo = CustomTrace(StackTrace.current);
@ -20,7 +21,7 @@ class CustomTrace {
try { try {
_parseTrace(); _parseTrace();
} catch (e) { } catch (e) {
print("Unable to parse trace (printV): $e"); if (kDebugMode) print("Unable to parse trace (printV): $e");
} }
} }
@ -80,7 +81,7 @@ class CustomTrace {
columnStr = columnStr.replaceFirst(")", ""); columnStr = columnStr.replaceFirst(")", "");
this.columnNumber = int.tryParse(columnStr); this.columnNumber = int.tryParse(columnStr);
} catch (e) { } catch (e) {
print("Unable to parse trace (printV): $e"); if (kDebugMode) print("Unable to parse trace (printV): $e");
} }
} }
} }

View file

@ -39,6 +39,8 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
ObservableMap<CryptoCurrency, BalanceType> get balance; ObservableMap<CryptoCurrency, BalanceType> get balance;
String formatCryptoAmount(String amount) => amount;
SyncStatus get syncStatus; SyncStatus get syncStatus;
set syncStatus(SyncStatus status); set syncStatus(SyncStatus status);

View file

@ -3,7 +3,6 @@ import 'dart:ffi';
import 'dart:io'; import 'dart:io';
import 'dart:async'; import 'dart:async';
import 'dart:isolate'; import 'dart:isolate';
import 'package:flutter/foundation.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_decred/api/libdcrwallet_bindings.dart'; import 'package:cw_decred/api/libdcrwallet_bindings.dart';
import 'package:cw_decred/api/util.dart'; import 'package:cw_decred/api/util.dart';
@ -79,10 +78,12 @@ class Libwallet {
switch (method) { switch (method) {
case "initlibdcrwallet": case "initlibdcrwallet":
final logDir = args["logdir"] ?? ""; final logDir = args["logdir"] ?? "";
final level = args["level"] ?? "";
final cLogDir = logDir.toCString(); final cLogDir = logDir.toCString();
final cLevel = level.toCString();
executePayloadFn( executePayloadFn(
fn: () => dcrwalletApi.initialize(cLogDir), fn: () => dcrwalletApi.initialize(cLogDir, cLevel),
ptrsToFree: [cLogDir], ptrsToFree: [cLogDir, cLevel],
); );
break; break;
case "createwallet": case "createwallet":
@ -300,7 +301,7 @@ class Libwallet {
break; break;
case "shutdown": case "shutdown":
final name = args["name"] ?? ""; final name = args["name"] ?? "";
final cName = name.toCString(); // final cName = name.toCString();
executePayloadFn( executePayloadFn(
fn: () => dcrwalletApi.shutdown(), fn: () => dcrwalletApi.shutdown(),
ptrsToFree: [], ptrsToFree: [],
@ -326,8 +327,8 @@ class Libwallet {
// initLibdcrwallet initializes libdcrwallet using the provided logDir and gets // initLibdcrwallet initializes libdcrwallet using the provided logDir and gets
// it ready for use. This must be done before attempting to create, load or use // it ready for use. This must be done before attempting to create, load or use
// a wallet. // a wallet. An empty string can be used to log to stdout and create no log files.
Future<void> initLibdcrwallet(String logDir) async { Future<void> initLibdcrwallet(String logDir, String level) async {
if (_closed) throw StateError('Closed'); if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync(); final completer = Completer<Object?>.sync();
final id = _idCounter++; final id = _idCounter++;
@ -335,6 +336,7 @@ class Libwallet {
final req = { final req = {
"method": "initlibdcrwallet", "method": "initlibdcrwallet",
"logdir": logDir, "logdir": logDir,
"level": level,
}; };
_commands.send((id, req)); _commands.send((id, req));
await completer.future; await completer.future;
@ -463,7 +465,11 @@ class Libwallet {
}; };
_commands.send((id, req)); _commands.send((id, req));
final res = await completer.future as PayloadResult; final res = await completer.future as PayloadResult;
return jsonDecode(res.payload); try {
return jsonDecode(res.payload);
} catch (_) {
return {};
}
} }
Future<String> estimateFee(String walletName, int numBlocks) async { Future<String> estimateFee(String walletName, int numBlocks) async {

View file

@ -380,7 +380,7 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance, DecredTransact
totalAmt = totalIn; totalAmt = totalIn;
} else if (out.cryptoAmount != null) { } else if (out.cryptoAmount != null) {
final coins = double.parse(out.cryptoAmount!); final coins = double.parse(out.cryptoAmount!);
amt = (coins * 1e8).toInt(); amt = (coins * 1e8).round();
} }
totalAmt += amt; totalAmt += amt;
final o = { final o = {
@ -415,7 +415,7 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance, DecredTransact
}; };
final fee = decoded["fee"] ?? 0; final fee = decoded["fee"] ?? 0;
if (sendAll) { if (sendAll) {
totalAmt = (totalAmt - fee).toInt(); totalAmt = (totalAmt - fee).round();
} }
return DecredPendingTransaction( return DecredPendingTransaction(
txid: decoded["txid"] ?? "", amount: totalAmt, fee: fee, rawHex: signedHex, send: send); txid: decoded["txid"] ?? "", amount: totalAmt, fee: fee, rawHex: signedHex, send: send);
@ -475,36 +475,41 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance, DecredTransact
} }
Future<Map<String, DecredTransactionInfo>> fetchFiveTransactions(int from) async { Future<Map<String, DecredTransactionInfo>> fetchFiveTransactions(int from) async {
final res = await _libwallet.listTransactions(walletInfo.name, from.toString(), "5"); try {
final decoded = json.decode(res); final res = await _libwallet.listTransactions(walletInfo.name, from.toString(), "5");
var txs = <String, DecredTransactionInfo>{}; final decoded = json.decode(res);
for (final d in decoded) { var txs = <String, DecredTransactionInfo>{};
final txid = uniqueTxID(d["txid"] ?? "", d["vout"] ?? 0); for (final d in decoded) {
var direction = TransactionDirection.outgoing; final txid = uniqueTxID(d["txid"] ?? "", d["vout"] ?? 0);
if (d["category"] == "receive") { var direction = TransactionDirection.outgoing;
direction = TransactionDirection.incoming; if (d["category"] == "receive") {
direction = TransactionDirection.incoming;
}
final amountDouble = d["amount"] ?? 0.0;
final amount = (amountDouble * 1e8).round().abs();
final feeDouble = d["fee"] ?? 0.0;
final fee = (feeDouble * 1e8).round().abs();
final confs = d["confirmations"] ?? 0;
final sendTime = d["time"] ?? 0;
final height = d["height"] ?? 0;
final txInfo = DecredTransactionInfo(
id: txid,
amount: amount,
fee: fee,
direction: direction,
isPending: confs == 0,
date: DateTime.fromMillisecondsSinceEpoch(sendTime * 1000, isUtc: false),
height: height,
confirmations: confs,
to: d["address"] ?? "",
);
txs[txid] = txInfo;
} }
final amountDouble = d["amount"] ?? 0.0; return txs;
final amount = (amountDouble * 1e8).toInt().abs(); } catch (e) {
final feeDouble = d["fee"] ?? 0.0; printV(e);
final fee = (feeDouble * 1e8).toInt().abs(); return {};
final confs = d["confirmations"] ?? 0;
final sendTime = d["time"] ?? 0;
final height = d["height"] ?? 0;
final txInfo = DecredTransactionInfo(
id: txid,
amount: amount,
fee: fee,
direction: direction,
isPending: confs == 0,
date: DateTime.fromMillisecondsSinceEpoch(sendTime * 1000, isUtc: false),
height: height,
confirmations: confs,
to: d["address"] ?? "",
);
txs[txid] = txInfo;
} }
return txs;
} }
// uniqueTxID combines the tx id and vout to create a unique id. // uniqueTxID combines the tx id and vout to create a unique id.
@ -612,21 +617,25 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance, DecredTransact
} }
Future<void> fetchUnspents() async { Future<void> fetchUnspents() async {
final res = await _libwallet.listUnspents(walletInfo.name); try {
final decoded = json.decode(res); final res = await _libwallet.listUnspents(walletInfo.name);
var unspents = <Unspent>[]; final decoded = json.decode(res);
for (final d in decoded) { var unspents = <Unspent>[];
final spendable = d["spendable"] ?? false; for (final d in decoded) {
if (!spendable) { final spendable = d["spendable"] ?? false;
continue; if (!spendable) {
continue;
}
final amountDouble = d["amount"] ?? 0.0;
final amount = (amountDouble * 1e8).round().abs();
final utxo = Unspent(d["address"] ?? "", d["txid"] ?? "", amount, d["vout"] ?? 0, null);
utxo.isChange = d["ischange"] ?? false;
unspents.add(utxo);
} }
final amountDouble = d["amount"] ?? 0.0; _unspents = unspents;
final amount = (amountDouble * 1e8).toInt().abs(); } catch (e) {
final utxo = Unspent(d["address"] ?? "", d["txid"] ?? "", amount, d["vout"] ?? 0, null); printV(e);
utxo.isChange = d["ischange"] ?? false;
unspents.add(utxo);
} }
_unspents = unspents;
} }
List<Unspent> unspents() { List<Unspent> unspents() {

View file

@ -1,4 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cw_core/address_info.dart'; import 'package:cw_core/address_info.dart';
@ -103,13 +104,18 @@ abstract class DecredWalletAddressesBase extends WalletAddresses with Store {
if (this.isEnabledAutoGenerateSubaddress) { if (this.isEnabledAutoGenerateSubaddress) {
nUnused = "3"; nUnused = "3";
} }
final res = await _libwallet.addresses(walletInfo.name, nUsed, nUnused); try {
final decoded = json.decode(res); final res = await _libwallet.addresses(walletInfo.name, nUsed, nUnused);
final usedAddrs = List<String>.from(decoded["used"] ?? []); final decoded = json.decode(res);
final unusedAddrs = List<String>.from(decoded["unused"] ?? []); final usedAddrs = List<String>.from(decoded["used"] ?? []);
// index is the index of the first unused address. final unusedAddrs = List<String>.from(decoded["unused"] ?? []);
final index = decoded["index"] ?? 0; // index is the index of the first unused address.
return new LibAddresses(usedAddrs, unusedAddrs, index); final index = decoded["index"] ?? 0;
return new LibAddresses(usedAddrs, unusedAddrs, index);
} catch (e) {
printV(e);
return LibAddresses([], [], 0);
}
} }
Future<void> generateNewAddress(String label) async { Future<void> generateNewAddress(String label) async {

View file

@ -27,17 +27,16 @@ class DecredWalletService extends WalletService<
static final pubkeyRestorePathTestnet = "m/44'/1'/0'"; static final pubkeyRestorePathTestnet = "m/44'/1'/0'";
final mainnet = "mainnet"; final mainnet = "mainnet";
final testnet = "testnet"; final testnet = "testnet";
Libwallet? libwallet; static Libwallet? libwallet;
Future<void> init() async { Future<void> init() async {
if (libwallet != null) { if (libwallet != null) {
return; return;
} }
libwallet = await Libwallet.spawn(); libwallet = await Libwallet.spawn();
// Use the general path for all dcr wallets as the general log directory. // Init logging with no directory to force printing to stdout and only
// Individual wallet paths may be removed if the wallet is deleted. // print ERROR level logs.
final dcrLogDir = await pathForWalletDir(name: '', type: WalletType.decred); libwallet!.initLibdcrwallet("", "err");
libwallet!.initLibdcrwallet(dcrLogDir);
} }
void closeLibwallet() { void closeLibwallet() {

View file

@ -17,6 +17,13 @@ class DefaultEthereumErc20Tokens {
decimal: 6, decimal: 6,
enabled: true, enabled: true,
), ),
Erc20Token(
name: "Digital Euro",
symbol: "DEURO",
contractAddress: "0xbA3f535bbCcCcA2A154b573Ca6c5A49BAAE0a3ea",
decimal: 18,
enabled: true,
),
Erc20Token( Erc20Token(
name: "Dai", name: "Dai",
symbol: "DAI", symbol: "DAI",

View file

@ -115,6 +115,7 @@ class EthereumWallet extends EVMChainWallet {
enabled: token.enabled, enabled: token.enabled,
tag: token.tag ?? "ETH", tag: token.tag ?? "ETH",
iconPath: iconPath, iconPath: iconPath,
isPotentialScam: token.isPotentialScam,
); );
} }

View file

@ -628,13 +628,13 @@ abstract class EVMChainWalletBase extends WalletBase<
Future<void> addErc20Token(Erc20Token token) async { Future<void> addErc20Token(Erc20Token token) async {
String? iconPath; String? iconPath;
if (token.iconPath == null || token.iconPath!.isEmpty) { if ((token.iconPath == null || token.iconPath!.isEmpty) && !token.isPotentialScam) {
try { try {
iconPath = CryptoCurrency.all iconPath = CryptoCurrency.all
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase()) .firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
.iconPath; .iconPath;
} catch (_) {} } catch (_) {}
} else { } else if (!token.isPotentialScam) {
iconPath = token.iconPath; iconPath = token.iconPath;
} }

View file

@ -1,15 +0,0 @@
//
// Generated file. Do not edit.
//
// clang-format off
#include "generated_plugin_registrant.h"
#include <cw_monero/cw_monero_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) cw_monero_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "CwMoneroPlugin");
cw_monero_plugin_register_with_registrar(cw_monero_registrar);
}

View file

@ -1,15 +0,0 @@
//
// Generated file. Do not edit.
//
// clang-format off
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
#include <flutter_linux/flutter_linux.h>
// Registers Flutter plugins.
void fl_register_plugins(FlPluginRegistry* registry);
#endif // GENERATED_PLUGIN_REGISTRANT_

View file

@ -1,24 +0,0 @@
#
# Generated file, do not edit.
#
list(APPEND FLUTTER_PLUGIN_LIST
cw_monero
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
)
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
endforeach(ffi_plugin)

View file

@ -7,7 +7,8 @@ bool get isViewOnly => int.tryParse(monero.Wallet_secretSpendKey(wptr!)) == 0;
int _wlptrForW = 0; int _wlptrForW = 0;
monero.WalletListener? _wlptr = null; monero.WalletListener? _wlptr = null;
monero.WalletListener getWlptr() { monero.WalletListener? getWlptr() {
if (wptr == null) return null;
if (wptr!.address == _wlptrForW) return _wlptr!; if (wptr!.address == _wlptrForW) return _wlptr!;
_wlptrForW = wptr!.address; _wlptrForW = wptr!.address;
_wlptr = monero.MONERO_cw_getWalletListener(wptr!); _wlptr = monero.MONERO_cw_getWalletListener(wptr!);

View file

@ -1,21 +1,42 @@
import 'dart:ffi';
import 'dart:isolate';
import 'package:cw_monero/api/account_list.dart'; import 'package:cw_monero/api/account_list.dart';
import 'package:monero/monero.dart' as monero; import 'package:monero/monero.dart' as monero;
import 'package:mutex/mutex.dart';
monero.Coins? coins = null; monero.Coins? coins = null;
final coinsMutex = Mutex();
void refreshCoins(int accountIndex) { Future<void> refreshCoins(int accountIndex) async {
if (coinsMutex.isLocked) {
return;
}
coins = monero.Wallet_coins(wptr!); coins = monero.Wallet_coins(wptr!);
monero.Coins_refresh(coins!); final coinsPtr = coins!.address;
await coinsMutex.acquire();
await Isolate.run(() => monero.Coins_refresh(Pointer.fromAddress(coinsPtr)));
coinsMutex.release();
} }
int countOfCoins() => monero.Coins_count(coins!); Future<int> countOfCoins() async {
await coinsMutex.acquire();
final count = monero.Coins_count(coins!);
coinsMutex.release();
return count;
}
monero.CoinsInfo getCoin(int index) => monero.Coins_coin(coins!, index); Future<monero.CoinsInfo> getCoin(int index) async {
await coinsMutex.acquire();
final coin = monero.Coins_coin(coins!, index);
coinsMutex.release();
return coin;
}
int? getCoinByKeyImage(String keyImage) { Future<int?> getCoinByKeyImage(String keyImage) async {
final count = countOfCoins(); final count = await countOfCoins();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
final coin = getCoin(i); final coin = await getCoin(i);
final coinAddress = monero.CoinsInfo_keyImage(coin); final coinAddress = monero.CoinsInfo_keyImage(coin);
if (keyImage == coinAddress) { if (keyImage == coinAddress) {
return i; return i;
@ -24,6 +45,16 @@ int? getCoinByKeyImage(String keyImage) {
return null; return null;
} }
void freezeCoin(int index) => monero.Coins_setFrozen(coins!, index: index); Future<void> freezeCoin(int index) async {
await coinsMutex.acquire();
final coinsPtr = coins!.address;
await Isolate.run(() => monero.Coins_setFrozen(Pointer.fromAddress(coinsPtr), index: index));
coinsMutex.release();
}
void thawCoin(int index) => monero.Coins_thaw(coins!, index: index); Future<void> thawCoin(int index) async {
await coinsMutex.acquire();
final coinsPtr = coins!.address;
await Isolate.run(() => monero.Coins_thaw(Pointer.fromAddress(coinsPtr), index: index));
coinsMutex.release();
}

View file

@ -1,6 +1,7 @@
import 'dart:ffi'; import 'dart:ffi';
import 'dart:isolate'; import 'dart:isolate';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_monero/api/account_list.dart'; import 'package:cw_monero/api/account_list.dart';
import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart'; import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart';
import 'package:cw_monero/api/monero_output.dart'; import 'package:cw_monero/api/monero_output.dart';
@ -13,15 +14,23 @@ import 'package:monero/src/generated_bindings_monero.g.dart' as monero_gen;
import 'package:mutex/mutex.dart'; import 'package:mutex/mutex.dart';
Map<int, Map<String, String>> txKeys = {};
String getTxKey(String txId) { String getTxKey(String txId) {
txKeys[wptr!.address] ??= {};
if (txKeys[wptr!.address]![txId] != null) {
return txKeys[wptr!.address]![txId]!;
}
final txKey = monero.Wallet_getTxKey(wptr!, txid: txId); final txKey = monero.Wallet_getTxKey(wptr!, txid: txId);
final status = monero.Wallet_status(wptr!); final status = monero.Wallet_status(wptr!);
if (status != 0) { if (status != 0) {
final error = monero.Wallet_errorString(wptr!); monero.Wallet_errorString(wptr!);
txKeys[wptr!.address]![txId] = "";
return ""; return "";
} }
txKeys[wptr!.address]![txId] = txKey;
return txKey; return txKey;
} }
final txHistoryMutex = Mutex(); final txHistoryMutex = Mutex();
monero.TransactionHistory? txhistory; monero.TransactionHistory? txhistory;
bool isRefreshingTx = false; bool isRefreshingTx = false;
@ -34,6 +43,7 @@ Future<void> refreshTransactions() async {
await Isolate.run(() { await Isolate.run(() {
monero.TransactionHistory_refresh(Pointer.fromAddress(ptr)); monero.TransactionHistory_refresh(Pointer.fromAddress(ptr));
}); });
await Future.delayed(Duration.zero);
txHistoryMutex.release(); txHistoryMutex.release();
isRefreshingTx = false; isRefreshingTx = false;
} }
@ -45,8 +55,24 @@ Future<List<Transaction>> getAllTransactions() async {
await txHistoryMutex.acquire(); await txHistoryMutex.acquire();
txhistory ??= monero.Wallet_history(wptr!); txhistory ??= monero.Wallet_history(wptr!);
final startAddress = txhistory!.address * wptr!.address;
int size = countOfTransactions(); int size = countOfTransactions();
final list = List.generate(size, (index) => Transaction(txInfo: monero.TransactionHistory_transaction(txhistory!, index: index))); final list = <Transaction>[];
for (int index = 0; index < size; index++) {
if (index % 25 == 0) {
// Give main thread a chance to do other things.
await Future.delayed(Duration.zero);
}
if (txhistory!.address * wptr!.address != startAddress) {
printV("Loop broken because txhistory!.address * wptr!.address != startAddress");
break;
}
final txInfo = monero.TransactionHistory_transaction(txhistory!, index: index);
final txHash = monero.TransactionInfo_hash(txInfo);
txCache[wptr!.address] ??= {};
txCache[wptr!.address]![txHash] = Transaction(txInfo: txInfo);
list.add(txCache[wptr!.address]![txHash]!);
}
txHistoryMutex.release(); txHistoryMutex.release();
final accts = monero.Wallet_numSubaddressAccounts(wptr!); final accts = monero.Wallet_numSubaddressAccounts(wptr!);
for (var i = 0; i < accts; i++) { for (var i = 0; i < accts; i++) {
@ -79,8 +105,18 @@ Future<List<Transaction>> getAllTransactions() async {
return list; return list;
} }
Transaction getTransaction(String txId) { Map<int, Map<String, Transaction>> txCache = {};
return Transaction(txInfo: monero.TransactionHistory_transactionById(txhistory!, txid: txId)); Future<Transaction> getTransaction(String txId) async {
if (txCache[wptr!.address] != null && txCache[wptr!.address]![txId] != null) {
return txCache[wptr!.address]![txId]!;
}
await txHistoryMutex.acquire();
final tx = monero.TransactionHistory_transactionById(txhistory!, txid: txId);
final txDart = Transaction(txInfo: tx);
txCache[wptr!.address] ??= {};
txCache[wptr!.address]![txId] = txDart;
txHistoryMutex.release();
return txDart;
} }
Future<PendingTransactionDescription> createTransactionSync( Future<PendingTransactionDescription> createTransactionSync(
@ -161,31 +197,39 @@ Future<PendingTransactionDescription> createTransactionSync(
); );
} }
PendingTransactionDescription createTransactionMultDestSync( Future<PendingTransactionDescription> createTransactionMultDest(
{required List<MoneroOutput> outputs, {required List<MoneroOutput> outputs,
required String paymentId, required String paymentId,
required int priorityRaw, required int priorityRaw,
int accountIndex = 0, int accountIndex = 0,
List<String> preferredInputs = const []}) { List<String> preferredInputs = const []}) async {
final dstAddrs = outputs.map((e) => e.address).toList(); final dstAddrs = outputs.map((e) => e.address).toList();
final amounts = outputs.map((e) => monero.Wallet_amountFromString(e.amount)).toList(); final amounts = outputs.map((e) => monero.Wallet_amountFromString(e.amount)).toList();
// printV("multDest: dstAddrs: $dstAddrs"); final waddr = wptr!.address;
// printV("multDest: amounts: $amounts");
// force reconnection in case the os killed the connection
Isolate.run(() async {
monero.Wallet_synchronized(Pointer.fromAddress(waddr));
});
final txptr = Pointer<Void>.fromAddress(await Isolate.run(() {
return monero.Wallet_createTransactionMultDest(
Pointer.fromAddress(waddr),
dstAddr: dstAddrs,
isSweepAll: false,
amounts: amounts,
mixinCount: 0,
pendingTransactionPriority: priorityRaw,
subaddr_account: accountIndex,
).address;
}));
final txptr = monero.Wallet_createTransactionMultDest(
wptr!,
dstAddr: dstAddrs,
isSweepAll: false,
amounts: amounts,
mixinCount: 0,
pendingTransactionPriority: priorityRaw,
subaddr_account: accountIndex,
);
if (monero.PendingTransaction_status(txptr) != 0) { if (monero.PendingTransaction_status(txptr) != 0) {
throw CreationTransactionException(message: monero.PendingTransaction_errorString(txptr)); throw CreationTransactionException(message: monero.PendingTransaction_errorString(txptr));
} }
return PendingTransactionDescription( return PendingTransactionDescription(
amount: monero.PendingTransaction_amount(txptr), amount: monero.PendingTransaction_amount(txptr),
fee: monero.PendingTransaction_fee(txptr), fee: monero.PendingTransaction_fee(txptr),
@ -255,21 +299,6 @@ Future<PendingTransactionDescription> _createTransactionSync(Map args) async {
preferredInputs: preferredInputs); preferredInputs: preferredInputs);
} }
PendingTransactionDescription _createTransactionMultDestSync(Map args) {
final outputs = args['outputs'] as List<MoneroOutput>;
final paymentId = args['paymentId'] as String;
final priorityRaw = args['priorityRaw'] as int;
final accountIndex = args['accountIndex'] as int;
final preferredInputs = args['preferredInputs'] as List<String>;
return createTransactionMultDestSync(
outputs: outputs,
paymentId: paymentId,
priorityRaw: priorityRaw,
accountIndex: accountIndex,
preferredInputs: preferredInputs);
}
Future<PendingTransactionDescription> createTransaction( Future<PendingTransactionDescription> createTransaction(
{required String address, {required String address,
required int priorityRaw, required int priorityRaw,
@ -286,21 +315,6 @@ Future<PendingTransactionDescription> createTransaction(
'preferredInputs': preferredInputs 'preferredInputs': preferredInputs
}); });
Future<PendingTransactionDescription> createTransactionMultDest(
{required List<MoneroOutput> outputs,
required int priorityRaw,
String paymentId = '',
int accountIndex = 0,
List<String> preferredInputs = const []}) async =>
_createTransactionMultDestSync({
'outputs': outputs,
'paymentId': paymentId,
'priorityRaw': priorityRaw,
'accountIndex': accountIndex,
'preferredInputs': preferredInputs
});
class Transaction { class Transaction {
final String displayLabel; final String displayLabel;
late final String subaddressLabel = monero.Wallet_getSubaddressLabel( late final String subaddressLabel = monero.Wallet_getSubaddressLabel(

View file

@ -2,10 +2,10 @@ import 'dart:async';
import 'dart:ffi'; import 'dart:ffi';
import 'dart:isolate'; import 'dart:isolate';
import 'package:cw_core/root_dir.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_monero/api/account_list.dart'; import 'package:cw_monero/api/account_list.dart';
import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart'; import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart';
import 'package:cw_monero/api/wallet_manager.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:monero/monero.dart' as monero; import 'package:monero/monero.dart' as monero;
import 'package:mutex/mutex.dart'; import 'package:mutex/mutex.dart';
@ -21,14 +21,18 @@ int getSyncingHeight() {
} }
bool isNeededToRefresh() { bool isNeededToRefresh() {
final ret = monero.MONERO_cw_WalletListener_isNeedToRefresh(getWlptr()); final wlptr = getWlptr();
monero.MONERO_cw_WalletListener_resetNeedToRefresh(getWlptr()); if (wlptr == null) return false;
final ret = monero.MONERO_cw_WalletListener_isNeedToRefresh(wlptr);
monero.MONERO_cw_WalletListener_resetNeedToRefresh(wlptr);
return ret; return ret;
} }
bool isNewTransactionExist() { bool isNewTransactionExist() {
final ret = monero.MONERO_cw_WalletListener_isNewTransactionExist(getWlptr()); final wlptr = getWlptr();
monero.MONERO_cw_WalletListener_resetIsNewTransactionExist(getWlptr()); if (wlptr == null) return false;
final ret = monero.MONERO_cw_WalletListener_isNewTransactionExist(wlptr);
monero.MONERO_cw_WalletListener_resetIsNewTransactionExist(wlptr);
return ret; return ret;
} }
@ -75,22 +79,28 @@ String? getSeedLanguage(String? language) {
String getSeedLegacy(String? language) { String getSeedLegacy(String? language) {
final cakepassphrase = getPassphrase(); final cakepassphrase = getPassphrase();
var legacy = monero.Wallet_seed(wptr!, seedOffset: cakepassphrase);
language = getSeedLanguage(language); language = getSeedLanguage(language);
var legacy = monero.Wallet_seed(wptr!, seedOffset: cakepassphrase);
if (monero.Wallet_status(wptr!) != 0) { if (monero.Wallet_status(wptr!) != 0) {
if (language != null) { if (monero.Wallet_errorString(wptr!).contains("seed_language")) {
monero.Wallet_setSeedLanguage(wptr!, language: language); monero.Wallet_setSeedLanguage(wptr!, language: "English");
final status = monero.Wallet_status(wptr!); legacy = monero.Wallet_seed(wptr!, seedOffset: cakepassphrase);
if (status != 0) { }
final err = monero.Wallet_errorString(wptr!); }
if (legacy.isNotEmpty) {
return "$err\n\n$legacy"; if (language != null) {
} monero.Wallet_setSeedLanguage(wptr!, language: language);
return err; final status = monero.Wallet_status(wptr!);
if (status != 0) {
final err = monero.Wallet_errorString(wptr!);
if (legacy.isNotEmpty) {
return "$err\n\n$legacy";
} }
return err;
} }
legacy = monero.Wallet_seed(wptr!, seedOffset: cakepassphrase); legacy = monero.Wallet_seed(wptr!, seedOffset: cakepassphrase);
} }
if (monero.Wallet_status(wptr!) != 0) { if (monero.Wallet_status(wptr!) != 0) {
final err = monero.Wallet_errorString(wptr!); final err = monero.Wallet_errorString(wptr!);
if (legacy.isNotEmpty) { if (legacy.isNotEmpty) {
@ -193,12 +203,15 @@ void startRefreshSync() {
} }
void setRefreshFromBlockHeight({required int height}) => void setRefreshFromBlockHeight({required int height}) {
monero.Wallet_setRefreshFromBlockHeight(wptr!, monero.Wallet_setRefreshFromBlockHeight(wptr!,
refresh_from_block_height: height); refresh_from_block_height: height);
}
void setRecoveringFromSeed({required bool isRecovery}) => void setRecoveringFromSeed({required bool isRecovery}) {
monero.Wallet_setRecoveringFromSeed(wptr!, recoveringFromSeed: isRecovery); monero.Wallet_setRecoveringFromSeed(wptr!, recoveringFromSeed: isRecovery);
monero.Wallet_store(wptr!);
}
final storeMutex = Mutex(); final storeMutex = Mutex();
@ -388,4 +401,6 @@ String signMessage(String message, {String address = ""}) {
bool verifyMessage(String message, String address, String signature) { bool verifyMessage(String message, String address, String signature) {
return monero.Wallet_verifySignedMessage(wptr!, message: message, address: address, signature: signature); return monero.Wallet_verifySignedMessage(wptr!, message: message, address: address, signature: signature);
} }
Map<String, List<int>> debugCallLength() => monero.debugCallLength;

View file

@ -89,11 +89,7 @@ void createWalletSync(
throw WalletCreationException(message: monero.Wallet_errorString(newWptr)); throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
} }
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: ''); setupBackgroundSync(password, newWptr);
status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
}
wptr = newWptr; wptr = newWptr;
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: passphrase); monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: passphrase);
@ -141,6 +137,7 @@ void restoreWalletFromSeedSync(
wptr = newWptr; wptr = newWptr;
setRefreshFromBlockHeight(height: restoreHeight); setRefreshFromBlockHeight(height: restoreHeight);
setupBackgroundSync(password, newWptr);
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: passphrase); monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: passphrase);
@ -186,13 +183,6 @@ void restoreWalletFromKeysSync(
message: monero.Wallet_errorString(newWptr)); message: monero.Wallet_errorString(newWptr));
} }
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
}
// CW-712 - Try to restore deterministic wallet first, if the view key doesn't // CW-712 - Try to restore deterministic wallet first, if the view key doesn't
// match the view key provided // match the view key provided
if (spendKey != "") { if (spendKey != "") {
@ -216,12 +206,8 @@ void restoreWalletFromKeysSync(
throw WalletRestoreFromKeysException( throw WalletRestoreFromKeysException(
message: monero.Wallet_errorString(newWptr)); message: monero.Wallet_errorString(newWptr));
} }
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: ''); setupBackgroundSync(password, newWptr);
status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
}
} }
} }
@ -267,12 +253,8 @@ void restoreWalletFromPolyseedWithOffset(
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed); monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: seedOffset); monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: seedOffset);
monero.Wallet_store(wptr!); monero.Wallet_store(wptr!);
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: ''); setupBackgroundSync(password, newWptr);
status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
}
storeSync(); storeSync();
openedWalletsByPath[path] = wptr!; openedWalletsByPath[path] = wptr!;
@ -323,12 +305,8 @@ void restoreWalletFromSpendKeySync(
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed); monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
storeSync(); storeSync();
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: ''); setupBackgroundSync(password, newWptr);
status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
}
openedWalletsByPath[path] = wptr!; openedWalletsByPath[path] = wptr!;
_lastOpenedWallet = path; _lastOpenedWallet = path;
@ -361,13 +339,6 @@ Future<void> restoreWalletFromHardwareWallet(
throw WalletRestoreFromSeedException(message: error); throw WalletRestoreFromSeedException(message: error);
} }
// TODO: Check with upstream if we can use background sync here
// monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
// status = monero.Wallet_status(newWptr);
// if (status != 0) {
// throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
// }
wptr = newWptr; wptr = newWptr;
_lastOpenedWallet = path; _lastOpenedWallet = path;
openedWalletsByPath[path] = wptr!; openedWalletsByPath[path] = wptr!;
@ -437,12 +408,8 @@ Future<void> loadWallet(
printV("loadWallet:"+err); printV("loadWallet:"+err);
throw WalletOpeningException(message: err); throw WalletOpeningException(message: err);
} }
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: ''); if (deviceType == 0) {
status = monero.Wallet_status(newWptr); setupBackgroundSync(password, newWptr);
if (status != 0) {
final err = monero.Wallet_errorString(newWptr);
printV("loadWallet:"+err);
throw WalletOpeningException(message: err);
} }
wptr = newWptr; wptr = newWptr;
@ -451,6 +418,17 @@ Future<void> loadWallet(
} }
} }
void setupBackgroundSync(String password, Pointer<Void>? wptrOverride) {
if (isViewOnlyBySpendKey(wptrOverride)) {
return;
}
monero.Wallet_setupBackgroundSync(wptrOverride ?? wptr!, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
if (monero.Wallet_status(wptrOverride ?? wptr!) != 0) {
// We simply ignore the error.
printV("setupBackgroundSync: ${monero.Wallet_errorString(wptrOverride ?? wptr!)}");
}
}
void _createWallet(Map<String, dynamic> args) { void _createWallet(Map<String, dynamic> args) {
final path = args['path'] as String; final path = args['path'] as String;
final password = args['password'] as String; final password = args['password'] as String;
@ -591,4 +569,4 @@ Future<void> restoreFromSpendKey(
bool isWalletExist({required String path}) => _isWalletExist(path); bool isWalletExist({required String path}) => _isWalletExist(path);
bool isViewOnlyBySpendKey() => int.tryParse(monero.Wallet_secretSpendKey(wptr!)) == 0; bool isViewOnlyBySpendKey(Pointer<Void>? wptrOverride) => int.tryParse(monero.Wallet_secretSpendKey(wptrOverride ?? wptr!)) == 0;

View file

@ -1,5 +1,6 @@
import 'package:cw_core/monero_amount_format.dart'; import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_monero/api/wallet_manager.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cw_core/account.dart'; import 'package:cw_core/account.dart';
import 'package:cw_monero/api/account_list.dart' as account_list; import 'package:cw_monero/api/account_list.dart' as account_list;
@ -44,7 +45,18 @@ abstract class MoneroAccountListBase with Store {
} }
} }
List<Account> getAll() => account_list.getAllAccount().map((accountRow) { Map<int, List<Account>> _cachedAccounts = {};
List<Account> getAll() {
final allAccounts = account_list.getAllAccount();
final currentCount = allAccounts.length;
_cachedAccounts[account_list.wptr!.address] ??= [];
if (_cachedAccounts[account_list.wptr!.address]!.length == currentCount) {
return _cachedAccounts[account_list.wptr!.address]!;
}
_cachedAccounts[account_list.wptr!.address] = allAccounts.map((accountRow) {
final balance = monero.SubaddressAccountRow_getUnlockedBalance(accountRow); final balance = monero.SubaddressAccountRow_getUnlockedBalance(accountRow);
return Account( return Account(
@ -53,6 +65,9 @@ abstract class MoneroAccountListBase with Store {
balance: moneroAmountToString(amount: monero.Wallet_amountFromString(balance)), balance: moneroAmountToString(amount: monero.Wallet_amountFromString(balance)),
); );
}).toList(); }).toList();
return _cachedAccounts[account_list.wptr!.address]!;
}
Future<void> addAccount({required String label}) async { Future<void> addAccount({required String label}) async {
await account_list.addAccount(label: label); await account_list.addAccount(label: label);

View file

@ -7,28 +7,33 @@ class MoneroUnspent extends Unspent {
MoneroUnspent( MoneroUnspent(
String address, String hash, String keyImage, int value, bool isFrozen, this.isUnlocked) String address, String hash, String keyImage, int value, bool isFrozen, this.isUnlocked)
: super(address, hash, value, 0, keyImage) { : super(address, hash, value, 0, keyImage) {
getCoinByKeyImage(keyImage).then((coinId) {
if (coinId == null) return;
getCoin(coinId).then((coin) {
_frozen = monero.CoinsInfo_frozen(coin);
});
});
} }
bool _frozen = false;
@override @override
set isFrozen(bool freeze) { set isFrozen(bool freeze) {
printV("set isFrozen: $freeze ($keyImage): $freeze"); printV("set isFrozen: $freeze ($keyImage): $freeze");
final coinId = getCoinByKeyImage(keyImage!); getCoinByKeyImage(keyImage!).then((coinId) async {
if (coinId == null) throw Exception("Unable to find a coin for address $address"); if (coinId == null) return;
if (freeze) { if (freeze) {
freezeCoin(coinId); await freezeCoin(coinId);
} else { _frozen = true;
thawCoin(coinId); } else {
} await thawCoin(coinId);
_frozen = false;
}
});
} }
@override @override
bool get isFrozen { bool get isFrozen => _frozen;
printV("get isFrozen");
final coinId = getCoinByKeyImage(keyImage!);
if (coinId == null) throw Exception("Unable to find a coin for address $address");
final coin = getCoin(coinId);
return monero.CoinsInfo_frozen(coin);
}
final bool isUnlocked; final bool isUnlocked;
} }

View file

@ -3,6 +3,7 @@ import 'dart:ffi';
import 'dart:io'; import 'dart:io';
import 'dart:isolate'; import 'dart:isolate';
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/account.dart'; import 'package:cw_core/account.dart';
@ -168,6 +169,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
if (monero_wallet.getCurrentHeight() <= 1) { if (monero_wallet.getCurrentHeight() <= 1) {
monero_wallet.setRefreshFromBlockHeight( monero_wallet.setRefreshFromBlockHeight(
height: walletInfo.restoreHeight); height: walletInfo.restoreHeight);
setupBackgroundSync(password, wptr!);
} }
} }
@ -233,18 +235,14 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
return; return;
} }
isBackgroundSyncRunning = true; isBackgroundSyncRunning = true;
int status = monero.Wallet_status(wptr!);
if (status != 0) {
final err = monero.Wallet_errorString(wptr!);
throw Exception("unable to setup background sync: $err");
}
await save(); await save();
monero.Wallet_startBackgroundSync(wptr!); monero.Wallet_startBackgroundSync(wptr!);
status = monero.Wallet_status(wptr!); final status = monero.Wallet_status(wptr!);
if (status != 0) { if (status != 0) {
final err = monero.Wallet_errorString(wptr!); final err = monero.Wallet_errorString(wptr!);
throw Exception("unable to start background sync: $err"); isBackgroundSyncRunning = false;
printV("startBackgroundSync: $err");
} }
await save(); await save();
await init(); await init();
@ -260,9 +258,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
printV("Stopping background sync"); printV("Stopping background sync");
await save(); await save();
monero.Wallet_stopBackgroundSync(wptr!, ''); monero.Wallet_stopBackgroundSync(wptr!, '');
await save();
isBackgroundSyncRunning = false; isBackgroundSyncRunning = false;
} }
await save();
} }
@action @action
@ -406,6 +404,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
outputs: moneroOutputs, outputs: moneroOutputs,
priorityRaw: _credentials.priority.serialize(), priorityRaw: _credentials.priority.serialize(),
accountIndex: walletAddresses.account!.id, accountIndex: walletAddresses.account!.id,
paymentId: "",
preferredInputs: inputs); preferredInputs: inputs);
} else { } else {
final output = outputs.first; final output = outputs.first;
@ -509,6 +508,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
final currentCacheFile = File(renamedWalletPath); final currentCacheFile = File(renamedWalletPath);
final currentKeysFile = File('$renamedWalletPath.keys'); final currentKeysFile = File('$renamedWalletPath.keys');
final currentAddressListFile = File('$renamedWalletPath.address.txt'); final currentAddressListFile = File('$renamedWalletPath.address.txt');
final backgroundSyncFile = File('$renamedWalletPath.background');
final newWalletPath = final newWalletPath =
await pathForWallet(name: newWalletName, type: type); await pathForWallet(name: newWalletName, type: type);
@ -522,6 +522,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
if (currentAddressListFile.existsSync()) { if (currentAddressListFile.existsSync()) {
await currentAddressListFile.rename('$newWalletPath.address.txt'); await currentAddressListFile.rename('$newWalletPath.address.txt');
} }
if (backgroundSyncFile.existsSync()) {
await backgroundSyncFile.rename('$newWalletPath.background');
}
await backupWalletFiles(newWalletName); await backupWalletFiles(newWalletName);
} catch (e) { } catch (e) {
@ -568,6 +571,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
walletInfo.restoreHeight = height; walletInfo.restoreHeight = height;
walletInfo.isRecovery = true; walletInfo.isRecovery = true;
monero_wallet.setRefreshFromBlockHeight(height: height); monero_wallet.setRefreshFromBlockHeight(height: height);
setupBackgroundSync(password, wptr!);
monero_wallet.rescanBlockchainAsync(); monero_wallet.rescanBlockchainAsync();
await startSync(); await startSync();
_askForUpdateBalance(); _askForUpdateBalance();
@ -583,9 +587,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
unspentCoins.clear(); unspentCoins.clear();
final coinCount = countOfCoins(); final coinCount = await countOfCoins();
for (var i = 0; i < coinCount; i++) { for (var i = 0; i < coinCount; i++) {
final coin = getCoin(i); final coin = await getCoin(i);
final coinSpent = monero.CoinsInfo_spent(coin); final coinSpent = monero.CoinsInfo_spent(coin);
if (coinSpent == false && monero.CoinsInfo_subaddrAccount(coin) == walletAddresses.account!.id) { if (coinSpent == false && monero.CoinsInfo_subaddrAccount(coin) == walletAddresses.account!.id) {
final unspent = MoneroUnspent( final unspent = MoneroUnspent(
@ -598,7 +602,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
); );
// TODO: double-check the logic here // TODO: double-check the logic here
if (unspent.hash.isNotEmpty) { if (unspent.hash.isNotEmpty) {
unspent.isChange = transaction_history.getTransaction(unspent.hash).isSpend == true; final tx = await transaction_history.getTransaction(unspent.hash);
unspent.isChange = tx.isSpend == true;
} }
unspentCoins.add(unspent); unspentCoins.add(unspent);
} }
@ -690,14 +695,15 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
@override @override
Future<Map<String, MoneroTransactionInfo>> fetchTransactions() async { Future<Map<String, MoneroTransactionInfo>> fetchTransactions() async {
transaction_history.refreshTransactions(); await transaction_history.refreshTransactions();
return (await _getAllTransactionsOfAccount(walletAddresses.account?.id)) final resp = (await _getAllTransactionsOfAccount(walletAddresses.account?.id))
.fold<Map<String, MoneroTransactionInfo>>( .fold<Map<String, MoneroTransactionInfo>>(
<String, MoneroTransactionInfo>{}, <String, MoneroTransactionInfo>{},
(Map<String, MoneroTransactionInfo> acc, MoneroTransactionInfo tx) { (Map<String, MoneroTransactionInfo> acc, MoneroTransactionInfo tx) {
acc[tx.id] = tx; acc[tx.id] = tx;
return acc; return acc;
}); });
return resp;
} }
Future<void> updateTransactions() async { Future<void> updateTransactions() async {
@ -708,8 +714,17 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
_isTransactionUpdating = true; _isTransactionUpdating = true;
final transactions = await fetchTransactions(); final transactions = await fetchTransactions();
transactionHistory.clear();
transactionHistory.addMany(transactions); final currentIds = transactionHistory.transactions.keys.toSet();
final newIds = transactions.keys.toSet();
// Remove transactions that no longer exist
currentIds.difference(newIds).forEach((id) =>
transactionHistory.transactions.remove(id));
// Add or update transactions
transactions.forEach((key, tx) =>
transactionHistory.transactions[key] = tx);
await transactionHistory.save(); await transactionHistory.save();
_isTransactionUpdating = false; _isTransactionUpdating = false;
} catch (e) { } catch (e) {
@ -776,6 +791,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
monero_wallet.setRecoveringFromSeed(isRecovery: true); monero_wallet.setRecoveringFromSeed(isRecovery: true);
monero_wallet.setRefreshFromBlockHeight(height: height); monero_wallet.setRefreshFromBlockHeight(height: height);
setupBackgroundSync(password, wptr!);
} }
int _getHeightDistance(DateTime date) { int _getHeightDistance(DateTime date) {
@ -904,4 +920,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
monero.WalletManager_openWallet(wmPtr, path: '', password: ''); monero.WalletManager_openWallet(wmPtr, path: '', password: '');
enableLedgerExchange(dummyWPtr, connection); enableLedgerExchange(dummyWPtr, connection);
} }
@override
String formatCryptoAmount(String amount) {
return moneroAmountToString(amount: int.parse(amount));
}
} }

View file

@ -75,6 +75,12 @@ class MoneroRestoreWalletFromKeysCredentials extends WalletCredentials {
final String spendKey; final String spendKey;
} }
enum OpenWalletTry {
initial,
cacheRestored,
cacheRemoved,
}
class MoneroWalletService extends WalletService< class MoneroWalletService extends WalletService<
MoneroNewWalletCredentials, MoneroNewWalletCredentials,
MoneroRestoreWalletFromSeedCredentials, MoneroRestoreWalletFromSeedCredentials,
@ -139,7 +145,7 @@ class MoneroWalletService extends WalletService<
} }
@override @override
Future<MoneroWallet> openWallet(String name, String password, {bool? retryOnFailure}) async { Future<MoneroWallet> openWallet(String name, String password, {OpenWalletTry openWalletTry = OpenWalletTry.initial}) async {
try { try {
final path = await pathForWallet(name: name, type: getType()); final path = await pathForWallet(name: name, type: getType());
@ -153,31 +159,28 @@ class MoneroWalletService extends WalletService<
walletInfo: walletInfo, walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource, unspentCoinsInfo: unspentCoinsInfoSource,
password: password); password: password);
final isValid = wallet.walletAddresses.validate();
if (wallet.isHardwareWallet) { if (wallet.isHardwareWallet) {
wallet.setLedgerConnection(gLedger!); wallet.setLedgerConnection(gLedger!);
gLedger = null; gLedger = null;
} }
if (!isValid) {
await restoreOrResetWalletFiles(name);
wallet.close(shouldCleanup: false);
return openWallet(name, password);
}
await wallet.init(); await wallet.init();
return wallet; return wallet;
} catch (e) { } catch (e) {
// TODO: Implement Exception for wallet list service. // TODO: Implement Exception for wallet list service.
if (retryOnFailure == false) { switch (openWalletTry) {
rethrow; case OpenWalletTry.initial:
await restoreOrResetWalletFiles(name);
return await openWallet(name, password, openWalletTry: OpenWalletTry.cacheRestored);
case OpenWalletTry.cacheRestored:
await removeCache(name);
return await openWallet(name, password, openWalletTry: OpenWalletTry.cacheRemoved);
case OpenWalletTry.cacheRemoved:
rethrow;
} }
await restoreOrResetWalletFiles(name);
return await openWallet(name, password, retryOnFailure: false);
} }
} }

View file

@ -1,11 +0,0 @@
//
// Generated file. Do not edit.
//
// clang-format off
#include "generated_plugin_registrant.h"
void fl_register_plugins(FlPluginRegistry* registry) {
}

View file

@ -1,15 +0,0 @@
//
// Generated file. Do not edit.
//
// clang-format off
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
#include <flutter_linux/flutter_linux.h>
// Registers Flutter plugins.
void fl_register_plugins(FlPluginRegistry* registry);
#endif // GENERATED_PLUGIN_REGISTRANT_

View file

@ -1,23 +0,0 @@
#
# Generated file, do not edit.
#
list(APPEND FLUTTER_PLUGIN_LIST
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
)
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
endforeach(ffi_plugin)

View file

@ -68,6 +68,7 @@ class PolygonWallet extends EVMChainWallet {
enabled: token.enabled, enabled: token.enabled,
tag: token.tag ?? "MATIC", tag: token.tag ?? "MATIC",
iconPath: iconPath, iconPath: iconPath,
isPotentialScam: token.isPotentialScam,
); );
} }

View file

@ -6,6 +6,7 @@ part 'spl_token.g.dart';
@HiveType(typeId: SPLToken.typeId) @HiveType(typeId: SPLToken.typeId)
class SPLToken extends CryptoCurrency with HiveObjectMixin { class SPLToken extends CryptoCurrency with HiveObjectMixin {
@override
@HiveField(0) @HiveField(0)
final String name; final String name;
@ -24,12 +25,18 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
@HiveField(5) @HiveField(5)
final String mint; final String mint;
@override
@HiveField(6) @HiveField(6)
final String? iconPath; final String? iconPath;
@override
@HiveField(7) @HiveField(7)
final String? tag; final String? tag;
@override
@HiveField(8, defaultValue: false)
final bool isPotentialScam;
SPLToken({ SPLToken({
required this.name, required this.name,
required this.symbol, required this.symbol,
@ -39,6 +46,7 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
this.iconPath, this.iconPath,
this.tag = 'SOL', this.tag = 'SOL',
bool enabled = true, bool enabled = true,
this.isPotentialScam = false,
}) : _enabled = enabled, }) : _enabled = enabled,
super( super(
name: mint.toLowerCase(), name: mint.toLowerCase(),
@ -47,6 +55,7 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
tag: tag, tag: tag,
iconPath: iconPath, iconPath: iconPath,
decimals: decimal, decimals: decimal,
isPotentialScam: isPotentialScam,
); );
factory SPLToken.fromMetadata({ factory SPLToken.fromMetadata({
@ -55,6 +64,7 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
required String symbol, required String symbol,
required String mintAddress, required String mintAddress,
String? iconPath, String? iconPath,
bool isPotentialScam = false,
}) { }) {
return SPLToken( return SPLToken(
name: name, name: name,
@ -63,28 +73,14 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
decimal: 0, decimal: 0,
mint: mint, mint: mint,
iconPath: iconPath, iconPath: iconPath,
isPotentialScam: isPotentialScam,
); );
} }
factory SPLToken.cryptoCurrency({ @override
required String name,
required String symbol,
required int decimals,
required String iconPath,
required String mint,
}) {
return SPLToken(
name: name,
symbol: symbol,
decimal: decimals,
mint: mint,
iconPath: iconPath,
mintAddress: '',
);
}
bool get enabled => _enabled; bool get enabled => _enabled;
@override
set enabled(bool value) => _enabled = value; set enabled(bool value) => _enabled = value;
SPLToken.copyWith(SPLToken other, String? icon, String? tag) SPLToken.copyWith(SPLToken other, String? icon, String? tag)
@ -96,6 +92,7 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
mint = other.mint, mint = other.mint,
tag = other.tag, tag = other.tag,
iconPath = icon, iconPath = icon,
isPotentialScam = other.isPotentialScam,
super( super(
title: other.symbol.toUpperCase(), title: other.symbol.toUpperCase(),
name: other.symbol.toLowerCase(), name: other.symbol.toLowerCase(),
@ -103,6 +100,7 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
fullName: other.name, fullName: other.name,
tag: other.tag, tag: other.tag,
iconPath: icon, iconPath: icon,
isPotentialScam: other.isPotentialScam,
); );
static const typeId = SPL_TOKEN_TYPE_ID; static const typeId = SPL_TOKEN_TYPE_ID;

View file

@ -25,10 +25,13 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
@HiveField(5) @HiveField(5)
final String? iconPath; final String? iconPath;
@HiveField(6) @HiveField(6)
final String? tag; final String? tag;
@HiveField(7, defaultValue: false)
final bool isPotentialScam;
bool get enabled => _enabled; bool get enabled => _enabled;
set enabled(bool value) => _enabled = value; set enabled(bool value) => _enabled = value;
@ -41,14 +44,17 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
bool enabled = true, bool enabled = true,
this.iconPath, this.iconPath,
this.tag = 'TRX', this.tag = 'TRX',
this.isPotentialScam = false,
}) : _enabled = enabled, }) : _enabled = enabled,
super( super(
name: symbol.toLowerCase(), name: symbol.toLowerCase(),
title: symbol.toUpperCase(), title: symbol.toUpperCase(),
fullName: name, fullName: name,
tag: tag, tag: tag,
iconPath: iconPath, iconPath: iconPath,
decimals: decimal); decimals: decimal,
isPotentialScam: isPotentialScam,
);
TronToken.copyWith(TronToken other, String? icon, String? tag) TronToken.copyWith(TronToken other, String? icon, String? tag)
: name = other.name, : name = other.name,
@ -58,6 +64,7 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
_enabled = other.enabled, _enabled = other.enabled,
tag = tag ?? other.tag, tag = tag ?? other.tag,
iconPath = icon ?? other.iconPath, iconPath = icon ?? other.iconPath,
isPotentialScam = other.isPotentialScam,
super( super(
name: other.name, name: other.name,
title: other.symbol.toUpperCase(), title: other.symbol.toUpperCase(),
@ -65,6 +72,7 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
tag: tag ?? other.tag, tag: tag ?? other.tag,
iconPath: icon ?? other.iconPath, iconPath: icon ?? other.iconPath,
decimals: other.decimal, decimals: other.decimal,
isPotentialScam: other.isPotentialScam,
); );
static const typeId = TRON_TOKEN_TYPE_ID; static const typeId = TRON_TOKEN_TYPE_ID;

View file

@ -509,11 +509,15 @@ abstract class TronWalletBase extends WalletBase<TronBalance, TronTransactionHis
Future<void> addTronToken(TronToken token) async { Future<void> addTronToken(TronToken token) async {
String? iconPath; String? iconPath;
try { if ((token.iconPath == null || token.iconPath!.isEmpty) && !token.isPotentialScam) {
iconPath = CryptoCurrency.all try {
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase()) iconPath = CryptoCurrency.all
.iconPath; .firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
} catch (_) {} .iconPath;
} catch (_) {}
} else if (!token.isPotentialScam) {
iconPath = token.iconPath;
}
final newToken = TronToken( final newToken = TronToken(
name: token.name, name: token.name,
@ -523,6 +527,7 @@ abstract class TronWalletBase extends WalletBase<TronBalance, TronTransactionHis
enabled: token.enabled, enabled: token.enabled,
tag: token.tag ?? "TRX", tag: token.tag ?? "TRX",
iconPath: iconPath, iconPath: iconPath,
isPotentialScam: token.isPotentialScam,
); );
await tronTokensBox.put(newToken.contractAddress, newToken); await tronTokensBox.put(newToken.contractAddress, newToken);

View file

@ -354,3 +354,5 @@ String signMessage(String message, {String address = ""}) {
bool verifyMessage(String message, String address, String signature) { bool verifyMessage(String message, String address, String signature) {
return wownero.Wallet_verifySignedMessage(wptr!, message: message, address: address, signature: signature); return wownero.Wallet_verifySignedMessage(wptr!, message: message, address: address, signature: signature);
} }
Map<String, List<int>> debugCallLength() => wownero.debugCallLength;

View file

@ -770,4 +770,9 @@ abstract class WowneroWalletBase extends WalletBase<WowneroBalance, WowneroTrans
return wownero_wallet.verifyMessage(message, address, signature); return wownero_wallet.verifyMessage(message, address, signature);
} }
@override
String formatCryptoAmount(String amount) {
return wowneroAmountToString(amount: int.parse(amount));
}
} }

View file

@ -508,4 +508,6 @@ Future<String> _closeWallet(int hWallet) async {
}); });
printV("Closing wallet: $str"); printV("Closing wallet: $str");
return str; return str;
} }
Map<String, List<int>> debugCallLength() => zano.debugCallLength;

View file

@ -1 +0,0 @@
extensions:

View file

@ -8,8 +8,6 @@ You can find the latest instructions for installing Docker on your given OS on t
- <https://docs.docker.com/engine/install/> - <https://docs.docker.com/engine/install/>
NOTE: If building on a Mac with an M-series CPU (arm64), you may encounter segmentation faults when building. If you do, simply retry the build.
## Building Cake Wallet or Monero.com ## Building Cake Wallet or Monero.com
### Using the pre-built builder image ### Using the pre-built builder image
@ -20,8 +18,8 @@ In order to build the latest version of Cake Wallet, simply run the following:
git clone --branch main https://github.com/cake-tech/cake_wallet.git git clone --branch main https://github.com/cake-tech/cake_wallet.git
# NOTE: Replace `main` with the latest release tag available at https://github.com/cake-tech/cake_wallet/releases/latest. # NOTE: Replace `main` with the latest release tag available at https://github.com/cake-tech/cake_wallet/releases/latest.
cd cake_wallet cd cake_wallet
# docker build -t ghcr.io/cake-tech/cake_wallet:main-linux . # Uncomment to build the docker image yourself instead of pulling it from the registry # docker build -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1 . # Uncomment to build the docker image yourself instead of pulling it from the registry
docker run -v$(pwd):$(pwd) -w $(pwd) -i --rm ghcr.io/cake-tech/cake_wallet:main-linux bash -x << EOF docker run -v$(pwd):$(pwd) -w $(pwd) -i --rm ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1 bash -x << EOF
set -x -e set -x -e
pushd scripts/android pushd scripts/android
source ./app_env.sh cakewallet source ./app_env.sh cakewallet

View file

@ -20,8 +20,8 @@ In order to build the latest version of Cake Wallet, simply run the following:
git clone --branch main https://github.com/cake-tech/cake_wallet.git git clone --branch main https://github.com/cake-tech/cake_wallet.git
# NOTE: Replace `main` with the latest release tag available at https://github.com/cake-tech/cake_wallet/releases/latest. # NOTE: Replace `main` with the latest release tag available at https://github.com/cake-tech/cake_wallet/releases/latest.
cd cake_wallet cd cake_wallet
# docker build -t ghcr.io/cake-tech/cake_wallet:main-linux . # Uncomment to build the docker image yourself instead of pulling it from the registry # docker build -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1 . # Uncomment to build the docker image yourself instead of pulling it from the registry
docker run -v$(pwd):$(pwd) -w $(pwd) -i --rm ghcr.io/cake-tech/cake_wallet:main-linux bash -x << EOF docker run --privileged -v$(pwd):$(pwd) -w $(pwd) -i --rm ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1 bash -x << EOF
set -x -e set -x -e
pushd scripts pushd scripts
./gen_android_manifest.sh ./gen_android_manifest.sh
@ -37,6 +37,13 @@ flutter clean
dart run tool/generate_localization.dart dart run tool/generate_localization.dart
dart run tool/generate_new_secrets.dart dart run tool/generate_new_secrets.dart
flutter build linux flutter build linux
cp -r build/linux/x64 build/linux/current
# use line below if you are building on arm64
# cp -r build/linux/arm64 build/linux/current
# If you want to build flatpak you need --privileged flag
flatpak-builder --force-clean flatpak-build com.cakewallet.CakeWallet.yml
flatpak build-export export flatpak-build
flatpak build-bundle export build/linux/current/cake_wallet.flatpak com.cakewallet.CakeWallet
EOF EOF
``` ```
@ -51,46 +58,11 @@ Building Linux application...
✓ Built build/linux/x64/release/bundle/cake_wallet ✓ Built build/linux/x64/release/bundle/cake_wallet
``` ```
Final builds can be found in `build/linux/x64/release/bundle/` as seen above. Final builds can be found in `build/linux/current/release/bundle/` as seen above.
## Flatpak (optional)
To package the built binaries as a flatpak, you need first to install `flatpak` and `flatpak-builder`:
```bash
sudo apt install flatpak flatpak-builder
```
Add the necessary Flathub:
```bash
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
```
Then need to install freedesktop runtime and sdk:
```bash
flatpak install flathub org.freedesktop.Platform//22.08 org.freedesktop.Sdk//22.08
```
Next, build the flatpak bundle:
```bash
flatpak-builder --force-clean flatpak-build com.cakewallet.CakeWallet.yml
```
And then export bundle:
```bash
flatpak build-export export flatpak-build
flatpak build-bundle export cake_wallet.flatpak com.cakewallet.CakeWallet
```
The Flatpak file, `cake_wallet.flatpak`, should be generated in the current directory.
To install the newly built Flatpak, run: To install the newly built Flatpak, run:
```bash ```bash
flatpak --user install cake_wallet.flatpak flatpak --user install build/linux/current/cake_wallet.flatpak
``` ```

View file

@ -2,9 +2,7 @@ PODS:
- connectivity_plus (0.0.1): - connectivity_plus (0.0.1):
- Flutter - Flutter
- ReachabilitySwift - ReachabilitySwift
- CryptoSwift (1.8.3) - CryptoSwift (1.8.4)
- cw_mweb (0.0.1):
- Flutter
- cw_decred (0.0.1): - cw_decred (0.0.1):
- Flutter - Flutter
- cw_mweb (0.0.1): - cw_mweb (0.0.1):
@ -80,9 +78,9 @@ PODS:
- permission_handler_apple (9.3.0): - permission_handler_apple (9.3.0):
- Flutter - Flutter
- ReachabilitySwift (5.2.4) - ReachabilitySwift (5.2.4)
- SDWebImage (5.19.7): - SDWebImage (5.20.0):
- SDWebImage/Core (= 5.19.7) - SDWebImage/Core (= 5.20.0)
- SDWebImage/Core (5.19.7) - SDWebImage/Core (5.20.0)
- sensitive_clipboard (0.0.1): - sensitive_clipboard (0.0.1):
- Flutter - Flutter
- share_plus (0.0.1): - share_plus (0.0.1):
@ -106,7 +104,6 @@ PODS:
DEPENDENCIES: DEPENDENCIES:
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- CryptoSwift - CryptoSwift
- cw_mweb (from `.symlinks/plugins/cw_mweb/ios`)
- cw_decred (from `.symlinks/plugins/cw_decred/ios`) - cw_decred (from `.symlinks/plugins/cw_decred/ios`)
- cw_mweb (from `.symlinks/plugins/cw_mweb/ios`) - cw_mweb (from `.symlinks/plugins/cw_mweb/ios`)
- device_display_brightness (from `.symlinks/plugins/device_display_brightness/ios`) - device_display_brightness (from `.symlinks/plugins/device_display_brightness/ios`)
@ -147,8 +144,6 @@ SPEC REPOS:
EXTERNAL SOURCES: EXTERNAL SOURCES:
connectivity_plus: connectivity_plus:
:path: ".symlinks/plugins/connectivity_plus/ios" :path: ".symlinks/plugins/connectivity_plus/ios"
cw_mweb:
:path: ".symlinks/plugins/cw_mweb/ios"
cw_decred: cw_decred:
:path: ".symlinks/plugins/cw_decred/ios" :path: ".symlinks/plugins/cw_decred/ios"
cw_mweb: cw_mweb:
@ -203,41 +198,40 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/wakelock_plus/ios" :path: ".symlinks/plugins/wakelock_plus/ios"
SPEC CHECKSUMS: SPEC CHECKSUMS:
connectivity_plus: 481668c94744c30c53b8895afb39159d1e619bdf connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d
CryptoSwift: 967f37cea5a3294d9cce358f78861652155be483 CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90
cw_decred: a02cf30175a46971c1e2fa22c48407534541edc6 cw_decred: 9c0e1df74745b51a1289ec5e91fb9e24b68fa14a
cw_mweb: 3aea2fb35b2bd04d8b2d21b83216f3b8fb768d85 cw_mweb: 22cd01dfb8ad2d39b15332006f22046aaa8352a3
device_display_brightness: 04374ebd653619292c1d996f00f42877ea19f17f device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7
device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89 device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
devicelocale: bd64aa714485a8afdaded0892c1e7d5b7f680cf8 devicelocale: 35ba84dc7f45f527c3001535d8c8d104edd5d926
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
fast_scanner: 2cb1ad3e69e645e9980fb4961396ce5804caa3e3 fast_scanner: 44c00940355a51258cd6c2085734193cd23d95bc
file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517 file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
flutter_local_authentication: 989278c681612f1ee0e36019e149137f114b9d7f flutter_local_authentication: 1172a4dd88f6306dadce067454e2c4caf07977bb
flutter_mailer: 3a8cd4f36c960fb04528d5471097270c19fec1c4 flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83
flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418 flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1 fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f
in_app_review: 5596fe56fab799e8edb3561c03d053363ab13457 in_app_review: a31b5257259646ea78e0e35fc914979b0031d011
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda
SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3 SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8
sensitive_clipboard: 161e9abc3d56b3131309d8a321eb4690a803c16b sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sp_scanner: b1bc9321690980bdb44bba7ec85d5543e716d1b5 sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
uni_links: ed8c961e47ed9ce42b6d91e1de8049e38a4b3152 universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6
universal_ble: ff19787898040d721109c6324472e5dd4bc86adc url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d wakelock_plus: 373cfe59b235a6dd5837d0fb88791d2f13a90d56
wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49
PODFILE CHECKSUM: e448f662d4c41f0c0b1ccbb78afd57dbf895a597 PODFILE CHECKSUM: e448f662d4c41f0c0b1ccbb78afd57dbf895a597

View file

@ -1,6 +1,7 @@
import 'package:cake_wallet/buy/buy_amount.dart'; import 'package:cake_wallet/buy/buy_amount.dart';
import 'package:cake_wallet/buy/buy_quote.dart'; import 'package:cake_wallet/buy/buy_quote.dart';
import 'package:cake_wallet/buy/order.dart'; import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/buy/pairs_utils.dart';
import 'package:cake_wallet/buy/payment_method.dart'; import 'package:cake_wallet/buy/payment_method.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart'; import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
@ -13,11 +14,15 @@ abstract class BuyProvider {
required this.wallet, required this.wallet,
required this.isTestEnvironment, required this.isTestEnvironment,
required this.ledgerVM, required this.ledgerVM,
required this.supportedCryptoList,
required this.supportedFiatList
}); });
final WalletBase wallet; final WalletBase wallet;
final bool isTestEnvironment; final bool isTestEnvironment;
final LedgerViewModel? ledgerVM; final LedgerViewModel? ledgerVM;
final List<TradePair<dynamic, dynamic>> supportedCryptoList;
final List<TradePair<dynamic, dynamic>> supportedFiatList;
String get title; String get title;

View file

@ -3,6 +3,7 @@ import 'dart:developer';
import 'package:cake_wallet/buy/buy_provider.dart'; import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/buy_quote.dart'; import 'package:cake_wallet/buy/buy_quote.dart';
import 'package:cake_wallet/buy/pairs_utils.dart';
import 'package:cake_wallet/buy/payment_method.dart'; import 'package:cake_wallet/buy/payment_method.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
@ -20,9 +21,19 @@ import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
class DFXBuyProvider extends BuyProvider { class DFXBuyProvider extends BuyProvider {
DFXBuyProvider( DFXBuyProvider({
{required WalletBase wallet, bool isTestEnvironment = false, LedgerViewModel? ledgerVM}) required WalletBase wallet,
: super(wallet: wallet, isTestEnvironment: isTestEnvironment, ledgerVM: ledgerVM); bool isTestEnvironment = false,
LedgerViewModel? ledgerVM,
}) : super(
wallet: wallet,
isTestEnvironment: isTestEnvironment,
ledgerVM: ledgerVM,
supportedCryptoList: supportedCryptoToFiatPairs(
notSupportedCrypto: _notSupportedCrypto, notSupportedFiat: _notSupportedFiat),
supportedFiatList: supportedFiatToCryptoPairs(
notSupportedFiat: _notSupportedFiat, notSupportedCrypto: _notSupportedCrypto)
);
static const _baseUrl = 'api.dfx.swiss'; static const _baseUrl = 'api.dfx.swiss';
@ -30,6 +41,9 @@ class DFXBuyProvider extends BuyProvider {
static const _authPath = '/v1/auth'; static const _authPath = '/v1/auth';
static const walletName = 'CakeWallet'; static const walletName = 'CakeWallet';
static const List<CryptoCurrency> _notSupportedCrypto = [];
static const List<FiatCurrency> _notSupportedFiat = [];
@override @override
String get title => 'DFX.swiss'; String get title => 'DFX.swiss';

View file

@ -3,6 +3,7 @@ import 'dart:convert';
import 'package:cake_wallet/.secrets.g.dart' as secrets; import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/buy/buy_provider.dart'; import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/buy_quote.dart'; import 'package:cake_wallet/buy/buy_quote.dart';
import 'package:cake_wallet/buy/pairs_utils.dart';
import 'package:cake_wallet/buy/payment_method.dart'; import 'package:cake_wallet/buy/payment_method.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
@ -16,7 +17,14 @@ import 'package:url_launcher/url_launcher.dart';
class KryptonimBuyProvider extends BuyProvider { class KryptonimBuyProvider extends BuyProvider {
KryptonimBuyProvider({required WalletBase wallet, bool isTestEnvironment = false}) KryptonimBuyProvider({required WalletBase wallet, bool isTestEnvironment = false})
: super(wallet: wallet, isTestEnvironment: isTestEnvironment, ledgerVM: null); : super(
wallet: wallet,
isTestEnvironment: isTestEnvironment,
ledgerVM: null,
supportedCryptoList: supportedCryptoToFiatPairs(
notSupportedCrypto: _notSupportedCrypto, notSupportedFiat: _notSupportedFiat),
supportedFiatList: supportedFiatToCryptoPairs(
notSupportedFiat: _notSupportedFiat, notSupportedCrypto: _notSupportedCrypto));
static const _isProduction = true; static const _isProduction = true;
@ -27,6 +35,9 @@ class KryptonimBuyProvider extends BuyProvider {
static String get _kryptonimApiKey => secrets.kryptonimApiKey; static String get _kryptonimApiKey => secrets.kryptonimApiKey;
static const List<CryptoCurrency> _notSupportedCrypto = [];
static const List<FiatCurrency> _notSupportedFiat = [];
@override @override
String get title => 'Kryptonim'; String get title => 'Kryptonim';

View file

@ -3,6 +3,7 @@ import 'dart:convert';
import 'package:cake_wallet/.secrets.g.dart' as secrets; import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/buy/buy_provider.dart'; import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/buy_quote.dart'; import 'package:cake_wallet/buy/buy_quote.dart';
import 'package:cake_wallet/buy/pairs_utils.dart';
import 'package:cake_wallet/buy/payment_method.dart'; import 'package:cake_wallet/buy/payment_method.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
@ -18,7 +19,14 @@ import 'package:url_launcher/url_launcher.dart';
class MeldBuyProvider extends BuyProvider { class MeldBuyProvider extends BuyProvider {
MeldBuyProvider({required WalletBase wallet, bool isTestEnvironment = false}) MeldBuyProvider({required WalletBase wallet, bool isTestEnvironment = false})
: super(wallet: wallet, isTestEnvironment: isTestEnvironment, ledgerVM: null); : super(
wallet: wallet,
isTestEnvironment: isTestEnvironment,
ledgerVM: null,
supportedCryptoList: supportedCryptoToFiatPairs(
notSupportedCrypto: _notSupportedCrypto, notSupportedFiat: _notSupportedFiat),
supportedFiatList: supportedFiatToCryptoPairs(
notSupportedFiat: _notSupportedFiat, notSupportedCrypto: _notSupportedCrypto));
static const _isProduction = false; static const _isProduction = false;
@ -34,6 +42,9 @@ class MeldBuyProvider extends BuyProvider {
static String get _testApiKey => secrets.meldTestApiKey; static String get _testApiKey => secrets.meldTestApiKey;
static const List<CryptoCurrency> _notSupportedCrypto = [];
static const List<FiatCurrency> _notSupportedFiat = [];
static String get _testPublicKey => '' ; //secrets.meldTestPublicKey; static String get _testPublicKey => '' ; //secrets.meldTestPublicKey;
@override @override

View file

@ -7,6 +7,7 @@ import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/buy_provider_description.dart'; import 'package:cake_wallet/buy/buy_provider_description.dart';
import 'package:cake_wallet/buy/buy_quote.dart'; import 'package:cake_wallet/buy/buy_quote.dart';
import 'package:cake_wallet/buy/order.dart'; import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/buy/pairs_utils.dart';
import 'package:cake_wallet/buy/payment_method.dart'; import 'package:cake_wallet/buy/payment_method.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/trade_state.dart';
@ -31,7 +32,14 @@ class MoonPayProvider extends BuyProvider {
}) : baseSellUrl = isTestEnvironment ? _baseSellTestUrl : _baseSellProductUrl, }) : baseSellUrl = isTestEnvironment ? _baseSellTestUrl : _baseSellProductUrl,
baseBuyUrl = isTestEnvironment ? _baseBuyTestUrl : _baseBuyProductUrl, baseBuyUrl = isTestEnvironment ? _baseBuyTestUrl : _baseBuyProductUrl,
this._settingsStore = settingsStore, this._settingsStore = settingsStore,
super(wallet: wallet, isTestEnvironment: isTestEnvironment, ledgerVM: null); super(
wallet: wallet,
isTestEnvironment: isTestEnvironment,
ledgerVM: null,
supportedCryptoList: supportedCryptoToFiatPairs(
notSupportedCrypto: _notSupportedCrypto, notSupportedFiat: _notSupportedFiat),
supportedFiatList: supportedFiatToCryptoPairs(
notSupportedFiat: _notSupportedFiat, notSupportedCrypto: _notSupportedCrypto));
final SettingsStore _settingsStore; final SettingsStore _settingsStore;
@ -48,6 +56,9 @@ class MoonPayProvider extends BuyProvider {
static const _transactionsSuffix = '/v1/transactions'; static const _transactionsSuffix = '/v1/transactions';
static const List<CryptoCurrency> _notSupportedCrypto = [];
static const List<FiatCurrency> _notSupportedFiat = [];
final String baseBuyUrl; final String baseBuyUrl;
final String baseSellUrl; final String baseSellUrl;

View file

@ -4,6 +4,7 @@ import 'dart:developer';
import 'package:cake_wallet/.secrets.g.dart' as secrets; import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/buy/buy_provider.dart'; import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/buy_quote.dart'; import 'package:cake_wallet/buy/buy_quote.dart';
import 'package:cake_wallet/buy/pairs_utils.dart';
import 'package:cake_wallet/buy/payment_method.dart'; import 'package:cake_wallet/buy/payment_method.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
@ -20,7 +21,13 @@ import 'package:url_launcher/url_launcher.dart';
class OnRamperBuyProvider extends BuyProvider { class OnRamperBuyProvider extends BuyProvider {
OnRamperBuyProvider(this._settingsStore, OnRamperBuyProvider(this._settingsStore,
{required WalletBase wallet, bool isTestEnvironment = false}) {required WalletBase wallet, bool isTestEnvironment = false})
: super(wallet: wallet, isTestEnvironment: isTestEnvironment, ledgerVM: null); : super(wallet: wallet,
isTestEnvironment: isTestEnvironment,
ledgerVM: null,
supportedCryptoList: supportedCryptoToFiatPairs(
notSupportedCrypto: _notSupportedCrypto, notSupportedFiat: _notSupportedFiat),
supportedFiatList: supportedFiatToCryptoPairs(
notSupportedFiat: _notSupportedFiat, notSupportedCrypto: _notSupportedCrypto));
static const _baseUrl = 'buy.onramper.com'; static const _baseUrl = 'buy.onramper.com';
static const _baseApiUrl = 'api.onramper.com'; static const _baseApiUrl = 'api.onramper.com';
@ -28,6 +35,9 @@ class OnRamperBuyProvider extends BuyProvider {
static const paymentTypes = '/payment-types'; static const paymentTypes = '/payment-types';
static const supported = '/supported'; static const supported = '/supported';
static const List<CryptoCurrency> _notSupportedCrypto = [];
static const List<FiatCurrency> _notSupportedFiat = [];
final SettingsStore _settingsStore; final SettingsStore _settingsStore;
String get _apiKey => secrets.onramperApiKey; String get _apiKey => secrets.onramperApiKey;
@ -222,8 +232,7 @@ class OnRamperBuyProvider extends BuyProvider {
'${prefix}defaultAmount': amount.toString(), '${prefix}defaultAmount': amount.toString(),
if (paymentMethod != null) '${prefix}defaultPaymentMethod': paymentMethod, if (paymentMethod != null) '${prefix}defaultPaymentMethod': paymentMethod,
'onlyOnramps': quote.rampId, 'onlyOnramps': quote.rampId,
'networkWallets': '$defaultCrypto:$cryptoCurrencyAddress', 'networkWallets': '${_tagToNetwork(quote.cryptoCurrency.tag ?? quote.cryptoCurrency.title)}:$cryptoCurrencyAddress',
'walletAddress': cryptoCurrencyAddress,
'supportSwap': "false", 'supportSwap': "false",
'primaryColor': primaryColor, 'primaryColor': primaryColor,
'secondaryColor': secondaryColor, 'secondaryColor': secondaryColor,

Some files were not shown because too many files have changed in this diff Show more