Remove replaced electrum transactions (#2738)
What changed, and why it matters
This commit changes how Cake Wallet's Bitcoin wallet handles transaction history from Electrum servers. When refreshing balances, it now deletes any stored Bitcoin transactions that send to the wallet's address but are no longer returned by the Electrum server. The stated goal is to remove transactions that were replaced or invalidated, such as RBF (Replace-By-Fee) replacements. This is a data-cleanup fix, but it could affect what transactions the user sees and what the wallet believes is spendable.
Review whether relying solely on Electrum server history to delete local transactions is safe. Consider adding checks for transaction age, confirmation depth, or local user intent before deletion. Ensure the change does not hide legitimate unconfirmed transactions when Electrum servers are slow, pruned, or malicious. Test RBF and reorg scenarios. If this addresses a reported bug, document the issue and any coordinated disclosure.
Security signals we found
Transaction history desynchronization between local wallet state and Electrum server
Potential removal of valid but unconfirmed transactions if server omits them
RBF/replacement transaction handling gap
Server-trusting logic: local state is altered based solely on Electrum server response
No explicit safeguards against malicious or faulty Electrum server omitting transactions
Evidence from the diff
In cw_bitcoin/lib/electrum_wallet.dart, during transaction history synchronization, the code now calls transactionHistory.transactions.removeWhere(…) only when this is a BitcoinWallet. It removes entries whose outputAddresses include the current address and whose tx_hash is absent from the Electrum server’s getHistory response. This is intended to purge replaced/invalid transactions. The patch is narrow: it only runs for BitcoinWallet, only checks outputAddresses, and only removes if the txid is missing from the server response. It does not add confirmation checks, reorg handling, or broader transaction validation.
Changed components
cw_bitcoin/lib/electrum_wallet.dartBitcoinWallet transaction history synchronizationElectrum client history parsingInspect captured patch +11 / −0
diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart
index a285ff97..298ccc5d 100644
--- a/cw_bitcoin/lib/electrum_wallet.dart
+++ b/cw_bitcoin/lib/electrum_wallet.dart
@@ -2311,10 +2311,21 @@ abstract class ElectrumWalletBase
final history = await electrumClient.getHistory(addressRecord.getScriptHash(network));
+
if (history.isNotEmpty) {
addressRecord.setAsUsed();
walletAddresses.clearLockIfMatches(addressRecord.type, addressRecord.address);
+ if(this is BitcoinWallet) {
+ //removes transactions no longer returned by the api, presumed replaced/invalid.
+ transactionHistory.transactions.removeWhere(
+ (hash, tx) =>
+ tx.outputAddresses != null &&
+ tx.outputAddresses!.contains(addressRecord.address) &&
+ !history.any((newTransaction) => newTransaction['tx_hash'] == hash),
+ );
+ }
+
await Future.wait(history.map((transaction) async {
txid = transaction['tx_hash'] as String;
final height = transaction['height'] as int;
Why this scored 35/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.