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:
Automated_integration_test:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:

View file

@ -4,14 +4,14 @@ on: [pull_request]
jobs:
PR_test_build:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Check for print() statements in dart code (use printV() instead)
if: github.event_name == 'pull_request'
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
echo "$GIT_GREP_OUT"
echo "There are .dart files which use print() statements"

View file

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

View file

@ -9,7 +9,7 @@ jobs:
PR_test_build:
runs-on: linux-amd64
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:
STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet
@ -274,7 +274,7 @@ jobs:
- name: Build
run: |
flutter build apk --release --split-per-abi
flutter build apk --dart-define=hasDevOptions=true --release --split-per-abi
- name: Rename apk file
run: |

View file

@ -9,7 +9,7 @@ jobs:
PR_test_build:
runs-on: linux-amd64
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:
STORE_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/go/pkg:/root/go/pkg
- /opt/cw_cache_linux/opt/generic_cache:/opt/generic_cache
strategy:
matrix:
api-level: [29]
steps:
- name: Fix github actions messing up $HOME...
@ -228,7 +225,7 @@ jobs:
- name: Build linux
run: |
flutter build linux --release
flutter build linux --dart-define=hasDevOptions=true --release
- name: Compress release
run: |

23
.gitignore vendored
View file

@ -187,3 +187,26 @@ ios/MoneroWallet.framework/MoneroWallet
ios/WowneroWallet.framework/WowneroWallet
ios/ZanoWallet.framework/ZanoWallet
*_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 push 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
# Heavily inspired by cirrusci images
# 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-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
# Set necessary environment variables
# 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
ENV FLUTTER_VERSION=3.27.4
@ -60,11 +59,20 @@ RUN set -o xtrace \
ffmpeg network-manager x11-utils xvfb psmisc \
# aarch64-linux-gnu dependencies
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/* \
&& sh -c 'echo "en_US.UTF-8 UTF-8" > /etc/locale.gen' \
&& locale-gen \
&& 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
RUN curl -fsSL https://deb.nodesource.com/setup_23.x | bash - && \
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 GOROOT=/usr/local/go
ENV GOPATH=${HOME}/go
RUN wget https://go.dev/dl/go${GOLANG_VERSION}.linux-amd64.tar.gz &&\
rm -rf /usr/local/go &&\
tar -C /usr/local -xzf go${GOLANG_VERSION}.linux-amd64.tar.gz && \
RUN ARCH=$(uname -m) && \
if [ "$ARCH" = "x86_64" ]; then \
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 && \
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
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/ \
&& unzip -q android-sdk-tools.zip -d ${ANDROID_HOME}/cmdline-tools/ \
&& 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 \
&& mkdir -p ${HOME}/.android \
&& 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)
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
RUN yes | sdkmanager \
RUN ARCH=$(uname -m) && \
if [ "$ARCH" != "x86_64" ]; then exit 0; fi \
&& yes | sdkmanager \
"platforms;android-$ANDROID_PLATFORM_VERSION" \
"build-tools;$ANDROID_BUILD_TOOLS_VERSION" \
"platforms;android-33" \
@ -114,12 +139,16 @@ RUN yes | sdkmanager \
# Install extra NDK dependency for sp_scanner
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"
# Install dependencies for tests
# 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-31;default;x86_64" \
"platforms;android-29" \
@ -135,7 +164,7 @@ RUN (addgroup kvm || true) && \
ENV PATH=${HOME}/.cargo/bin:${PATH}
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \
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 \
rustup target add --toolchain stable $target; \
done

View file

@ -13,7 +13,7 @@
},
{
"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ć?",
@ -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"
},
{
"question" : "Co mogę zrobić, jeśli stracę nasiona?",
"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"
"question" : "Co mogę zrobić, jeśli zapomniałem frazę seed?",
"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"
},
{
@ -37,7 +37,7 @@
},
{
"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?",

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"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_adaptive_back"/>
<foreground android:drawable="@mipmap/ic_launcher_adaptive_fore"/>
<monochrome android:drawable="@mipmap/ic_launcher_adaptive_mono"/>
<background android:drawable="@mipmap/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
</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
useSSL: true
is_default: true
-
uri: rpc.nano.to
is_default: true
useSSL: true
-
uri: node.nautilus.io

View file

@ -1,3 +1,5 @@
UI/UX enhancements
Stability improvements
Add background sync to Monero
Enhance Backup files
Improve app usability and user experience
User interface enhancements
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
runtime: org.freedesktop.Platform
runtime-version: '22.08'
runtime-version: '24.08'
sdk: org.freedesktop.Sdk
command: cake_wallet
separate-locales: false
@ -15,8 +15,6 @@ finish-args:
modules:
- name: cake_wallet
buildsystem: simple
only-arches:
- x86_64
build-commands:
- "cp -R bundle /app/cake_wallet"
- "chmod +x /app/cake_wallet/cake_wallet"
@ -28,7 +26,7 @@ modules:
- "cp com.cakewallet.CakeWallet.desktop /app/share/applications"
sources:
- type: dir
path: build/linux/x64/release
path: build/linux/current/release
- type: file
path: assets/images/cakewallet_icon_180.png
- type: file

View file

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

View file

@ -110,7 +110,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
CryptoCurrency.wow,
CryptoCurrency.zano,
CryptoCurrency.ton,
CryptoCurrency.flip
CryptoCurrency.flip,
CryptoCurrency.deuro
];
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 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 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 =
[...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;
@HiveField(6)
final String? tag;
@HiveField(7, defaultValue: false)
final bool isPotentialScam;
bool get enabled => _enabled;
@ -33,6 +35,7 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
bool enabled = true,
this.iconPath,
this.tag,
this.isPotentialScam = false,
}) : _enabled = enabled,
super(
name: symbol.toLowerCase(),
@ -40,7 +43,9 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
fullName: name,
tag: tag,
iconPath: iconPath,
decimals: decimal);
decimals: decimal,
isPotentialScam: isPotentialScam,
);
Erc20Token.copyWith(Erc20Token other, String? icon, String? tag)
: this.name = other.name,
@ -50,6 +55,7 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
this._enabled = other.enabled,
this.tag = tag,
this.iconPath = icon,
this.isPotentialScam = other.isPotentialScam,
super(
name: other.name,
title: other.symbol.toUpperCase(),
@ -57,6 +63,7 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
tag: tag,
iconPath: icon,
decimals: other.decimal,
isPotentialScam: other.isPotentialScam,
);
static const typeId = ERC20_TOKEN_TYPE_ID;

View file

@ -1,4 +1,5 @@
import 'dart:math';
import 'package:flutter/foundation.dart';
void printV(dynamic content) {
CustomTrace programInfo = CustomTrace(StackTrace.current);
@ -20,7 +21,7 @@ class CustomTrace {
try {
_parseTrace();
} 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(")", "");
this.columnNumber = int.tryParse(columnStr);
} 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;
String formatCryptoAmount(String amount) => amount;
SyncStatus get syncStatus;
set syncStatus(SyncStatus status);

View file

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

View file

@ -380,7 +380,7 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance, DecredTransact
totalAmt = totalIn;
} else if (out.cryptoAmount != null) {
final coins = double.parse(out.cryptoAmount!);
amt = (coins * 1e8).toInt();
amt = (coins * 1e8).round();
}
totalAmt += amt;
final o = {
@ -415,7 +415,7 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance, DecredTransact
};
final fee = decoded["fee"] ?? 0;
if (sendAll) {
totalAmt = (totalAmt - fee).toInt();
totalAmt = (totalAmt - fee).round();
}
return DecredPendingTransaction(
txid: decoded["txid"] ?? "", amount: totalAmt, fee: fee, rawHex: signedHex, send: send);
@ -475,6 +475,7 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance, DecredTransact
}
Future<Map<String, DecredTransactionInfo>> fetchFiveTransactions(int from) async {
try {
final res = await _libwallet.listTransactions(walletInfo.name, from.toString(), "5");
final decoded = json.decode(res);
var txs = <String, DecredTransactionInfo>{};
@ -485,9 +486,9 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance, DecredTransact
direction = TransactionDirection.incoming;
}
final amountDouble = d["amount"] ?? 0.0;
final amount = (amountDouble * 1e8).toInt().abs();
final amount = (amountDouble * 1e8).round().abs();
final feeDouble = d["fee"] ?? 0.0;
final fee = (feeDouble * 1e8).toInt().abs();
final fee = (feeDouble * 1e8).round().abs();
final confs = d["confirmations"] ?? 0;
final sendTime = d["time"] ?? 0;
final height = d["height"] ?? 0;
@ -505,6 +506,10 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance, DecredTransact
txs[txid] = txInfo;
}
return txs;
} catch (e) {
printV(e);
return {};
}
}
// uniqueTxID combines the tx id and vout to create a unique id.
@ -612,6 +617,7 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance, DecredTransact
}
Future<void> fetchUnspents() async {
try {
final res = await _libwallet.listUnspents(walletInfo.name);
final decoded = json.decode(res);
var unspents = <Unspent>[];
@ -621,12 +627,15 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance, DecredTransact
continue;
}
final amountDouble = d["amount"] ?? 0.0;
final amount = (amountDouble * 1e8).toInt().abs();
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);
}
_unspents = unspents;
} catch (e) {
printV(e);
}
}
List<Unspent> unspents() {

View file

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

View file

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

View file

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

View file

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

View file

@ -628,13 +628,13 @@ abstract class EVMChainWalletBase extends WalletBase<
Future<void> addErc20Token(Erc20Token token) async {
String? iconPath;
if (token.iconPath == null || token.iconPath!.isEmpty) {
if ((token.iconPath == null || token.iconPath!.isEmpty) && !token.isPotentialScam) {
try {
iconPath = CryptoCurrency.all
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
.iconPath;
} catch (_) {}
} else {
} else if (!token.isPotentialScam) {
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;
monero.WalletListener? _wlptr = null;
monero.WalletListener getWlptr() {
monero.WalletListener? getWlptr() {
if (wptr == null) return null;
if (wptr!.address == _wlptrForW) return _wlptr!;
_wlptrForW = wptr!.address;
_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:monero/monero.dart' as monero;
import 'package:mutex/mutex.dart';
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!);
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) {
final count = countOfCoins();
Future<int?> getCoinByKeyImage(String keyImage) async {
final count = await countOfCoins();
for (int i = 0; i < count; i++) {
final coin = getCoin(i);
final coin = await getCoin(i);
final coinAddress = monero.CoinsInfo_keyImage(coin);
if (keyImage == coinAddress) {
return i;
@ -24,6 +45,16 @@ int? getCoinByKeyImage(String keyImage) {
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:isolate';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_monero/api/account_list.dart';
import 'package:cw_monero/api/exceptions/creation_transaction_exception.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';
Map<int, Map<String, String>> txKeys = {};
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 status = monero.Wallet_status(wptr!);
if (status != 0) {
final error = monero.Wallet_errorString(wptr!);
monero.Wallet_errorString(wptr!);
txKeys[wptr!.address]![txId] = "";
return "";
}
txKeys[wptr!.address]![txId] = txKey;
return txKey;
}
final txHistoryMutex = Mutex();
monero.TransactionHistory? txhistory;
bool isRefreshingTx = false;
@ -34,6 +43,7 @@ Future<void> refreshTransactions() async {
await Isolate.run(() {
monero.TransactionHistory_refresh(Pointer.fromAddress(ptr));
});
await Future.delayed(Duration.zero);
txHistoryMutex.release();
isRefreshingTx = false;
}
@ -45,8 +55,24 @@ Future<List<Transaction>> getAllTransactions() async {
await txHistoryMutex.acquire();
txhistory ??= monero.Wallet_history(wptr!);
final startAddress = txhistory!.address * wptr!.address;
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();
final accts = monero.Wallet_numSubaddressAccounts(wptr!);
for (var i = 0; i < accts; i++) {
@ -79,8 +105,18 @@ Future<List<Transaction>> getAllTransactions() async {
return list;
}
Transaction getTransaction(String txId) {
return Transaction(txInfo: monero.TransactionHistory_transactionById(txhistory!, txid: txId));
Map<int, Map<String, Transaction>> txCache = {};
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(
@ -161,31 +197,39 @@ Future<PendingTransactionDescription> createTransactionSync(
);
}
PendingTransactionDescription createTransactionMultDestSync(
Future<PendingTransactionDescription> createTransactionMultDest(
{required List<MoneroOutput> outputs,
required String paymentId,
required int priorityRaw,
int accountIndex = 0,
List<String> preferredInputs = const []}) {
List<String> preferredInputs = const []}) async {
final dstAddrs = outputs.map((e) => e.address).toList();
final amounts = outputs.map((e) => monero.Wallet_amountFromString(e.amount)).toList();
// printV("multDest: dstAddrs: $dstAddrs");
// printV("multDest: amounts: $amounts");
final waddr = wptr!.address;
final txptr = monero.Wallet_createTransactionMultDest(
wptr!,
// 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;
}));
if (monero.PendingTransaction_status(txptr) != 0) {
throw CreationTransactionException(message: monero.PendingTransaction_errorString(txptr));
}
return PendingTransactionDescription(
amount: monero.PendingTransaction_amount(txptr),
fee: monero.PendingTransaction_fee(txptr),
@ -255,21 +299,6 @@ Future<PendingTransactionDescription> _createTransactionSync(Map args) async {
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(
{required String address,
required int priorityRaw,
@ -286,21 +315,6 @@ Future<PendingTransactionDescription> createTransaction(
'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 {
final String displayLabel;
late final String subaddressLabel = monero.Wallet_getSubaddressLabel(

View file

@ -2,10 +2,10 @@ import 'dart:async';
import 'dart:ffi';
import 'dart:isolate';
import 'package:cw_core/root_dir.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_monero/api/account_list.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:monero/monero.dart' as monero;
import 'package:mutex/mutex.dart';
@ -21,14 +21,18 @@ int getSyncingHeight() {
}
bool isNeededToRefresh() {
final ret = monero.MONERO_cw_WalletListener_isNeedToRefresh(getWlptr());
monero.MONERO_cw_WalletListener_resetNeedToRefresh(getWlptr());
final wlptr = getWlptr();
if (wlptr == null) return false;
final ret = monero.MONERO_cw_WalletListener_isNeedToRefresh(wlptr);
monero.MONERO_cw_WalletListener_resetNeedToRefresh(wlptr);
return ret;
}
bool isNewTransactionExist() {
final ret = monero.MONERO_cw_WalletListener_isNewTransactionExist(getWlptr());
monero.MONERO_cw_WalletListener_resetIsNewTransactionExist(getWlptr());
final wlptr = getWlptr();
if (wlptr == null) return false;
final ret = monero.MONERO_cw_WalletListener_isNewTransactionExist(wlptr);
monero.MONERO_cw_WalletListener_resetIsNewTransactionExist(wlptr);
return ret;
}
@ -75,9 +79,15 @@ String? getSeedLanguage(String? language) {
String getSeedLegacy(String? language) {
final cakepassphrase = getPassphrase();
var legacy = monero.Wallet_seed(wptr!, seedOffset: cakepassphrase);
language = getSeedLanguage(language);
var legacy = monero.Wallet_seed(wptr!, seedOffset: cakepassphrase);
if (monero.Wallet_status(wptr!) != 0) {
if (monero.Wallet_errorString(wptr!).contains("seed_language")) {
monero.Wallet_setSeedLanguage(wptr!, language: "English");
legacy = monero.Wallet_seed(wptr!, seedOffset: cakepassphrase);
}
}
if (language != null) {
monero.Wallet_setSeedLanguage(wptr!, language: language);
final status = monero.Wallet_status(wptr!);
@ -88,9 +98,9 @@ String getSeedLegacy(String? language) {
}
return err;
}
}
legacy = monero.Wallet_seed(wptr!, seedOffset: cakepassphrase);
}
if (monero.Wallet_status(wptr!) != 0) {
final err = monero.Wallet_errorString(wptr!);
if (legacy.isNotEmpty) {
@ -193,12 +203,15 @@ void startRefreshSync() {
}
void setRefreshFromBlockHeight({required int height}) =>
void setRefreshFromBlockHeight({required int height}) {
monero.Wallet_setRefreshFromBlockHeight(wptr!,
refresh_from_block_height: height);
}
void setRecoveringFromSeed({required bool isRecovery}) =>
void setRecoveringFromSeed({required bool isRecovery}) {
monero.Wallet_setRecoveringFromSeed(wptr!, recoveringFromSeed: isRecovery);
monero.Wallet_store(wptr!);
}
final storeMutex = Mutex();
@ -389,3 +402,5 @@ String signMessage(String message, {String address = ""}) {
bool verifyMessage(String message, String address, String 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));
}
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
}
setupBackgroundSync(password, newWptr);
wptr = newWptr;
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: passphrase);
@ -141,6 +137,7 @@ void restoreWalletFromSeedSync(
wptr = newWptr;
setRefreshFromBlockHeight(height: restoreHeight);
setupBackgroundSync(password, newWptr);
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: passphrase);
@ -186,13 +183,6 @@ void restoreWalletFromKeysSync(
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
// match the view key provided
if (spendKey != "") {
@ -217,11 +207,7 @@ void restoreWalletFromKeysSync(
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));
}
setupBackgroundSync(password, newWptr);
}
}
@ -268,11 +254,7 @@ void restoreWalletFromPolyseedWithOffset(
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: seedOffset);
monero.Wallet_store(wptr!);
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
}
setupBackgroundSync(password, newWptr);
storeSync();
openedWalletsByPath[path] = wptr!;
@ -324,11 +306,7 @@ void restoreWalletFromSpendKeySync(
storeSync();
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
}
setupBackgroundSync(password, newWptr);
openedWalletsByPath[path] = wptr!;
_lastOpenedWallet = path;
@ -361,13 +339,6 @@ Future<void> restoreWalletFromHardwareWallet(
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;
_lastOpenedWallet = path;
openedWalletsByPath[path] = wptr!;
@ -437,12 +408,8 @@ Future<void> loadWallet(
printV("loadWallet:"+err);
throw WalletOpeningException(message: err);
}
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
status = monero.Wallet_status(newWptr);
if (status != 0) {
final err = monero.Wallet_errorString(newWptr);
printV("loadWallet:"+err);
throw WalletOpeningException(message: err);
if (deviceType == 0) {
setupBackgroundSync(password, 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) {
final path = args['path'] as String;
final password = args['password'] as String;
@ -591,4 +569,4 @@ Future<void> restoreFromSpendKey(
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/utils/print_verbose.dart';
import 'package:cw_monero/api/wallet_manager.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_core/account.dart';
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);
return Account(
@ -54,6 +66,9 @@ abstract class MoneroAccountListBase with Store {
);
}).toList();
return _cachedAccounts[account_list.wptr!.address]!;
}
Future<void> addAccount({required String label}) async {
await account_list.addAccount(label: label);
update();

View file

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

View file

@ -3,6 +3,7 @@ import 'dart:ffi';
import 'dart:io';
import 'dart:isolate';
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/account.dart';
@ -168,6 +169,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
if (monero_wallet.getCurrentHeight() <= 1) {
monero_wallet.setRefreshFromBlockHeight(
height: walletInfo.restoreHeight);
setupBackgroundSync(password, wptr!);
}
}
@ -233,18 +235,14 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
return;
}
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();
monero.Wallet_startBackgroundSync(wptr!);
status = monero.Wallet_status(wptr!);
final status = monero.Wallet_status(wptr!);
if (status != 0) {
final err = monero.Wallet_errorString(wptr!);
throw Exception("unable to start background sync: $err");
isBackgroundSyncRunning = false;
printV("startBackgroundSync: $err");
}
await save();
await init();
@ -260,9 +258,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
printV("Stopping background sync");
await save();
monero.Wallet_stopBackgroundSync(wptr!, '');
await save();
isBackgroundSyncRunning = false;
}
await save();
}
@action
@ -406,6 +404,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
outputs: moneroOutputs,
priorityRaw: _credentials.priority.serialize(),
accountIndex: walletAddresses.account!.id,
paymentId: "",
preferredInputs: inputs);
} else {
final output = outputs.first;
@ -509,6 +508,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
final currentCacheFile = File(renamedWalletPath);
final currentKeysFile = File('$renamedWalletPath.keys');
final currentAddressListFile = File('$renamedWalletPath.address.txt');
final backgroundSyncFile = File('$renamedWalletPath.background');
final newWalletPath =
await pathForWallet(name: newWalletName, type: type);
@ -522,6 +522,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
if (currentAddressListFile.existsSync()) {
await currentAddressListFile.rename('$newWalletPath.address.txt');
}
if (backgroundSyncFile.existsSync()) {
await backgroundSyncFile.rename('$newWalletPath.background');
}
await backupWalletFiles(newWalletName);
} catch (e) {
@ -568,6 +571,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
walletInfo.restoreHeight = height;
walletInfo.isRecovery = true;
monero_wallet.setRefreshFromBlockHeight(height: height);
setupBackgroundSync(password, wptr!);
monero_wallet.rescanBlockchainAsync();
await startSync();
_askForUpdateBalance();
@ -583,9 +587,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
unspentCoins.clear();
final coinCount = countOfCoins();
final coinCount = await countOfCoins();
for (var i = 0; i < coinCount; i++) {
final coin = getCoin(i);
final coin = await getCoin(i);
final coinSpent = monero.CoinsInfo_spent(coin);
if (coinSpent == false && monero.CoinsInfo_subaddrAccount(coin) == walletAddresses.account!.id) {
final unspent = MoneroUnspent(
@ -598,7 +602,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
);
// TODO: double-check the logic here
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);
}
@ -690,14 +695,15 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
@override
Future<Map<String, MoneroTransactionInfo>> fetchTransactions() async {
transaction_history.refreshTransactions();
return (await _getAllTransactionsOfAccount(walletAddresses.account?.id))
await transaction_history.refreshTransactions();
final resp = (await _getAllTransactionsOfAccount(walletAddresses.account?.id))
.fold<Map<String, MoneroTransactionInfo>>(
<String, MoneroTransactionInfo>{},
(Map<String, MoneroTransactionInfo> acc, MoneroTransactionInfo tx) {
acc[tx.id] = tx;
return acc;
});
return resp;
}
Future<void> updateTransactions() async {
@ -708,8 +714,17 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
_isTransactionUpdating = true;
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();
_isTransactionUpdating = false;
} catch (e) {
@ -776,6 +791,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
monero_wallet.setRecoveringFromSeed(isRecovery: true);
monero_wallet.setRefreshFromBlockHeight(height: height);
setupBackgroundSync(password, wptr!);
}
int _getHeightDistance(DateTime date) {
@ -904,4 +920,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
monero.WalletManager_openWallet(wmPtr, path: '', password: '');
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;
}
enum OpenWalletTry {
initial,
cacheRestored,
cacheRemoved,
}
class MoneroWalletService extends WalletService<
MoneroNewWalletCredentials,
MoneroRestoreWalletFromSeedCredentials,
@ -139,7 +145,7 @@ class MoneroWalletService extends WalletService<
}
@override
Future<MoneroWallet> openWallet(String name, String password, {bool? retryOnFailure}) async {
Future<MoneroWallet> openWallet(String name, String password, {OpenWalletTry openWalletTry = OpenWalletTry.initial}) async {
try {
final path = await pathForWallet(name: name, type: getType());
@ -153,31 +159,28 @@ class MoneroWalletService extends WalletService<
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
password: password);
final isValid = wallet.walletAddresses.validate();
if (wallet.isHardwareWallet) {
wallet.setLedgerConnection(gLedger!);
gLedger = null;
}
if (!isValid) {
await restoreOrResetWalletFiles(name);
wallet.close(shouldCleanup: false);
return openWallet(name, password);
}
await wallet.init();
return wallet;
} catch (e) {
// TODO: Implement Exception for wallet list service.
if (retryOnFailure == false) {
switch (openWalletTry) {
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,
tag: token.tag ?? "MATIC",
iconPath: iconPath,
isPotentialScam: token.isPotentialScam,
);
}

View file

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

View file

@ -29,6 +29,9 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
@HiveField(6)
final String? tag;
@HiveField(7, defaultValue: false)
final bool isPotentialScam;
bool get enabled => _enabled;
set enabled(bool value) => _enabled = value;
@ -41,6 +44,7 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
bool enabled = true,
this.iconPath,
this.tag = 'TRX',
this.isPotentialScam = false,
}) : _enabled = enabled,
super(
name: symbol.toLowerCase(),
@ -48,7 +52,9 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
fullName: name,
tag: tag,
iconPath: iconPath,
decimals: decimal);
decimals: decimal,
isPotentialScam: isPotentialScam,
);
TronToken.copyWith(TronToken other, String? icon, String? tag)
: name = other.name,
@ -58,6 +64,7 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
_enabled = other.enabled,
tag = tag ?? other.tag,
iconPath = icon ?? other.iconPath,
isPotentialScam = other.isPotentialScam,
super(
name: other.name,
title: other.symbol.toUpperCase(),
@ -65,6 +72,7 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
tag: tag ?? other.tag,
iconPath: icon ?? other.iconPath,
decimals: other.decimal,
isPotentialScam: other.isPotentialScam,
);
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 {
String? iconPath;
if ((token.iconPath == null || token.iconPath!.isEmpty) && !token.isPotentialScam) {
try {
iconPath = CryptoCurrency.all
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
.iconPath;
} catch (_) {}
} else if (!token.isPotentialScam) {
iconPath = token.iconPath;
}
final newToken = TronToken(
name: token.name,
@ -523,6 +527,7 @@ abstract class TronWalletBase extends WalletBase<TronBalance, TronTransactionHis
enabled: token.enabled,
tag: token.tag ?? "TRX",
iconPath: iconPath,
isPotentialScam: token.isPotentialScam,
);
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) {
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);
}
@override
String formatCryptoAmount(String amount) {
return wowneroAmountToString(amount: int.parse(amount));
}
}

View file

@ -509,3 +509,5 @@ Future<String> _closeWallet(int hWallet) async {
printV("Closing wallet: $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/>
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
### 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
# NOTE: Replace `main` with the latest release tag available at https://github.com/cake-tech/cake_wallet/releases/latest.
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 run -v$(pwd):$(pwd) -w $(pwd) -i --rm ghcr.io/cake-tech/cake_wallet:main-linux bash -x << EOF
# 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:debian12-flutter3.27.4-go1.24.1 bash -x << EOF
set -x -e
pushd scripts/android
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
# NOTE: Replace `main` with the latest release tag available at https://github.com/cake-tech/cake_wallet/releases/latest.
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 run -v$(pwd):$(pwd) -w $(pwd) -i --rm ghcr.io/cake-tech/cake_wallet:main-linux bash -x << EOF
# 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 --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
pushd scripts
./gen_android_manifest.sh
@ -37,6 +37,13 @@ flutter clean
dart run tool/generate_localization.dart
dart run tool/generate_new_secrets.dart
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
```
@ -51,46 +58,11 @@ Building Linux application...
✓ 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:
```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):
- Flutter
- ReachabilitySwift
- CryptoSwift (1.8.3)
- cw_mweb (0.0.1):
- Flutter
- CryptoSwift (1.8.4)
- cw_decred (0.0.1):
- Flutter
- cw_mweb (0.0.1):
@ -80,9 +78,9 @@ PODS:
- permission_handler_apple (9.3.0):
- Flutter
- ReachabilitySwift (5.2.4)
- SDWebImage (5.19.7):
- SDWebImage/Core (= 5.19.7)
- SDWebImage/Core (5.19.7)
- SDWebImage (5.20.0):
- SDWebImage/Core (= 5.20.0)
- SDWebImage/Core (5.20.0)
- sensitive_clipboard (0.0.1):
- Flutter
- share_plus (0.0.1):
@ -106,7 +104,6 @@ PODS:
DEPENDENCIES:
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- CryptoSwift
- cw_mweb (from `.symlinks/plugins/cw_mweb/ios`)
- cw_decred (from `.symlinks/plugins/cw_decred/ios`)
- cw_mweb (from `.symlinks/plugins/cw_mweb/ios`)
- device_display_brightness (from `.symlinks/plugins/device_display_brightness/ios`)
@ -147,8 +144,6 @@ SPEC REPOS:
EXTERNAL SOURCES:
connectivity_plus:
:path: ".symlinks/plugins/connectivity_plus/ios"
cw_mweb:
:path: ".symlinks/plugins/cw_mweb/ios"
cw_decred:
:path: ".symlinks/plugins/cw_decred/ios"
cw_mweb:
@ -203,41 +198,40 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/wakelock_plus/ios"
SPEC CHECKSUMS:
connectivity_plus: 481668c94744c30c53b8895afb39159d1e619bdf
CryptoSwift: 967f37cea5a3294d9cce358f78861652155be483
cw_decred: a02cf30175a46971c1e2fa22c48407534541edc6
cw_mweb: 3aea2fb35b2bd04d8b2d21b83216f3b8fb768d85
device_display_brightness: 04374ebd653619292c1d996f00f42877ea19f17f
device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89
devicelocale: bd64aa714485a8afdaded0892c1e7d5b7f680cf8
connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d
CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90
cw_decred: 9c0e1df74745b51a1289ec5e91fb9e24b68fa14a
cw_mweb: 22cd01dfb8ad2d39b15332006f22046aaa8352a3
device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
devicelocale: 35ba84dc7f45f527c3001535d8c8d104edd5d926
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
fast_scanner: 2cb1ad3e69e645e9980fb4961396ce5804caa3e3
file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517
fast_scanner: 44c00940355a51258cd6c2085734193cd23d95bc
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
flutter_local_authentication: 989278c681612f1ee0e36019e149137f114b9d7f
flutter_mailer: 3a8cd4f36c960fb04528d5471097270c19fec1c4
flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
in_app_review: 5596fe56fab799e8edb3561c03d053363ab13457
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
flutter_local_authentication: 1172a4dd88f6306dadce067454e2c4caf07977bb
flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f
in_app_review: a31b5257259646ea78e0e35fc914979b0031d011
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda
SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3
sensitive_clipboard: 161e9abc3d56b3131309d8a321eb4690a803c16b
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
sp_scanner: b1bc9321690980bdb44bba7ec85d5543e716d1b5
SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8
sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
uni_links: ed8c961e47ed9ce42b6d91e1de8049e38a4b3152
universal_ble: ff19787898040d721109c6324472e5dd4bc86adc
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
wakelock_plus: 373cfe59b235a6dd5837d0fb88791d2f13a90d56
PODFILE CHECKSUM: e448f662d4c41f0c0b1ccbb78afd57dbf895a597

View file

@ -1,6 +1,7 @@
import 'package:cake_wallet/buy/buy_amount.dart';
import 'package:cake_wallet/buy/buy_quote.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/entities/fiat_currency.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.isTestEnvironment,
required this.ledgerVM,
required this.supportedCryptoList,
required this.supportedFiatList
});
final WalletBase wallet;
final bool isTestEnvironment;
final LedgerViewModel? ledgerVM;
final List<TradePair<dynamic, dynamic>> supportedCryptoList;
final List<TradePair<dynamic, dynamic>> supportedFiatList;
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_quote.dart';
import 'package:cake_wallet/buy/pairs_utils.dart';
import 'package:cake_wallet/buy/payment_method.dart';
import 'package:cake_wallet/entities/fiat_currency.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';
class DFXBuyProvider extends BuyProvider {
DFXBuyProvider(
{required WalletBase wallet, bool isTestEnvironment = false, LedgerViewModel? ledgerVM})
: super(wallet: wallet, isTestEnvironment: isTestEnvironment, ledgerVM: ledgerVM);
DFXBuyProvider({
required WalletBase wallet,
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';
@ -30,6 +41,9 @@ class DFXBuyProvider extends BuyProvider {
static const _authPath = '/v1/auth';
static const walletName = 'CakeWallet';
static const List<CryptoCurrency> _notSupportedCrypto = [];
static const List<FiatCurrency> _notSupportedFiat = [];
@override
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/buy/buy_provider.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/entities/fiat_currency.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 {
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;
@ -27,6 +35,9 @@ class KryptonimBuyProvider extends BuyProvider {
static String get _kryptonimApiKey => secrets.kryptonimApiKey;
static const List<CryptoCurrency> _notSupportedCrypto = [];
static const List<FiatCurrency> _notSupportedFiat = [];
@override
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/buy/buy_provider.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/entities/fiat_currency.dart';
import 'package:cake_wallet/generated/i18n.dart';
@ -18,7 +19,14 @@ import 'package:url_launcher/url_launcher.dart';
class MeldBuyProvider extends BuyProvider {
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;
@ -34,6 +42,9 @@ class MeldBuyProvider extends BuyProvider {
static String get _testApiKey => secrets.meldTestApiKey;
static const List<CryptoCurrency> _notSupportedCrypto = [];
static const List<FiatCurrency> _notSupportedFiat = [];
static String get _testPublicKey => '' ; //secrets.meldTestPublicKey;
@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_quote.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/entities/fiat_currency.dart';
import 'package:cake_wallet/exchange/trade_state.dart';
@ -31,7 +32,14 @@ class MoonPayProvider extends BuyProvider {
}) : baseSellUrl = isTestEnvironment ? _baseSellTestUrl : _baseSellProductUrl,
baseBuyUrl = isTestEnvironment ? _baseBuyTestUrl : _baseBuyProductUrl,
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;
@ -48,6 +56,9 @@ class MoonPayProvider extends BuyProvider {
static const _transactionsSuffix = '/v1/transactions';
static const List<CryptoCurrency> _notSupportedCrypto = [];
static const List<FiatCurrency> _notSupportedFiat = [];
final String baseBuyUrl;
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/buy/buy_provider.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/entities/fiat_currency.dart';
import 'package:cake_wallet/generated/i18n.dart';
@ -20,7 +21,13 @@ import 'package:url_launcher/url_launcher.dart';
class OnRamperBuyProvider extends BuyProvider {
OnRamperBuyProvider(this._settingsStore,
{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 _baseApiUrl = 'api.onramper.com';
@ -28,6 +35,9 @@ class OnRamperBuyProvider extends BuyProvider {
static const paymentTypes = '/payment-types';
static const supported = '/supported';
static const List<CryptoCurrency> _notSupportedCrypto = [];
static const List<FiatCurrency> _notSupportedFiat = [];
final SettingsStore _settingsStore;
String get _apiKey => secrets.onramperApiKey;
@ -222,8 +232,7 @@ class OnRamperBuyProvider extends BuyProvider {
'${prefix}defaultAmount': amount.toString(),
if (paymentMethod != null) '${prefix}defaultPaymentMethod': paymentMethod,
'onlyOnramps': quote.rampId,
'networkWallets': '$defaultCrypto:$cryptoCurrencyAddress',
'walletAddress': cryptoCurrencyAddress,
'networkWallets': '${_tagToNetwork(quote.cryptoCurrency.tag ?? quote.cryptoCurrency.title)}:$cryptoCurrencyAddress',
'supportSwap': "false",
'primaryColor': primaryColor,
'secondaryColor': secondaryColor,

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