What changed, and why it matters
This commit appears to be a routine bug-fix and polish update for a Monero light wallet app. It fixes a broken wallet-delete routine (the old code compared a variable to null instead of actually setting it to null), improves connection status display, adds a timeout to stats loading, and ensures Tor is ready before fetching blockchain height. There is no clear security vulnerability being patched, and no vendor disclosure or researcher attribution is present.
Treat as a normal maintenance commit. Reviewers may want to verify the delete() fix actually clears the wallet object and that the 20-second timeout and Tor wait behavior do not introduce usability issues. No urgent security action is indicated by the diff alone.
Security signals we found
Fixed dangling wallet reference after deletion (_w2Wallet = null instead of _w2Wallet == null)
Added timeout to stats loading to prevent indefinite hangs during sync
Added Tor readiness wait before querying remote blockchain height
Added SSL scheme prefix to daemon address based on useSsl flag
Added connection error logging from FFI wallet
Evidence from the diff
The diff is a mixed bag of small fixes in a Flutter/Dart Monero wallet. Notable changes: (1) wallet_model.dart fixes _w2Wallet == null to _w2Wallet = null during delete(), which previously failed to null out the wallet reference and could leave a dangling object. (2) It adds _hasAttemptedConnection state and a derived getter, plus refactors wallet_home.dart to use an LwsConnectionStatus enum instead of inline boolean logic. (3) It adds a 20-second timeout to loadAllStats() inside the periodic sync loop and calls store() only when connected, synced, and txCount > 0. (4) It removes two redundant notifyListenersFromOutside() calls in main.dart. (5) It adds await TorService.sharedInstance.waitUntilConnected() before fetching blockchain height. (6) It prefixes daemon address with http:// or https:// based on useSsl. (7) It adds a debug print('im still alive 1/2') and logs wallet connection errors. No explicit security fix or advisory is stated.
Changed components
lib/models/wallet_model.dartlib/screens/wallet_home.dartlib/screens/generate_seed.dartlib/util/height.dartlib/main.dartInspect captured patch +55 / −32
diff --git a/lib/main.dart b/lib/main.dart
index caf9885..8d00931 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -81,9 +81,7 @@ class MyApp extends StatelessWidget {
(() async {
await wallet.refresh();
await wallet.loadAllStats();
- wallet.notifyListenersFromOutside();
await wallet.connectToDaemon();
- wallet.notifyListenersFromOutside();
})();
}
diff --git a/lib/models/wallet_model.dart b/lib/models/wallet_model.dart
index 92bf764..2e651f5 100644
--- a/lib/models/wallet_model.dart
+++ b/lib/models/wallet_model.dart
@@ -9,6 +9,7 @@ import 'dart:io';
import 'dart:isolate';
import 'dart:math';
import 'package:flutter/foundation.dart';
+import 'package:shared_preferences/shared_preferences.dart';
import 'package:monero_light_wallet/consts.dart';
import 'package:monero_light_wallet/services/shared_preferences_service.dart';
@@ -20,7 +21,6 @@ import 'package:monero_light_wallet/util/wallet.dart';
import 'package:monero/monero.dart' as monero;
import 'package:monero/src/monero.dart';
import 'package:monero/src/wallet2.dart';
-import 'package:shared_preferences/shared_preferences.dart';
String generateHexString(int length) {
final Random random = Random.secure();
@@ -137,6 +137,7 @@ class WalletModel with ChangeNotifier {
late bool _connectionUseTor;
late bool _connectionUseSsl;
+ var _hasAttemptedConnection = false;
var _isConnected = false;
var _isSynced = false;
int? _syncedHeight;
@@ -145,6 +146,7 @@ class WalletModel with ChangeNotifier {
List<TxDetails>? _txHistory = [];
Wallet2Wallet? get w2Wallet => _w2Wallet;
+ bool get hasAttemptedConnection => _hasAttemptedConnection;
bool get isConnected => _isConnected;
bool get isSynced => _isSynced;
int? get syncedHeight => _syncedHeight;
@@ -178,6 +180,8 @@ class WalletModel with ChangeNotifier {
return;
}
+ print('im still alive 1');
+
final isConnected = await getIsConnected();
if (isConnected != _isConnected) {
@@ -191,9 +195,16 @@ class WalletModel with ChangeNotifier {
return;
}
+ print('im still alive 2');
+
await refresh();
- await loadAllStats();
- notifyListeners();
+ await loadAllStats().timeout(Duration(seconds: 20));
+
+ final txCount = _w2TxHistory!.count();
+
+ if (_isConnected && _isSynced && txCount > 0) {
+ await store();
+ }
}
Future<void> loadAllStats() async {
@@ -204,6 +215,8 @@ class WalletModel with ChangeNotifier {
loadTotalBalance(),
_loadTxHistory(),
]);
+
+ notifyListeners();
}
Future<void> _loadTxHistory() async {
@@ -315,6 +328,8 @@ class WalletModel with ChangeNotifier {
useSsl: _connectionUseSsl,
);
+ _hasAttemptedConnection = true;
+
notifyListeners();
}
@@ -324,13 +339,14 @@ class WalletModel with ChangeNotifier {
bool useSsl = false,
}) async {
final walletFfiAddr = _w2Wallet!.ffiAddress();
+ final proxyAddress = proxyPort != '' ? '127.0.0.1:$proxyPort' : '';
await Isolate.run(
// ignore: deprecated_member_use
() => monero.Wallet_init(
Pointer.fromAddress(walletFfiAddr),
- daemonAddress: address,
- proxyAddress: proxyPort != '' ? '127.0.0.1:$proxyPort' : '',
+ daemonAddress: '${useSsl ? 'https://' : 'http://'}$address',
+ proxyAddress: proxyAddress,
useSsl: useSsl,
lightWallet: true,
),
@@ -340,6 +356,12 @@ class WalletModel with ChangeNotifier {
// ignore: deprecated_member_use
() => monero.Wallet_connectToDaemon(Pointer.fromAddress(walletFfiAddr)),
);
+
+ final connectError = _w2Wallet!.errorString();
+
+ if (connectError != '') {
+ log(LogLevel.warn, connectError);
+ }
}
Future<void> refresh() async {
@@ -496,10 +518,9 @@ class WalletModel with ChangeNotifier {
Future delete() async {
_w2WalletManager.closeWallet(_w2Wallet!, false);
- _w2Wallet == null;
+ _w2Wallet = null;
final path = await getWalletPath();
- final walletFile = File(path);
- await walletFile.delete();
+ await File(path).delete();
final prefs = await SharedPreferences.getInstance();
prefs.remove('txHistoryCount');
diff --git a/lib/screens/generate_seed.dart b/lib/screens/generate_seed.dart
index f283880..f25dc4d 100644
--- a/lib/screens/generate_seed.dart
+++ b/lib/screens/generate_seed.dart
@@ -57,9 +57,11 @@ class _GenerateSeedScreenState extends State<GenerateSeedScreen> {
try {
final height = await getCurrentBlockchainHeight();
- setState(() {
- _restoreHeight = height;
- });
+ if (mounted) {
+ setState(() {
+ _restoreHeight = height;
+ });
+ }
} catch (error) {
var errorMsg = 'Sorry, something went wrong.';
diff --git a/lib/screens/wallet_home.dart b/lib/screens/wallet_home.dart
index 96606d2..283ee81 100644
--- a/lib/screens/wallet_home.dart
+++ b/lib/screens/wallet_home.dart
@@ -18,6 +18,8 @@ import 'package:monero_light_wallet/models/wallet_model.dart';
import 'package:monero_light_wallet/consts.dart' as consts;
import 'package:monero_light_wallet/widgets/wallet_navigation_bar.dart';
+enum LwsConnectionStatus { disconnected, connecting, connected }
+
class WalletHomeScreen extends StatefulWidget {
const WalletHomeScreen({super.key});
@@ -94,11 +96,19 @@ class _WalletHomeScreenState extends State<WalletHomeScreen> {
final lockedBalance =
(wallet.totalBalance ?? 0) - (wallet.unlockedBalance ?? 0);
final fiatSymbol = fiatRate.fiatCode == 'EUR' ? '€' : '\$';
+ var connectionStatus = LwsConnectionStatus.disconnected;
- print(wallet.isConnected);
- print(wallet.isSynced);
- print(wallet.syncedHeight);
- print('----');
+ if (wallet.isConnected &&
+ wallet.isSynced &&
+ (wallet.syncedHeight ?? 0) > 0) {
+ connectionStatus = LwsConnectionStatus.connected;
+ } else if (wallet.usingTor &&
+ TorService.sharedInstance.status ==
+ TorConnectionStatus.connecting ||
+ !wallet.hasAttemptedConnection ||
+ wallet.isConnected && !wallet.isSynced) {
+ connectionStatus = LwsConnectionStatus.connecting;
+ }
return Scaffold(
bottomNavigationBar: WalletNavigationBar(selectedIndex: 0),
@@ -123,9 +133,8 @@ class _WalletHomeScreenState extends State<WalletHomeScreen> {
child: Column(
spacing: 10,
children: [
- if (wallet.isConnected &&
- wallet.isSynced &&
- wallet.syncedHeight != 0)
+ if (connectionStatus ==
+ LwsConnectionStatus.connected)
SizedBox(
width: 26,
height: 26,
@@ -136,13 +145,8 @@ class _WalletHomeScreenState extends State<WalletHomeScreen> {
),
),
- // TODO: make dis better
- if ((wallet.usingTor &&
- TorService.sharedInstance.status ==
- TorConnectionStatus.connecting) ||
- wallet.isConnected &&
- (!wallet.isSynced ||
- wallet.syncedHeight == 0))
+ if (connectionStatus ==
+ LwsConnectionStatus.connecting)
SizedBox(
width: 22,
height: 22,
@@ -155,11 +159,8 @@ class _WalletHomeScreenState extends State<WalletHomeScreen> {
),
),
- if (wallet.usingTor
- ? TorService.sharedInstance.status !=
- TorConnectionStatus.connecting &&
- !wallet.isConnected
- : !wallet.isConnected)
+ if (connectionStatus ==
+ LwsConnectionStatus.disconnected)
SizedBox(
width: 26,
height: 26,
diff --git a/lib/util/height.dart b/lib/util/height.dart
index bba0ff3..3348367 100644
--- a/lib/util/height.dart
+++ b/lib/util/height.dart
@@ -15,6 +15,7 @@ Future<int> getCurrentBlockchainHeight() async {
urls.shuffle(Random.secure());
+ await TorService.sharedInstance.waitUntilConnected();
final proxyInfo = TorService.sharedInstance.getProxyInfo();
for (String url in urls) {
Why this scored 31/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.