Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
|
@ -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:
|
||||||
|
|
4
.github/workflows/no_print_in_dart.yaml
vendored
|
@ -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"
|
||||||
|
|
2
.github/workflows/no_restricted_imports.yaml
vendored
|
@ -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
|
||||||
|
|
4
.github/workflows/pr_test_build_android.yml
vendored
|
@ -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: |
|
||||||
|
|
7
.github/workflows/pr_test_build_linux.yml
vendored
|
@ -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
|
@ -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
|
||||||
|
|
59
Dockerfile
|
@ -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
|
||||||
|
|
|
@ -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?",
|
||||||
|
|
Before Width: | Height: | Size: 3 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
assets/images/cakewallet_android_icon.png
Executable file → Normal file
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 52 KiB |
|
@ -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>
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 5 KiB |
Before Width: | Height: | Size: 509 B |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 852 B |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 327 B |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 459 B |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 677 B |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 8.5 KiB |
After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 5 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 1,017 B |
Before Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 207 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 206 KiB |
BIN
assets/images/deuro_icon.png
Normal file
After Width: | Height: | Size: 132 KiB |
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -69,6 +69,6 @@ class ElectrumBalance extends Balance {
|
||||||
'unconfirmed': unconfirmed,
|
'unconfirmed': unconfirmed,
|
||||||
'frozen': frozen,
|
'frozen': frozen,
|
||||||
'secondConfirmed': secondConfirmed,
|
'secondConfirmed': secondConfirmed,
|
||||||
'secondUnconfirmed': secondUnconfirmed
|
'secondUnconfirmed': secondUnconfirmed,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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_
|
|
|
@ -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)
|
|
|
@ -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!);
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
//
|
|
||||||
// Generated file. Do not edit.
|
|
||||||
//
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
|
||||||
|
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
|
||||||
}
|
|
|
@ -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_
|
|
|
@ -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)
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
@ -1 +0,0 @@
|
||||||
extensions:
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
```
|
```
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|