diff --git a/.github/workflows/automated_integration_test.yml b/.github/workflows/automated_integration_test.yml
index 84c680dda..47b08c44d 100644
--- a/.github/workflows/automated_integration_test.yml
+++ b/.github/workflows/automated_integration_test.yml
@@ -55,7 +55,7 @@ jobs:
- name: Flutter action
uses: subosito/flutter-action@v1
with:
- flutter-version: "3.27.4"
+ flutter-version: "3.27.0"
channel: stable
- name: Install package dependencies
@@ -153,8 +153,8 @@ jobs:
echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart
echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
- echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
- echo "const changeNowApiKeyDesktop = '${{ secrets.CHANGE_NOW_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
+ echo "const changeNowCakeWalletApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const changeNowMoneroApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
@@ -168,6 +168,7 @@ jobs:
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const trocadorMoneroApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
@@ -178,7 +179,8 @@ jobs:
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
- echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const exolixCakeWalletApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const exolixMoneroApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
diff --git a/.github/workflows/no_http_imports.yaml b/.github/workflows/no_http_imports.yaml
new file mode 100644
index 000000000..dad6821ac
--- /dev/null
+++ b/.github/workflows/no_http_imports.yaml
@@ -0,0 +1,21 @@
+name: No http imports
+
+on: [pull_request]
+
+jobs:
+ PR_test_build:
+ runs-on: ubuntu-24.04
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Check for http package usage
+ if: github.event_name == 'pull_request'
+ run: |
+ GIT_GREP_OUT="$(git grep package:http | (grep .dart: || test $? = 1) | (grep -v proxy_wrapper.dart || test $? = 1) | (grep -v very_insecure_http_do_not_use || test $? = 1) || true)"
+ [[ "x$GIT_GREP_OUT" == "x" ]] && exit 0
+ echo "$GIT_GREP_OUT"
+ echo "There are .dart files which use http imports"
+ echo "Using http package breaks proxy integration"
+ echo "Please use ProxyWrapper.getHttpClient() from package:cw_core/utils/proxy_wrapper.dart"
+ exit 1
+
\ No newline at end of file
diff --git a/.github/workflows/no_print_in_dart.yaml b/.github/workflows/no_print_in_dart.yaml
index 9c3d82bc2..507793bd8 100644
--- a/.github/workflows/no_print_in_dart.yaml
+++ b/.github/workflows/no_print_in_dart.yaml
@@ -15,5 +15,5 @@ jobs:
[[ "x$GIT_GREP_OUT" == "x" ]] && exit 0
echo "$GIT_GREP_OUT"
echo "There are .dart files which use print() statements"
- echo "Please use printV from package: cw_core/utils/print_verbose.dart"
+ echo "Please use printV from package:cw_core/utils/print_verbose.dart"
exit 1
diff --git a/.github/workflows/pr_test_build_android.yml b/.github/workflows/pr_test_build_android.yml
index 8f6139747..f7c226ce4 100644
--- a/.github/workflows/pr_test_build_android.yml
+++ b/.github/workflows/pr_test_build_android.yml
@@ -9,7 +9,7 @@ jobs:
PR_test_build:
runs-on: linux-amd64
container:
- image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1
+ image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly
env:
STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet
@@ -98,8 +98,8 @@ jobs:
else
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
fi
- echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
- echo "const changeNowApiKeyDesktop = '${{ secrets.CHANGE_NOW_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
+ echo "const changeNowCakeWalletApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const changeNowMoneroApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
@@ -113,6 +113,7 @@ jobs:
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const trocadorMoneroApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
@@ -124,7 +125,8 @@ jobs:
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const nowNodesApiKey = '${{ secrets.EVM_NOWNODES_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
- echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const exolixCakeWalletApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const exolixMoneroApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
@@ -253,6 +255,11 @@ jobs:
- name: Build generated code
run: |
+ flutter --version
+ flutter clean
+ rm -rf .dart_tool
+ rm pubspec.lock
+ flutter pub get
./model_generator.sh async
- name: Generate key properties
diff --git a/.github/workflows/pr_test_build_linux.yml b/.github/workflows/pr_test_build_linux.yml
index 476a033a0..f057b19e5 100644
--- a/.github/workflows/pr_test_build_linux.yml
+++ b/.github/workflows/pr_test_build_linux.yml
@@ -9,7 +9,7 @@ jobs:
PR_test_build:
runs-on: linux-amd64
container:
- image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1
+ image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly
env:
STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet
@@ -91,8 +91,8 @@ jobs:
else
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
fi
- echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
- echo "const changeNowApiKeyDesktop = '${{ secrets.CHANGE_NOW_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
+ echo "const changeNowCakeWalletApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const changeNowMoneroApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
@@ -106,6 +106,7 @@ jobs:
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const trocadorMoneroApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
@@ -117,7 +118,8 @@ jobs:
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const nowNodesApiKey = '${{ secrets.EVM_NOWNODES_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
- echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const exolixCakeWalletApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const exolixMoneroApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
diff --git a/Dockerfile b/Dockerfile
index 84179d645..151b7af20 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-# 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 buildx build --push --pull --platform linux/amd64,linux/arm64 . -f Dockerfile -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly
# Heavily inspired by cirrusci images
# https://github.com/cirruslabs/docker-images-android/blob/master/sdk/tools/Dockerfile
@@ -15,11 +15,11 @@ LABEL org.opencontainers.image.source=https://github.com/cake-tech/cake_wallet
ENV GOLANG_VERSION=1.24.1
# Pin Flutter version to latest known-working version
-ENV FLUTTER_VERSION=3.27.4
+ENV FLUTTER_VERSION=3.27.0
# Pin Android Studio, platform, and build tools versions to latest known-working version
# Comes from https://developer.android.com/studio/#command-tools
-ENV ANDROID_SDK_TOOLS_VERSION=11076708
+ENV ANDROID_SDK_TOOLS_VERSION=13114758
# Comes from https://developer.android.com/studio/releases/build-tools
ENV ANDROID_PLATFORM_VERSION=35
ENV ANDROID_BUILD_TOOLS_VERSION=34.0.0
@@ -164,9 +164,12 @@ RUN (addgroup kvm || true) && \
ENV PATH=${HOME}/.cargo/bin:${PATH}
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \
cargo install cargo-ndk && \
+ for toolchain in stable nightly; \
+ do \
for target in aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu aarch64-unknown-linux-gnu; \
do \
- rustup target add --toolchain stable $target; \
+ rustup target add --toolchain $toolchain $target; \
+ done \
done
# Download and install Flutter
@@ -175,8 +178,11 @@ ENV FLUTTER_HOME=${HOME}/sdks/flutter/${FLUTTER_VERSION}
ENV FLUTTER_ROOT=$FLUTTER_HOME
ENV PATH=${PATH}:${FLUTTER_HOME}/bin:${FLUTTER_HOME}/bin/cache/dart-sdk/bin
-RUN git clone --depth 1 --branch ${FLUTTER_VERSION} https://github.com/flutter/flutter.git ${FLUTTER_HOME} \
- && yes | flutter doctor --android-licenses \
+RUN git clone --branch ${FLUTTER_VERSION} https://github.com/flutter/flutter.git ${FLUTTER_HOME} && \
+ cd ${FLUTTER_HOME} && \
+ git fetch -a
+
+RUN yes | flutter doctor --android-licenses \
&& flutter doctor \
&& chown -R root:root ${FLUTTER_HOME}
diff --git a/android/app/src/main/AndroidManifestBase.xml b/android/app/src/main/AndroidManifestBase.xml
index 280a45b3c..8283a7c8c 100644
--- a/android/app/src/main/AndroidManifestBase.xml
+++ b/android/app/src/main/AndroidManifestBase.xml
@@ -111,6 +111,8 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/images/2fa_warning_light.svg b/assets/images/2fa_warning_light.svg
new file mode 100644
index 000000000..087d8e99b
--- /dev/null
+++ b/assets/images/2fa_warning_light.svg
@@ -0,0 +1,101 @@
+
diff --git a/assets/images/birthday_cake.png b/assets/images/birthday_cake.png
index 84b084fba..293cd10f6 100644
Binary files a/assets/images/birthday_cake.png and b/assets/images/birthday_cake.png differ
diff --git a/assets/images/birthday_cake.svg b/assets/images/birthday_cake.svg
deleted file mode 100644
index b5e31dddb..000000000
--- a/assets/images/birthday_cake.svg
+++ /dev/null
@@ -1,31 +0,0 @@
-
diff --git a/assets/images/btc_lock_dark.png b/assets/images/btc_lock_dark.png
new file mode 100644
index 000000000..f5b3d7e27
Binary files /dev/null and b/assets/images/btc_lock_dark.png differ
diff --git a/assets/images/btc_lock_light.png b/assets/images/btc_lock_light.png
new file mode 100644
index 000000000..4320d96e3
Binary files /dev/null and b/assets/images/btc_lock_light.png differ
diff --git a/assets/images/buy.png b/assets/images/buy.png
index ff4549d5a..32c116e6b 100644
Binary files a/assets/images/buy.png and b/assets/images/buy.png differ
diff --git a/assets/images/cake_logo_dark.svg b/assets/images/cake_logo_dark.svg
new file mode 100644
index 000000000..095077443
--- /dev/null
+++ b/assets/images/cake_logo_dark.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/cake_logo_light.svg b/assets/images/cake_logo_light.svg
new file mode 100644
index 000000000..767e205d1
--- /dev/null
+++ b/assets/images/cake_logo_light.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/contact.png b/assets/images/contact.png
new file mode 100644
index 000000000..5cf96694b
Binary files /dev/null and b/assets/images/contact.png differ
diff --git a/assets/images/hero/cw_welcome_dark.svg b/assets/images/hero/cw_welcome_dark.svg
new file mode 100644
index 000000000..5479cb1ee
--- /dev/null
+++ b/assets/images/hero/cw_welcome_dark.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/images/hero/cw_welcome_light.svg b/assets/images/hero/cw_welcome_light.svg
new file mode 100644
index 000000000..ece7d1f84
--- /dev/null
+++ b/assets/images/hero/cw_welcome_light.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/images/history.svg b/assets/images/history.svg
new file mode 100644
index 000000000..f308ab7e3
--- /dev/null
+++ b/assets/images/history.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/images/home_screen_setting_icon.svg b/assets/images/home_screen_setting_icon.svg
new file mode 100644
index 000000000..7b3aa7b4c
--- /dev/null
+++ b/assets/images/home_screen_setting_icon.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/images/menu.svg b/assets/images/menu.svg
new file mode 100644
index 000000000..0a4cc3784
--- /dev/null
+++ b/assets/images/menu.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/notif.svg b/assets/images/notif.svg
new file mode 100644
index 000000000..b1ff5b4fa
--- /dev/null
+++ b/assets/images/notif.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/notification_icon.svg b/assets/images/notification_icon.svg
index 099039e67..360d0b4e6 100644
--- a/assets/images/notification_icon.svg
+++ b/assets/images/notification_icon.svg
@@ -1,69 +1,3 @@
-
-
-
-
\ No newline at end of file
+
diff --git a/assets/images/passphrase_dark.png b/assets/images/passphrase_dark.png
new file mode 100644
index 000000000..f72d1e1a1
Binary files /dev/null and b/assets/images/passphrase_dark.png differ
diff --git a/assets/images/passphrase_light.png b/assets/images/passphrase_light.png
new file mode 100644
index 000000000..f86f68156
Binary files /dev/null and b/assets/images/passphrase_light.png differ
diff --git a/assets/images/qr-cake.png b/assets/images/qr-cake.png
new file mode 100644
index 000000000..7c54dedb0
Binary files /dev/null and b/assets/images/qr-cake.png differ
diff --git a/assets/images/receive.png b/assets/images/receive.png
new file mode 100644
index 000000000..180a4e5b3
Binary files /dev/null and b/assets/images/receive.png differ
diff --git a/assets/images/seed_verified_dark.png b/assets/images/seed_verified_dark.png
new file mode 100644
index 000000000..cbefa5d8c
Binary files /dev/null and b/assets/images/seed_verified_dark.png differ
diff --git a/assets/images/seed_verified_light.png b/assets/images/seed_verified_light.png
new file mode 100644
index 000000000..a51eddcd7
Binary files /dev/null and b/assets/images/seed_verified_light.png differ
diff --git a/assets/images/seed_warning_dark.svg b/assets/images/seed_warning_dark.svg
new file mode 100644
index 000000000..0a47254ff
--- /dev/null
+++ b/assets/images/seed_warning_dark.svg
@@ -0,0 +1,86 @@
+
diff --git a/assets/images/seed_warning_light.svg b/assets/images/seed_warning_light.svg
new file mode 100644
index 000000000..cab27ec31
--- /dev/null
+++ b/assets/images/seed_warning_light.svg
@@ -0,0 +1,111 @@
+
diff --git a/assets/images/send.png b/assets/images/send.png
deleted file mode 100644
index aef504999..000000000
Binary files a/assets/images/send.png and /dev/null differ
diff --git a/assets/images/send2.png b/assets/images/send2.png
new file mode 100644
index 000000000..85fc570a8
Binary files /dev/null and b/assets/images/send2.png differ
diff --git a/assets/images/swap.png b/assets/images/swap.png
new file mode 100644
index 000000000..fe3fc0893
Binary files /dev/null and b/assets/images/swap.png differ
diff --git a/assets/images/tor_logo.svg b/assets/images/tor_logo.svg
new file mode 100644
index 000000000..ebd00324d
--- /dev/null
+++ b/assets/images/tor_logo.svg
@@ -0,0 +1,76 @@
+
+
+
+
diff --git a/assets/images/usdtbsc_icon.png b/assets/images/usdtbsc_icon.png
new file mode 100644
index 000000000..9f2cda237
Binary files /dev/null and b/assets/images/usdtbsc_icon.png differ
diff --git a/assets/images/wallet_group_bright.png b/assets/images/wallet_group_bright.png
deleted file mode 100644
index 263361db6..000000000
Binary files a/assets/images/wallet_group_bright.png and /dev/null differ
diff --git a/assets/images/wallet_group_confirmed_dark.png b/assets/images/wallet_group_confirmed_dark.png
new file mode 100644
index 000000000..a047cb29c
Binary files /dev/null and b/assets/images/wallet_group_confirmed_dark.png differ
diff --git a/assets/images/wallet_group_confirmed_light.png b/assets/images/wallet_group_confirmed_light.png
new file mode 100644
index 000000000..851d32300
Binary files /dev/null and b/assets/images/wallet_group_confirmed_light.png differ
diff --git a/assets/images/wallet_group_dark.png b/assets/images/wallet_group_dark.png
deleted file mode 100644
index 7cd08d2cd..000000000
Binary files a/assets/images/wallet_group_dark.png and /dev/null differ
diff --git a/assets/images/wallet_group_empty_dark.png b/assets/images/wallet_group_empty_dark.png
new file mode 100644
index 000000000..e613d876e
Binary files /dev/null and b/assets/images/wallet_group_empty_dark.png differ
diff --git a/assets/images/wallet_group_empty_light.png b/assets/images/wallet_group_empty_light.png
new file mode 100644
index 000000000..f795648ae
Binary files /dev/null and b/assets/images/wallet_group_empty_light.png differ
diff --git a/assets/images/wallet_group_light.png b/assets/images/wallet_group_light.png
deleted file mode 100644
index 7827971e7..000000000
Binary files a/assets/images/wallet_group_light.png and /dev/null differ
diff --git a/assets/images/wallet_group_options_dark.png b/assets/images/wallet_group_options_dark.png
new file mode 100644
index 000000000..479aac57c
Binary files /dev/null and b/assets/images/wallet_group_options_dark.png differ
diff --git a/assets/images/wallet_group_options_light.png b/assets/images/wallet_group_options_light.png
new file mode 100644
index 000000000..308930520
Binary files /dev/null and b/assets/images/wallet_group_options_light.png differ
diff --git a/assets/images/wallet_name.png b/assets/images/wallet_name.png
deleted file mode 100644
index f586682bd..000000000
Binary files a/assets/images/wallet_name.png and /dev/null differ
diff --git a/assets/images/wallet_name_light.png b/assets/images/wallet_name_light.png
deleted file mode 100644
index 0199c1b30..000000000
Binary files a/assets/images/wallet_name_light.png and /dev/null differ
diff --git a/assets/images/wallet_type.png b/assets/images/wallet_type.png
deleted file mode 100644
index 4e0eba8b5..000000000
Binary files a/assets/images/wallet_type.png and /dev/null differ
diff --git a/assets/images/wallet_type_light.png b/assets/images/wallet_type_light.png
deleted file mode 100644
index e36c0d3aa..000000000
Binary files a/assets/images/wallet_type_light.png and /dev/null differ
diff --git a/assets/images/wallet_type_wallet_dark.png b/assets/images/wallet_type_wallet_dark.png
new file mode 100644
index 000000000..b840f5547
Binary files /dev/null and b/assets/images/wallet_type_wallet_dark.png differ
diff --git a/assets/images/wallet_type_wallet_light.png b/assets/images/wallet_type_wallet_light.png
new file mode 100644
index 000000000..ee759a109
Binary files /dev/null and b/assets/images/wallet_type_wallet_light.png differ
diff --git a/assets/images/wallets.png b/assets/images/wallets.png
new file mode 100644
index 000000000..62ea20039
Binary files /dev/null and b/assets/images/wallets.png differ
diff --git a/assets/images/welcome.png b/assets/images/welcome.png
deleted file mode 100644
index f1132d253..000000000
Binary files a/assets/images/welcome.png and /dev/null differ
diff --git a/assets/images/welcome_dark_theme.svg b/assets/images/welcome_dark_theme.svg
new file mode 100644
index 000000000..8f60c931a
--- /dev/null
+++ b/assets/images/welcome_dark_theme.svg
@@ -0,0 +1,215 @@
+
diff --git a/assets/images/welcome_light.png b/assets/images/welcome_light.png
deleted file mode 100644
index 6feff85d1..000000000
Binary files a/assets/images/welcome_light.png and /dev/null differ
diff --git a/assets/images/welcome_light_theme.svg b/assets/images/welcome_light_theme.svg
new file mode 100644
index 000000000..178b2853d
--- /dev/null
+++ b/assets/images/welcome_light_theme.svg
@@ -0,0 +1,14 @@
+
diff --git a/assets/images/welcome_wallet_dark.png b/assets/images/welcome_wallet_dark.png
new file mode 100644
index 000000000..771a600d3
Binary files /dev/null and b/assets/images/welcome_wallet_dark.png differ
diff --git a/assets/images/welcome_wallet_light.png b/assets/images/welcome_wallet_light.png
new file mode 100644
index 000000000..2a738be0b
Binary files /dev/null and b/assets/images/welcome_wallet_light.png differ
diff --git a/assets/images/wyre-icon.png b/assets/images/wyre-icon.png
deleted file mode 100644
index a2810948e..000000000
Binary files a/assets/images/wyre-icon.png and /dev/null differ
diff --git a/assets/images/wyre.png b/assets/images/wyre.png
deleted file mode 100644
index a16bbdc8b..000000000
Binary files a/assets/images/wyre.png and /dev/null differ
diff --git a/assets/images/yat_crypto.png b/assets/images/yat_crypto.png
deleted file mode 100644
index fbd5d2483..000000000
Binary files a/assets/images/yat_crypto.png and /dev/null differ
diff --git a/assets/text/Monerocom_Release_Notes.txt b/assets/text/Monerocom_Release_Notes.txt
index 852e6ad0d..faf57258a 100644
--- a/assets/text/Monerocom_Release_Notes.txt
+++ b/assets/text/Monerocom_Release_Notes.txt
@@ -1,4 +1,4 @@
-Background sync improvements
-Payment notifications
+Add built-in Tor support (experimental)
+Ledger improvements
UI/UX improvements
Bug fixes
\ No newline at end of file
diff --git a/assets/text/Release_Notes.txt b/assets/text/Release_Notes.txt
index c766c39ff..c49b895e3 100644
--- a/assets/text/Release_Notes.txt
+++ b/assets/text/Release_Notes.txt
@@ -1,5 +1,9 @@
-Background sync improvements
-Payment notifications
-WalletConnect enhancements
+Add built-in Tor support (experimental)
+Add dEuro investments
+Solana fixes/enhancements
+Polygon fixes/enhancements
+WalletConnect improvements
+Ledger improvements
+Payjoin improvements
UI/UX improvements
Bug fixes
\ No newline at end of file
diff --git a/cw_bitcoin/lib/address_from_output.dart b/cw_bitcoin/lib/address_from_output.dart
index e726217f5..0d985b237 100644
--- a/cw_bitcoin/lib/address_from_output.dart
+++ b/cw_bitcoin/lib/address_from_output.dart
@@ -20,6 +20,7 @@ BitcoinBaseAddress addressFromScript(Script script,
return P2pkhAddress.fromScriptPubkey(
script: script, network: BitcoinNetwork.mainnet);
case P2shAddressType.p2pkhInP2sh:
+ case P2shAddressType.p2pkInP2sh:
return P2shAddress.fromScriptPubkey(
script: script, network: BitcoinNetwork.mainnet);
case SegwitAddresType.p2wpkh:
diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart
index a23b72660..9231022f6 100644
--- a/cw_bitcoin/lib/bitcoin_wallet.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet.dart
@@ -266,6 +266,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
derivationPath: walletInfo.derivationInfo!.derivationPath!);
}
+ @override
+ Future close({bool shouldCleanup = false}) async {
+ payjoinManager.cleanupSessions();
+ super.close(shouldCleanup: shouldCleanup);
+ }
+
late final PayjoinManager payjoinManager;
bool get isPayjoinAvailable => unspentCoinsInfo.values
diff --git a/cw_bitcoin/lib/bitcoin_wallet_addresses.dart b/cw_bitcoin/lib/bitcoin_wallet_addresses.dart
index 0fefe4e57..d84d958be 100644
--- a/cw_bitcoin/lib/bitcoin_wallet_addresses.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet_addresses.dart
@@ -31,12 +31,10 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
final PayjoinManager payjoinManager;
- @observable
payjoin.Receiver? currentPayjoinReceiver;
- @computed
- String? get payjoinEndpoint =>
- currentPayjoinReceiver?.pjUriBuilder().build().pjEndpoint();
+ @observable
+ String? payjoinEndpoint = null;
@override
String getAddress(
@@ -59,16 +57,32 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
return generateP2WPKHAddress(hd: hd, index: index, network: network);
}
+ @action
Future initPayjoin() async {
- currentPayjoinReceiver = await payjoinManager.initReceiver(primaryAddress);
-
- payjoinManager.resumeSessions();
+ try {
+ await payjoinManager.initPayjoin();
+ currentPayjoinReceiver = await payjoinManager.getUnusedReceiver(primaryAddress);
+ payjoinEndpoint = (await currentPayjoinReceiver?.pjUri())?.pjEndpoint();
+
+ payjoinManager.resumeSessions();
+ } catch (e) {
+ printV(e);
+ // Ignore Connectivity errors
+ if (!e.toString().contains("error sending request for url")) rethrow;
+ }
}
+ @action
Future newPayjoinReceiver() async {
- currentPayjoinReceiver = await payjoinManager.initReceiver(primaryAddress);
+ try {
+ currentPayjoinReceiver = await payjoinManager.getUnusedReceiver(primaryAddress);
+ payjoinEndpoint = (await currentPayjoinReceiver?.pjUri())?.pjEndpoint();
- printV("Initializing new Payjoin Receiver");
- payjoinManager.spawnNewReceiver(receiver: currentPayjoinReceiver!);
+ payjoinManager.spawnReceiver(receiver: currentPayjoinReceiver!);
+ } catch (e) {
+ printV(e);
+ // Ignore Connectivity errors
+ if (!e.toString().contains("error sending request for url")) rethrow;
+ }
}
}
diff --git a/cw_bitcoin/lib/electrum.dart b/cw_bitcoin/lib/electrum.dart
index 1f5c369e3..2ddd30df6 100644
--- a/cw_bitcoin/lib/electrum.dart
+++ b/cw_bitcoin/lib/electrum.dart
@@ -5,6 +5,8 @@ import 'dart:typed_data';
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
import 'package:cw_core/utils/print_verbose.dart';
+import 'package:cw_core/utils/proxy_socket/abstract.dart';
+import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:flutter/foundation.dart';
import 'package:rxdart/rxdart.dart';
@@ -42,7 +44,7 @@ class ElectrumClient {
static const aliveTimerDuration = Duration(seconds: 4);
bool get isConnected => _isConnected;
- Socket? socket;
+ ProxySocket? socket;
void Function(ConnectionStatus)? onConnectionStatusChange;
int _id;
final Map _tasks;
@@ -72,18 +74,11 @@ class ElectrumClient {
} catch (_) {}
socket = null;
+ final ssl = !(useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum")));
try {
- if (useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum"))) {
- socket = await Socket.connect(host, port, timeout: connectionTimeout);
- } else {
- socket = await SecureSocket.connect(
- host,
- port,
- timeout: connectionTimeout,
- onBadCertificate: (_) => true,
- );
- }
+ socket = await ProxyWrapper().getSocksSocket(ssl, host, port, connectionTimeout: connectionTimeout);
} catch (e) {
+ printV("connect: $e");
if (e is HandshakeException) {
useSSL = !(useSSL ?? false);
}
@@ -105,7 +100,6 @@ class ElectrumClient {
// use ping to determine actual connection status since we could've just not timed out yet:
// _setConnectionStatus(ConnectionStatus.connected);
-
socket!.listen(
(Uint8List event) {
try {
diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart
index 35c15682c..bb9cea1bc 100644
--- a/cw_bitcoin/lib/electrum_wallet.dart
+++ b/cw_bitcoin/lib/electrum_wallet.dart
@@ -4,6 +4,7 @@ import 'dart:io';
import 'dart:isolate';
import 'package:bitcoin_base/bitcoin_base.dart';
+import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
import 'package:cw_core/format_amount.dart';
import 'package:cw_core/utils/print_verbose.dart';
@@ -49,7 +50,6 @@ import 'package:mobx/mobx.dart';
import 'package:rxdart/subjects.dart';
import 'package:sp_scanner/sp_scanner.dart';
import 'package:hex/hex.dart';
-import 'package:http/http.dart' as http;
part 'electrum_wallet.g.dart';
@@ -493,10 +493,9 @@ abstract class ElectrumWalletBase
Future updateFeeRates() async {
if (await checkIfMempoolAPIIsEnabled() && type == WalletType.bitcoin) {
try {
- final response = await http
- .get(Uri.parse("https://mempool.cakewallet.com/api/v1/fees/recommended"))
- .timeout(Duration(seconds: 5));
-
+ final response = await ProxyWrapper()
+ .get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/fees/recommended"))
+ .timeout(Duration(seconds: 15));
final result = json.decode(response.body) as Map;
final slowFee = (result['economyFee'] as num?)?.toInt() ?? 0;
int mediumFee = (result['hourFee'] as num?)?.toInt() ?? 0;
@@ -1176,20 +1175,18 @@ abstract class ElectrumWalletBase
}
});
- return PendingBitcoinTransaction(
- transaction,
- type,
- electrumClient: electrumClient,
- amount: estimatedTx.amount,
- fee: estimatedTx.fee,
- feeRate: feeRateInt.toString(),
- network: network,
- hasChange: estimatedTx.hasChange,
- isSendAll: estimatedTx.isSendAll,
- hasTaprootInputs: hasTaprootInputs,
- utxos: estimatedTx.utxos,
- publicKeys: estimatedTx.publicKeys
- )..addListener((transaction) async {
+ return PendingBitcoinTransaction(transaction, type,
+ electrumClient: electrumClient,
+ amount: estimatedTx.amount,
+ fee: estimatedTx.fee,
+ feeRate: feeRateInt.toString(),
+ network: network,
+ hasChange: estimatedTx.hasChange,
+ isSendAll: estimatedTx.isSendAll,
+ hasTaprootInputs: hasTaprootInputs,
+ utxos: estimatedTx.utxos,
+ publicKeys: estimatedTx.publicKeys)
+ ..addListener((transaction) async {
transactionHistory.addOne(transaction);
if (estimatedTx.spendsSilentPayment) {
transactionHistory.transactions.values.forEach((tx) {
@@ -1880,20 +1877,17 @@ abstract class ElectrumWalletBase
if (height != null && height > 0 && await checkIfMempoolAPIIsEnabled()) {
try {
- final blockHash = await http.get(
- Uri.parse(
- "https://mempool.cakewallet.com/api/v1/block-height/$height",
- ),
- );
+ final blockHash = await ProxyWrapper()
+ .get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/block-height/$height"))
+ .timeout(Duration(seconds: 15));
if (blockHash.statusCode == 200 &&
blockHash.body.isNotEmpty &&
jsonDecode(blockHash.body) != null) {
- final blockResponse = await http.get(
- Uri.parse(
- "https://mempool.cakewallet.com/api/v1/block/${blockHash.body}",
- ),
- );
+ final blockResponse = await ProxyWrapper()
+ .get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/block/${blockHash}"))
+ .timeout(Duration(seconds: 15));
+
if (blockResponse.statusCode == 200 &&
blockResponse.body.isNotEmpty &&
jsonDecode(blockResponse.body)['timestamp'] != null) {
diff --git a/cw_bitcoin/lib/litecoin_wallet.dart b/cw_bitcoin/lib/litecoin_wallet.dart
index 662d70d67..08c56c600 100644
--- a/cw_bitcoin/lib/litecoin_wallet.dart
+++ b/cw_bitcoin/lib/litecoin_wallet.dart
@@ -464,7 +464,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
final oldBox = await CakeHive.openBox(oldBoxName);
mwebUtxosBox = await CakeHive.openBox(newBoxName);
for (final key in oldBox.keys) {
- await mwebUtxosBox.put(key, oldBox.get(key)!);
+ final value = oldBox.get(key);
+ await oldBox.delete(key);
+ await mwebUtxosBox.put(key, value!);
}
oldBox.deleteFromDisk();
diff --git a/cw_bitcoin/lib/payjoin/manager.dart b/cw_bitcoin/lib/payjoin/manager.dart
index b80fa777c..95a523d89 100644
--- a/cw_bitcoin/lib/payjoin/manager.dart
+++ b/cw_bitcoin/lib/payjoin/manager.dart
@@ -6,6 +6,7 @@ import 'dart:typed_data';
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:cw_bitcoin/bitcoin_wallet.dart';
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
+import 'package:cw_bitcoin/payjoin/payjoin_persister.dart';
import 'package:cw_bitcoin/payjoin/payjoin_receive_worker.dart';
import 'package:cw_bitcoin/payjoin/payjoin_send_worker.dart';
import 'package:cw_bitcoin/payjoin/payjoin_session_errors.dart';
@@ -16,6 +17,7 @@ import 'package:cw_core/utils/print_verbose.dart';
import 'package:payjoin_flutter/common.dart';
import 'package:payjoin_flutter/receive.dart';
import 'package:payjoin_flutter/send.dart';
+import 'package:payjoin_flutter/src/config.dart' as pj_config;
import 'package:payjoin_flutter/uri.dart' as PayjoinUri;
class PayjoinManager {
@@ -28,13 +30,16 @@ class PayjoinManager {
static const List ohttpRelayUrls = [
'https://pj.bobspacebkk.com',
'https://ohttp.achow101.com',
+ 'https://ohttp.cakewallet.com',
];
- static Future randomOhttpRelayUrl() => PayjoinUri.Url.fromStr(
- ohttpRelayUrls[Random.secure().nextInt(ohttpRelayUrls.length)]);
+ static String randomOhttpRelayUrl() =>
+ ohttpRelayUrls[Random.secure().nextInt(ohttpRelayUrls.length)];
static const payjoinDirectoryUrl = 'https://payjo.in';
+ Future initPayjoin() => pj_config.PConfig.initializeApp();
+
Future resumeSessions() async {
final allSessions = _payjoinStorage.readAllOpenSessions(_wallet.id);
@@ -42,13 +47,13 @@ class PayjoinManager {
if (session.isSenderSession) {
printV("Resuming Payjoin Sender Session ${session.pjUri!}");
return _spawnSender(
- sender: Sender.fromJson(session.sender!),
+ sender: Sender.fromJson(json: session.sender!),
pjUri: session.pjUri!,
);
}
- final receiver = Receiver.fromJson(session.receiver!);
+ final receiver = Receiver.fromJson(json: session.receiver!);
printV("Resuming Payjoin Receiver Session ${receiver.id()}");
- return _spawnReceiver(receiver: receiver);
+ return spawnReceiver(receiver: receiver);
});
printV("Resumed ${spawnedSessions.length} Payjoin Sessions");
@@ -65,7 +70,12 @@ class PayjoinManager {
psbtBase64: originalPsbt,
pjUri: pjUri,
);
- return senderBuilder.buildRecommended(minFeeRate: minFeeRateSatPerKwu);
+ final persister = PayjoinSenderPersister.impl();
+ final newSender =
+ await senderBuilder.buildRecommended(minFeeRate: minFeeRateSatPerKwu);
+ final senderToken = await newSender.persist(persister: persister);
+
+ return Sender.load(token: senderToken, persister: persister);
} catch (e) {
throw Exception('Error initializing Payjoin Sender: $e');
}
@@ -111,15 +121,13 @@ class PayjoinManager {
}
} catch (e) {
_cleanupSession(pjUri);
- printV(e);
- await _payjoinStorage.markSenderSessionUnrecoverable(pjUri);
- completer.completeError(e);
+ await _payjoinStorage.markSenderSessionUnrecoverable(pjUri, e.toString());
+ completer.complete();
}
} else if (message is PayjoinSessionError) {
_cleanupSession(pjUri);
if (message is UnrecoverableError) {
- printV(message.message);
- await _payjoinStorage.markSenderSessionUnrecoverable(pjUri);
+ await _payjoinStorage.markSenderSessionUnrecoverable(pjUri, message.message);
completer.complete();
} else if (message is RecoverableError) {
completer.complete();
@@ -139,42 +147,41 @@ class PayjoinManager {
return completer.future;
}
- Future initReceiver(String address,
+ Future getUnusedReceiver(String address,
[bool isTestnet = false]) async {
- try {
- final payjoinDirectory =
- await PayjoinUri.Url.fromStr(payjoinDirectoryUrl);
+ final session = _payjoinStorage.getUnusedActiveReceiverSession(_wallet.id);
- final ohttpKeys = await PayjoinUri.fetchOhttpKeys(
- ohttpRelay: await randomOhttpRelayUrl(),
- payjoinDirectory: payjoinDirectory,
- );
+ if (session != null) {
+ await PayjoinUri.Url.fromStr(payjoinDirectoryUrl);
- final receiver = await Receiver.create(
- address: address,
- network: isTestnet ? Network.testnet : Network.bitcoin,
- directory: payjoinDirectory,
- ohttpKeys: ohttpKeys,
- ohttpRelay: await randomOhttpRelayUrl(),
- );
-
- await _payjoinStorage.insertReceiverSession(receiver, _wallet.id);
-
- return receiver;
- } catch (e) {
- throw Exception('Error initializing Payjoin Receiver: $e');
+ return Receiver.fromJson(json: session.receiver!);
}
+
+ return initReceiver(address);
}
- Future spawnNewReceiver({
- required Receiver receiver,
- bool isTestnet = false,
- }) async {
+ Future initReceiver(String address, [bool isTestnet = false]) async {
+ final ohttpKeys = await PayjoinUri.fetchOhttpKeys(
+ ohttpRelay: await randomOhttpRelayUrl(),
+ payjoinDirectory: payjoinDirectoryUrl,
+ );
+
+ final newReceiver = await NewReceiver.create(
+ address: address,
+ network: isTestnet ? Network.testnet : Network.bitcoin,
+ directory: payjoinDirectoryUrl,
+ ohttpKeys: ohttpKeys,
+ );
+ final persister = PayjoinReceiverPersister.impl();
+ final receiverToken = await newReceiver.persist(persister: persister);
+ final receiver = await Receiver.load(persister: persister, token: receiverToken);
+
await _payjoinStorage.insertReceiverSession(receiver, _wallet.id);
- return _spawnReceiver(isTestnet: isTestnet, receiver: receiver);
+
+ return receiver;
}
- Future _spawnReceiver({
+ Future spawnReceiver({
required Receiver receiver,
bool isTestnet = false,
}) async {
@@ -194,7 +201,8 @@ class PayjoinManager {
rawAmount = getOutputAmountFromTx(tx, _wallet);
break;
case PayjoinReceiverRequestTypes.checkIsOwned:
- (_wallet.walletAddresses as BitcoinWalletAddresses).newPayjoinReceiver();
+ (_wallet.walletAddresses as BitcoinWalletAddresses)
+ .newPayjoinReceiver();
_payjoinStorage.markReceiverSessionInProgress(receiver.id());
final inputScript = message['input_script'] as Uint8List;
@@ -218,6 +226,10 @@ class PayjoinManager {
case PayjoinReceiverRequestTypes.getCandidateInputs:
utxos = _wallet.getUtxoWithPrivateKeys();
+ if (utxos.isEmpty) {
+ await _wallet.updateAllUnspents();
+ utxos = _wallet.getUtxoWithPrivateKeys();
+ }
mainToIsolateSendPort?.send({
'requestId': message['requestId'],
'result': utxos,
diff --git a/cw_bitcoin/lib/payjoin/payjoin_persister.dart b/cw_bitcoin/lib/payjoin/payjoin_persister.dart
new file mode 100644
index 000000000..4e395e36a
--- /dev/null
+++ b/cw_bitcoin/lib/payjoin/payjoin_persister.dart
@@ -0,0 +1,66 @@
+import 'package:payjoin_flutter/src/generated/api/receive.dart';
+import 'package:payjoin_flutter/src/generated/api/send.dart';
+
+class PayjoinSenderPersister implements DartSenderPersister {
+ static DartSenderPersister impl() {
+ final impl = PayjoinSenderPersister();
+ return DartSenderPersister(
+ save: (sender) => impl.save(sender: sender),
+ load: (token) => impl.load(token: token),
+ );
+ }
+
+ final Map _store = {};
+
+ Future save({required FfiSender sender}) async {
+ final token = sender.key();
+ _store[token.toBytes().toString()] = sender;
+ return token;
+ }
+
+ Future load({required SenderToken token}) async {
+ final sender = _store[token.toBytes().toString()];
+ if (sender == null) {
+ throw Exception('Sender not found for the provided token.');
+ }
+ return sender;
+ }
+
+ @override
+ void dispose() => _store.clear();
+
+ @override
+ bool get isDisposed => _store.isEmpty;
+}
+
+class PayjoinReceiverPersister implements DartReceiverPersister {
+ static DartReceiverPersister impl() {
+ final impl = PayjoinReceiverPersister();
+ return DartReceiverPersister(
+ save: (receiver) => impl.save(receiver: receiver),
+ load: (token) => impl.load(token: token),
+ );
+ }
+
+ final Map _store = {};
+
+ Future save({required FfiReceiver receiver}) async {
+ final token = receiver.key();
+ _store[token.toBytes().toString()] = receiver;
+ return token;
+ }
+
+ Future load({required ReceiverToken token}) async {
+ final receiver = _store[token.toBytes().toString()];
+ if (receiver == null) {
+ throw Exception('Receiver not found for the provided token.');
+ }
+ return receiver;
+ }
+
+ @override
+ void dispose() => _store.clear();
+
+ @override
+ bool get isDisposed => _store.isEmpty;
+}
diff --git a/cw_bitcoin/lib/payjoin/payjoin_receive_worker.dart b/cw_bitcoin/lib/payjoin/payjoin_receive_worker.dart
index a499660b0..c56148de2 100644
--- a/cw_bitcoin/lib/payjoin/payjoin_receive_worker.dart
+++ b/cw_bitcoin/lib/payjoin/payjoin_receive_worker.dart
@@ -4,14 +4,16 @@ import 'dart:isolate';
import 'dart:typed_data';
import 'package:blockchain_utils/blockchain_utils.dart';
+import 'package:cw_bitcoin/payjoin/manager.dart';
import 'package:cw_bitcoin/payjoin/payjoin_session_errors.dart';
import 'package:cw_bitcoin/psbt/signer.dart';
import 'package:cw_core/utils/print_verbose.dart';
-import 'package:http/http.dart' as http;
+import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:payjoin_flutter/bitcoin_ffi.dart';
import 'package:payjoin_flutter/common.dart';
import 'package:payjoin_flutter/receive.dart';
import 'package:payjoin_flutter/src/generated/frb_generated.dart' as pj;
+import 'package:http/http.dart' as very_insecure_http_do_not_use; // for errors
enum PayjoinReceiverRequestTypes {
processOriginalTx,
@@ -27,7 +29,7 @@ class PayjoinReceiverWorker {
final pendingRequests = >{};
PayjoinReceiverWorker._(this.sendPort);
-
+ static final client = ProxyWrapper().getHttpIOClient();
static Future run(List