What changed, and why it matters
This commit fixes a logic bug in how Stack Wallet decides whether to use an Epicbox server or an HTTP/HTTPS receiver when sending Epic Cash transactions. The old code used OR instead of AND when checking for HTTP/HTTPS prefixes, which meant every receiver address was treated as needing an Epicbox check. The new code cleanly separates the two paths and adds a unit test to confirm HTTP/HTTPS addresses bypass Epicbox while email-style Epicbox addresses use it.
Review whether the always-true condition caused any user-facing transaction failures or unexpected Epicbox dependency. Consider backporting this cleanup to stable releases and verifying that HTTP/HTTPS Epic Cash sends now skip the Epicbox check as intended. No immediate emergency response appears necessary.
Security signals we found
Logic bug in protocol routing condition (OR instead of AND)
Unnecessary Epicbox connectivity check for HTTP/HTTPS receivers
Potential transaction failure or unexpected network behavior due to incorrect path selection
Added unit test for routing behavior
Evidence from the diff
In lib/wallets/wallet/impl/epiccash_wallet.dart, the confirmSend method previously tested !receiverAddress.startsWith("http://") || !receiverAddress.startsWith("https://"). Because a string cannot start with both prefixes, this condition was always true, causing the wallet to always call _testEpicboxServer before sending. The patch introduces a helper shouldCheckEpicbox(String receiverAddress) => !isHttpAddress(receiverAddress) and uses it to branch correctly: Epicbox addresses get the connectivity check, HTTP/HTTPS addresses go through libEpic.txHttpSend. A new test file verifies the routing logic.
Changed components
lib/wallets/wallet/impl/epiccash_wallet.dartEpic Cash send/confirmSend flowEpicbox server connectivity checkHTTP/HTTPS receiver routingInspect captured patch +22 / −5
diff --git a/lib/wallets/wallet/impl/epiccash_wallet.dart b/lib/wallets/wallet/impl/epiccash_wallet.dart
index 3746a48..805ea30 100644
--- a/lib/wallets/wallet/impl/epiccash_wallet.dart
+++ b/lib/wallets/wallet/impl/epiccash_wallet.dart
@@ -3,6 +3,7 @@ import 'dart:convert';
import 'dart:io';
import 'package:decimal/decimal.dart';
+import 'package:flutter/foundation.dart';
import 'package:isar_community/isar.dart';
import 'package:mutex/mutex.dart';
import 'package:stack_wallet_backup/generate_password.dart';
@@ -931,18 +932,22 @@ class EpiccashWallet extends Bip39Wallet {
return await super.init();
}
+ @visibleForTesting
+ bool shouldCheckEpicbox(String receiverAddress) =>
+ !isHttpAddress(receiverAddress);
+
@override
Future<TxData> confirmSend({required TxData txData}) async {
try {
_hackedCheckTorNodePrefs();
- final EpicBoxConfigModel epicboxConfig = await getEpicBoxConfig();
// TODO determine whether it is worth sending change to a change address.
final String receiverAddress = txData.recipients!.first.address;
+ final useEpicbox = shouldCheckEpicbox(receiverAddress);
- if (!receiverAddress.startsWith("http://") ||
- !receiverAddress.startsWith("https://")) {
+ if (useEpicbox) {
+ final epicboxConfig = await getEpicBoxConfig();
final bool isEpicboxConnected = await _testEpicboxServer(epicboxConfig);
if (!isEpicboxConnected) {
throw Exception("Failed to send TX : Unable to reach epicbox server");
@@ -951,8 +956,7 @@ class EpiccashWallet extends Bip39Wallet {
({String commitId, String slateId, String slateJson}) transaction;
- if (receiverAddress.startsWith("http://") ||
- receiverAddress.startsWith("https://")) {
+ if (!useEpicbox) {
final httpResult = await libEpic.txHttpSend(
wallet: _wallet!,
selectionStrategyIsAll: 0,
diff --git a/test/wallets/epiccash_routing_test.dart b/test/wallets/epiccash_routing_test.dart
new file mode 100644
index 0000000..2b56d64
--- /dev/null
+++ b/test/wallets/epiccash_routing_test.dart
@@ -0,0 +1,13 @@
+import 'package:flutter_test/flutter_test.dart';
+import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
+import 'package:stackwallet/wallets/wallet/impl/epiccash_wallet.dart';
+
+void main() {
+ test('HTTP receivers bypass Epicbox', () {
+ final wallet = EpiccashWallet(CryptoCurrencyNetwork.main);
+
+ expect(wallet.shouldCheckEpicbox('http://receiver'), isFalse);
+ expect(wallet.shouldCheckEpicbox('https://receiver'), isFalse);
+ expect(wallet.shouldCheckEpicbox('user@epicbox.example'), isTrue);
+ });
+}
Why this scored 29/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.