diff --git a/.github/workflows/automated_integration_test.yml b/.github/workflows/automated_integration_test.yml
index 47b08c44d..84c680dda 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.0"
+ flutter-version: "3.27.4"
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 changeNowCakeWalletApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
- echo "const changeNowMoneroApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> 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 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,7 +168,6 @@ 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
@@ -179,8 +178,7 @@ 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 exolixCakeWalletApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
- echo "const exolixMoneroApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const exolixApiKey = '${{ 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
deleted file mode 100644
index dad6821ac..000000000
--- a/.github/workflows/no_http_imports.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-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 507793bd8..9c3d82bc2 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 f7c226ce4..8f6139747 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.0-go1.24.1-ruststablenightly
+ image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1
env:
STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet
@@ -98,8 +98,8 @@ jobs:
else
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
fi
- 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 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 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,7 +113,6 @@ 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
@@ -125,8 +124,7 @@ 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 exolixCakeWalletApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
- echo "const exolixMoneroApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const exolixApiKey = '${{ 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
@@ -255,11 +253,6 @@ 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 f057b19e5..476a033a0 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.0-go1.24.1-ruststablenightly
+ image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1
env:
STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet
@@ -91,8 +91,8 @@ jobs:
else
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
fi
- 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 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 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,7 +106,6 @@ 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
@@ -118,8 +117,7 @@ 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 exolixCakeWalletApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
- echo "const exolixMoneroApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const exolixApiKey = '${{ 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 151b7af20..84179d645 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.0-go1.24.1-ruststablenightly
+# docker buildx build --push --pull --platform linux/amd64,linux/arm64 . -f Dockerfile -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1
# Heavily inspired by cirrusci images
# https://github.com/cirruslabs/docker-images-android/blob/master/sdk/tools/Dockerfile
@@ -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.0
+ENV FLUTTER_VERSION=3.27.4
# 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=13114758
+ENV ANDROID_SDK_TOOLS_VERSION=11076708
# Comes from https://developer.android.com/studio/releases/build-tools
ENV ANDROID_PLATFORM_VERSION=35
ENV ANDROID_BUILD_TOOLS_VERSION=34.0.0
@@ -164,12 +164,9 @@ 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 $toolchain $target; \
- done \
+ rustup target add --toolchain stable $target; \
done
# Download and install Flutter
@@ -178,11 +175,8 @@ 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 --branch ${FLUTTER_VERSION} https://github.com/flutter/flutter.git ${FLUTTER_HOME} && \
- cd ${FLUTTER_HOME} && \
- git fetch -a
-
-RUN yes | flutter doctor --android-licenses \
+RUN git clone --depth 1 --branch ${FLUTTER_VERSION} https://github.com/flutter/flutter.git ${FLUTTER_HOME} \
+ && yes | flutter doctor --android-licenses \
&& flutter doctor \
&& chown -R root:root ${FLUTTER_HOME}
diff --git a/assets/images/history.svg b/assets/images/history.svg
deleted file mode 100644
index f308ab7e3..000000000
--- a/assets/images/history.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-
diff --git a/assets/images/notif.svg b/assets/images/notif.svg
deleted file mode 100644
index b1ff5b4fa..000000000
--- a/assets/images/notif.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/assets/images/qr-cake.png b/assets/images/qr-cake.png
deleted file mode 100644
index 7c54dedb0..000000000
Binary files a/assets/images/qr-cake.png and /dev/null differ
diff --git a/assets/images/tor_logo.svg b/assets/images/tor_logo.svg
deleted file mode 100644
index ebd00324d..000000000
--- a/assets/images/tor_logo.svg
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
-
diff --git a/assets/images/usdtbsc_icon.png b/assets/images/usdtbsc_icon.png
deleted file mode 100644
index 9f2cda237..000000000
Binary files a/assets/images/usdtbsc_icon.png and /dev/null differ
diff --git a/assets/text/Monerocom_Release_Notes.txt b/assets/text/Monerocom_Release_Notes.txt
index faf57258a..1176d3d8c 100644
--- a/assets/text/Monerocom_Release_Notes.txt
+++ b/assets/text/Monerocom_Release_Notes.txt
@@ -1,4 +1,3 @@
-Add built-in Tor support (experimental)
-Ledger improvements
-UI/UX improvements
+New themes and UI/UX improvements
+Ledger flow enhancements
Bug fixes
\ No newline at end of file
diff --git a/assets/text/Release_Notes.txt b/assets/text/Release_Notes.txt
index c49b895e3..6afc88fa1 100644
--- a/assets/text/Release_Notes.txt
+++ b/assets/text/Release_Notes.txt
@@ -1,9 +1,4 @@
-Add built-in Tor support (experimental)
-Add dEuro investments
-Solana fixes/enhancements
-Polygon fixes/enhancements
-WalletConnect improvements
-Ledger improvements
-Payjoin improvements
-UI/UX improvements
+New themes and UI/UX improvements
+Payjoin enhancements
+Ledger flow enhancements
Bug fixes
\ No newline at end of file
diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart
index 9231022f6..a23b72660 100644
--- a/cw_bitcoin/lib/bitcoin_wallet.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet.dart
@@ -266,12 +266,6 @@ 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 d84d958be..0fefe4e57 100644
--- a/cw_bitcoin/lib/bitcoin_wallet_addresses.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet_addresses.dart
@@ -31,10 +31,12 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
final PayjoinManager payjoinManager;
+ @observable
payjoin.Receiver? currentPayjoinReceiver;
- @observable
- String? payjoinEndpoint = null;
+ @computed
+ String? get payjoinEndpoint =>
+ currentPayjoinReceiver?.pjUriBuilder().build().pjEndpoint();
@override
String getAddress(
@@ -57,32 +59,16 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
return generateP2WPKHAddress(hd: hd, index: index, network: network);
}
- @action
Future initPayjoin() async {
- 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;
- }
+ currentPayjoinReceiver = await payjoinManager.initReceiver(primaryAddress);
+
+ payjoinManager.resumeSessions();
}
- @action
Future newPayjoinReceiver() async {
- try {
- currentPayjoinReceiver = await payjoinManager.getUnusedReceiver(primaryAddress);
- payjoinEndpoint = (await currentPayjoinReceiver?.pjUri())?.pjEndpoint();
+ currentPayjoinReceiver = await payjoinManager.initReceiver(primaryAddress);
- payjoinManager.spawnReceiver(receiver: currentPayjoinReceiver!);
- } catch (e) {
- printV(e);
- // Ignore Connectivity errors
- if (!e.toString().contains("error sending request for url")) rethrow;
- }
+ printV("Initializing new Payjoin Receiver");
+ payjoinManager.spawnNewReceiver(receiver: currentPayjoinReceiver!);
}
}
diff --git a/cw_bitcoin/lib/electrum.dart b/cw_bitcoin/lib/electrum.dart
index 2ddd30df6..1f5c369e3 100644
--- a/cw_bitcoin/lib/electrum.dart
+++ b/cw_bitcoin/lib/electrum.dart
@@ -5,8 +5,6 @@ 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';
@@ -44,7 +42,7 @@ class ElectrumClient {
static const aliveTimerDuration = Duration(seconds: 4);
bool get isConnected => _isConnected;
- ProxySocket? socket;
+ Socket? socket;
void Function(ConnectionStatus)? onConnectionStatusChange;
int _id;
final Map _tasks;
@@ -74,11 +72,18 @@ class ElectrumClient {
} catch (_) {}
socket = null;
- final ssl = !(useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum")));
try {
- socket = await ProxyWrapper().getSocksSocket(ssl, host, port, connectionTimeout: connectionTimeout);
+ 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,
+ );
+ }
} catch (e) {
- printV("connect: $e");
if (e is HandshakeException) {
useSSL = !(useSSL ?? false);
}
@@ -100,6 +105,7 @@ 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 bb9cea1bc..35c15682c 100644
--- a/cw_bitcoin/lib/electrum_wallet.dart
+++ b/cw_bitcoin/lib/electrum_wallet.dart
@@ -4,7 +4,6 @@ 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';
@@ -50,6 +49,7 @@ 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,9 +493,10 @@ abstract class ElectrumWalletBase
Future updateFeeRates() async {
if (await checkIfMempoolAPIIsEnabled() && type == WalletType.bitcoin) {
try {
- final response = await ProxyWrapper()
- .get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/fees/recommended"))
- .timeout(Duration(seconds: 15));
+ final response = await http
+ .get(Uri.parse("https://mempool.cakewallet.com/api/v1/fees/recommended"))
+ .timeout(Duration(seconds: 5));
+
final result = json.decode(response.body) as Map;
final slowFee = (result['economyFee'] as num?)?.toInt() ?? 0;
int mediumFee = (result['hourFee'] as num?)?.toInt() ?? 0;
@@ -1175,18 +1176,20 @@ 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) {
@@ -1877,17 +1880,20 @@ abstract class ElectrumWalletBase
if (height != null && height > 0 && await checkIfMempoolAPIIsEnabled()) {
try {
- final blockHash = await ProxyWrapper()
- .get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/block-height/$height"))
- .timeout(Duration(seconds: 15));
+ final blockHash = await http.get(
+ Uri.parse(
+ "https://mempool.cakewallet.com/api/v1/block-height/$height",
+ ),
+ );
if (blockHash.statusCode == 200 &&
blockHash.body.isNotEmpty &&
jsonDecode(blockHash.body) != null) {
- final blockResponse = await ProxyWrapper()
- .get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/block/${blockHash}"))
- .timeout(Duration(seconds: 15));
-
+ final blockResponse = await http.get(
+ Uri.parse(
+ "https://mempool.cakewallet.com/api/v1/block/${blockHash.body}",
+ ),
+ );
if (blockResponse.statusCode == 200 &&
blockResponse.body.isNotEmpty &&
jsonDecode(blockResponse.body)['timestamp'] != null) {
diff --git a/cw_bitcoin/lib/payjoin/manager.dart b/cw_bitcoin/lib/payjoin/manager.dart
index 95a523d89..7ba3ceb9b 100644
--- a/cw_bitcoin/lib/payjoin/manager.dart
+++ b/cw_bitcoin/lib/payjoin/manager.dart
@@ -6,7 +6,6 @@ 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';
@@ -17,7 +16,6 @@ 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 {
@@ -33,13 +31,11 @@ class PayjoinManager {
'https://ohttp.cakewallet.com',
];
- static String randomOhttpRelayUrl() =>
- ohttpRelayUrls[Random.secure().nextInt(ohttpRelayUrls.length)];
+ static Future randomOhttpRelayUrl() => PayjoinUri.Url.fromStr(
+ 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);
@@ -47,13 +43,13 @@ class PayjoinManager {
if (session.isSenderSession) {
printV("Resuming Payjoin Sender Session ${session.pjUri!}");
return _spawnSender(
- sender: Sender.fromJson(json: session.sender!),
+ sender: Sender.fromJson(session.sender!),
pjUri: session.pjUri!,
);
}
- final receiver = Receiver.fromJson(json: session.receiver!);
+ final receiver = Receiver.fromJson(session.receiver!);
printV("Resuming Payjoin Receiver Session ${receiver.id()}");
- return spawnReceiver(receiver: receiver);
+ return _spawnReceiver(receiver: receiver);
});
printV("Resumed ${spawnedSessions.length} Payjoin Sessions");
@@ -70,12 +66,7 @@ class PayjoinManager {
psbtBase64: originalPsbt,
pjUri: pjUri,
);
- 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);
+ return senderBuilder.buildRecommended(minFeeRate: minFeeRateSatPerKwu);
} catch (e) {
throw Exception('Error initializing Payjoin Sender: $e');
}
@@ -121,13 +112,15 @@ class PayjoinManager {
}
} catch (e) {
_cleanupSession(pjUri);
- await _payjoinStorage.markSenderSessionUnrecoverable(pjUri, e.toString());
- completer.complete();
+ printV(e);
+ await _payjoinStorage.markSenderSessionUnrecoverable(pjUri);
+ completer.completeError(e);
}
} else if (message is PayjoinSessionError) {
_cleanupSession(pjUri);
if (message is UnrecoverableError) {
- await _payjoinStorage.markSenderSessionUnrecoverable(pjUri, message.message);
+ printV(message.message);
+ await _payjoinStorage.markSenderSessionUnrecoverable(pjUri);
completer.complete();
} else if (message is RecoverableError) {
completer.complete();
@@ -147,41 +140,42 @@ class PayjoinManager {
return completer.future;
}
- Future getUnusedReceiver(String address,
+ Future initReceiver(String address,
[bool isTestnet = false]) async {
- final session = _payjoinStorage.getUnusedActiveReceiverSession(_wallet.id);
+ try {
+ final payjoinDirectory =
+ await PayjoinUri.Url.fromStr(payjoinDirectoryUrl);
- if (session != null) {
- await PayjoinUri.Url.fromStr(payjoinDirectoryUrl);
+ final ohttpKeys = await PayjoinUri.fetchOhttpKeys(
+ ohttpRelay: await randomOhttpRelayUrl(),
+ payjoinDirectory: payjoinDirectory,
+ );
- return Receiver.fromJson(json: session.receiver!);
+ 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 initReceiver(address);
}
- 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);
-
+ Future spawnNewReceiver({
+ required Receiver receiver,
+ bool isTestnet = false,
+ }) async {
await _payjoinStorage.insertReceiverSession(receiver, _wallet.id);
-
- return receiver;
+ return _spawnReceiver(isTestnet: isTestnet, receiver: receiver);
}
- Future spawnReceiver({
+ Future _spawnReceiver({
required Receiver receiver,
bool isTestnet = false,
}) async {
@@ -201,8 +195,7 @@ 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;
@@ -226,10 +219,6 @@ 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
deleted file mode 100644
index 4e395e36a..000000000
--- a/cw_bitcoin/lib/payjoin/payjoin_persister.dart
+++ /dev/null
@@ -1,66 +0,0 @@
-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 c56148de2..a499660b0 100644
--- a/cw_bitcoin/lib/payjoin/payjoin_receive_worker.dart
+++ b/cw_bitcoin/lib/payjoin/payjoin_receive_worker.dart
@@ -4,16 +4,14 @@ 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:cw_core/utils/proxy_wrapper.dart';
+import 'package:http/http.dart' as http;
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,
@@ -29,7 +27,7 @@ class PayjoinReceiverWorker {
final pendingRequests = >{};
PayjoinReceiverWorker._(this.sendPort);
- static final client = ProxyWrapper().getHttpIOClient();
+
static Future run(List