add extra check to nano interface account info parsing
What changed, and why it matters
This commit tightens how Stack Wallet parses account information for Nano cryptocurrency sends. Previously, if the Nano node returned an error or a malformed balance, the code could crash or behave unpredictably. Now it explicitly checks for error responses and invalid balance values before continuing. This is a defensive hardening fix that prevents bad node responses from causing app crashes or incorrect send calculations.
Review whether other RPC response parsers in the wallet interface code perform similar error/balance validation, and consider applying the same pattern consistently. No immediate user action appears necessary beyond updating to a version containing this fix.
Security signals we found
Input validation added to RPC/node response parsing
Missing or malformed balance now handled explicitly instead of throwing raw FormatException
Error field from upstream Nano node now checked before balance parsing
Unit tests added for error and malformed balance cases
Evidence from the diff
The parseNanoSendState function in nano_interface.dart now checks accountInfo["error"] and uses BigInt.tryParse on the balance field, throwing descriptive exceptions if either is invalid. Previously it directly called BigInt.parse(accountInfo["balance"].toString()), which would throw a FormatException if the balance was missing or malformed, and it ignored any error field in the response. The patch adds two unit tests covering error and malformed responses.
Changed components
lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dartNano wallet send flowparseNanoSendState functionInspect captured patch +20 / −1
diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart
index 1fbe4fb..1b12d1e 100644
--- a/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart
+++ b/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart
@@ -39,7 +39,13 @@ Map<String, String> _buildHeaders(String url) {
({String frontier, String representative, BigInt balanceAfterSend})
parseNanoSendState(Map<String, dynamic> accountInfo, BigInt sendAmount) {
- final liveBalance = BigInt.parse(accountInfo["balance"].toString());
+ if (accountInfo["error"] != null) {
+ throw Exception("account_info error: ${accountInfo["error"]}");
+ }
+ final liveBalance = BigInt.tryParse(accountInfo["balance"].toString());
+ if (liveBalance == null) {
+ throw Exception("Invalid account_info balance");
+ }
if (sendAmount > liveBalance) {
throw Exception("Insufficient balance");
}
diff --git a/test/wallets/nano_interface_test.dart b/test/wallets/nano_interface_test.dart
index d80968f..ca57ba5 100644
--- a/test/wallets/nano_interface_test.dart
+++ b/test/wallets/nano_interface_test.dart
@@ -17,4 +17,17 @@ void main() {
throwsException,
);
});
+
+ test('Nano send state surfaces error and malformed responses clearly', () {
+ expect(
+ () => parseNanoSendState({'error': 'Account not found'}, BigInt.one),
+ throwsA(predicate((e) => e.toString().contains('Account not found'))),
+ );
+ expect(
+ () => parseNanoSendState({}, BigInt.one),
+ throwsA(
+ predicate((e) => e.toString().contains('Invalid account_info balance')),
+ ),
+ );
+ });
}
Why this scored 45/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.