Firo: recognize Spark V2 spend transactions
What changed, and why it matters
This commit updates the Stack Wallet app so it can correctly identify a newer kind of Firo cryptocurrency transaction (Spark V2 spends, type 11) in addition to the older Spark V1 spends (type 9). Before this change, the wallet only recognized type 9 as a spend, so a type-11 spend might have been misclassified or mishandled in the user's transaction history and balance calculations. There is no direct evidence in the commit that this misclassification could be exploited by an attacker to steal funds, but it is a correctness fix that could affect balance display and user trust.
Treat as a routine wallet-correctness fix. Review whether the prior misclassification of Spark V2 spends could have caused any balance or transaction-history issues for users, and consider whether additional transaction types need similar recognition. No urgent security patch is indicated by the diff alone.
Security signals we found
Transaction-type parsing logic changed to recognize additional spend type
Potential prior misclassification of Spark V2 spends could affect balance/UX
No input validation, cryptography, or authorization changes visible
No vendor disclosure of security relevance in commit or supplied references
Evidence from the diff
The change extracts the Spark spend detection logic into a new helper isSparkSpendTransaction() in lib/wallets/wallet/impl/firo_transaction_type.dart. The predicate now returns true when version == 3 and type is either 9 (Spark V1 spend) or 11 (Spark V2 spend), whereas the previous inline check only matched type == 9. FiroWallet now imports and uses this helper. A unit test verifies the four cases: types 9 and 11 with version 3 are recognized; type 10 and version 2/type 11 are not.
Changed components
lib/wallets/wallet/impl/firo_transaction_type.dartlib/wallets/wallet/impl/firo_wallet.darttest/wallets/firo_transaction_type_test.dartInspect captured patch +17 / −1
diff --git a/lib/wallets/wallet/impl/firo_transaction_type.dart b/lib/wallets/wallet/impl/firo_transaction_type.dart
new file mode 100644
index 0000000..501ae00
--- /dev/null
+++ b/lib/wallets/wallet/impl/firo_transaction_type.dart
@@ -0,0 +1,4 @@
+bool isSparkSpendTransaction(Map<String, dynamic> transaction) {
+ final type = transaction['type'];
+ return transaction['version'] == 3 && (type == 9 || type == 11);
+}
diff --git a/lib/wallets/wallet/impl/firo_wallet.dart b/lib/wallets/wallet/impl/firo_wallet.dart
index 34c68c2..ea27514 100644
--- a/lib/wallets/wallet/impl/firo_wallet.dart
+++ b/lib/wallets/wallet/impl/firo_wallet.dart
@@ -30,6 +30,7 @@ import '../wallet_mixin_interfaces/coin_control_interface.dart';
import '../wallet_mixin_interfaces/electrumx_interface.dart';
import '../wallet_mixin_interfaces/extended_keys_interface.dart';
import '../wallet_mixin_interfaces/spark_interface.dart';
+import 'firo_transaction_type.dart';
class MasternodeInfo {
final String proTxHash;
@@ -332,7 +333,7 @@ class FiroWallet<T extends ElectrumXCurrencyInterface> extends Bip39HDWallet<T>
bool isMint = false;
bool isJMint = false;
bool isSparkMint = false;
- final bool isSparkSpend = txData["type"] == 9 && txData["version"] == 3;
+ final bool isSparkSpend = isSparkSpendTransaction(txData);
final bool isMySpark = sparkTxids.contains(txData["txid"] as String);
final bool isMySpentSpark = missing
.where((e) => e.txid == txData["txid"])
diff --git a/test/wallets/firo_transaction_type_test.dart b/test/wallets/firo_transaction_type_test.dart
new file mode 100644
index 0000000..89abfa3
--- /dev/null
+++ b/test/wallets/firo_transaction_type_test.dart
@@ -0,0 +1,11 @@
+import 'package:flutter_test/flutter_test.dart';
+import 'package:paymint/wallets/wallet/impl/firo_transaction_type.dart';
+
+void main() {
+ test('recognizes Spark spend transaction types', () {
+ expect(isSparkSpendTransaction({'version': 3, 'type': 9}), isTrue);
+ expect(isSparkSpendTransaction({'version': 3, 'type': 11}), isTrue);
+ expect(isSparkSpendTransaction({'version': 3, 'type': 10}), isFalse);
+ expect(isSparkSpendTransaction({'version': 2, 'type': 11}), isFalse);
+ });
+}
Why this scored 23/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.