feat: warn when txCount != 1 (#3644)
What changed, and why it matters
This commit adds a safety check in Cake Wallet's Monero wallet code. When a user tries to send Monero, the app now checks how many separate transactions would be created. If it is not exactly one transaction, the app stops and warns the user instead of proceeding. This appears to prevent a situation where a payment unexpectedly splits into multiple transactions, which could confuse users or cause funds to move in unintended ways.
Treat as a hardening/defensive fix. Review whether multi-output transactions are a legitimate use case that should be supported rather than blocked. If blocking is intentional, ensure the error message is localized and that the app handles the exception gracefully in the UI. Consider restoring or replacing the removed status check for completeness.
Security signals we found
Defensive guard added against multi-transaction payment splits
User-facing error thrown instead of silent multi-tx execution
Previously commented-out status check not restored
Partial mitigation: blocks rather than correctly handles txCount > 1
Evidence from the diff
The change threads a new txCount field from the Monero FFI pending transaction description through to the wallet layer. After creating a transaction, MoneroWalletBase.createTransaction now throws MoneroTransactionCreationException if pendingTransactionDescription.txCount != 1, instructing the user to first send a smaller transaction to themselves. The previously commented-out status check remains removed. The patch is defensive but partial: it blocks multi-tx payments rather than handling them, and the warning text is user-facing rather than a robust fix.
Changed components
cw_monero/lib/api/structs/pending_transaction.dartcw_monero/lib/api/transaction_history.dartcw_monero/lib/monero_wallet.dartInspect captured patch +9 / −2
### cw_monero/lib/api/structs/pending_transaction.dart
@@ -4,11 +4,13 @@ class PendingTransactionDescription {
required this.fee,
required this.hash,
required this.hex,
- required this.pointerAddress});
+ required this.pointerAddress,
+ required this.txCount});
final int amount;
final int fee;
final String hash;
final String hex;
final int pointerAddress;
+ final int txCount;
}
### cw_monero/lib/api/transaction_history.dart
@@ -219,6 +219,7 @@ Future<PendingTransactionDescription> createTransactionSync(
fee: rFee,
hash: rHash,
hex: rHex,
+ txCount: pendingTx.txCount(),
pointerAddress: pendingTx.ffiAddress(),
);
}
@@ -263,6 +264,7 @@ Future<PendingTransactionDescription> createTransactionMultDest(
hash: tx.txid(''),
hex: tx.hex(''),
pointerAddress: tx.ffiAddress(),
+ txCount: tx.txCount(),
);
}
### cw_monero/lib/monero_wallet.dart
@@ -491,7 +491,10 @@ abstract class MoneroWalletBase
paymentId: '');
}
- // final status = monero.PendingTransaction_status(pendingTransactionDescription);
+ if (pendingTransactionDescription.txCount != 1) {
+ throw MoneroTransactionCreationException(
+ "This payment would be split into ${pendingTransactionDescription.txCount} transactions. Send smaller transaction to yourself first.",);
+ }
return PendingMoneroTransaction(pendingTransactionDescription, this);
}Why this scored 57/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.