From 59621d6098fc04bef0a1a37969e4f864a4ecd5a9 Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 May 2025 18:14:33 -0600 Subject: [PATCH 01/11] demo --- .../wallet/intermediate/lib_monero_wallet.dart | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/wallets/wallet/intermediate/lib_monero_wallet.dart b/lib/wallets/wallet/intermediate/lib_monero_wallet.dart index b81a10d97..9e2661311 100644 --- a/lib/wallets/wallet/intermediate/lib_monero_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_monero_wallet.dart @@ -478,9 +478,16 @@ abstract class LibMoneroWallet }); } + // dumb temporary hack + bool _canPing = false; + @override Future pingCheck() async { - return (await libMoneroWallet?.isConnectedToDaemon()) ?? false; + if (_canPing) { + return (await libMoneroWallet?.isConnectedToDaemon()) ?? false; + } else { + return false; + } } @override @@ -490,8 +497,10 @@ abstract class LibMoneroWallet final host = node.host.endsWith(".onion") ? node.host : Uri.parse(node.host).host; ({InternetAddress host, int port})? proxy; + _canPing = true; if (prefs.useTor) { if (node.clearnetEnabled && !node.torEnabled) { + _canPing = false; libMoneroWallet?.stopAutoSaving(); libMoneroWallet?.stopListeners(); libMoneroWallet?.stopSyncing(); @@ -501,6 +510,7 @@ abstract class LibMoneroWallet proxy = TorService.sharedInstance.getProxyInfo(); } else { if (!node.clearnetEnabled && node.torEnabled) { + _canPing = false; libMoneroWallet?.stopAutoSaving(); libMoneroWallet?.stopListeners(); libMoneroWallet?.stopSyncing(); @@ -1087,8 +1097,10 @@ abstract class LibMoneroWallet final node = getCurrentNode(); + _canPing = true; if (prefs.useTor) { if (node.clearnetEnabled && !node.torEnabled) { + _canPing = false; libMoneroWallet?.stopAutoSaving(); libMoneroWallet?.stopListeners(); libMoneroWallet?.stopSyncing(); @@ -1097,6 +1109,7 @@ abstract class LibMoneroWallet } } else { if (!node.clearnetEnabled && node.torEnabled) { + _canPing = false; libMoneroWallet?.stopAutoSaving(); libMoneroWallet?.stopListeners(); libMoneroWallet?.stopSyncing(); From 0f32556f095f48fff24ec64dcbee90d151b4ba75 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 2 Jun 2025 10:03:30 -0600 Subject: [PATCH 02/11] primary node flag --- lib/models/node_model.dart | 6 ++++++ lib/models/type_adaptors/node_model.g.dart | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/models/node_model.dart b/lib/models/node_model.dart index 530c2a0c2..1224d7e5b 100644 --- a/lib/models/node_model.dart +++ b/lib/models/node_model.dart @@ -45,6 +45,8 @@ class NodeModel { final bool clearnetEnabled; // @HiveField(13) final bool forceNoTor; + // @HiveField(14) + final bool isPrimary; NodeModel({ required this.host, @@ -58,6 +60,7 @@ class NodeModel { required this.isDown, required this.torEnabled, required this.clearnetEnabled, + required this.isPrimary, this.forceNoTor = false, this.loginName, this.trusted, @@ -77,6 +80,7 @@ class NodeModel { bool? torEnabled, bool? forceNoTor, bool? clearnetEnabled, + bool? isPrimary, }) { return NodeModel( host: host ?? this.host, @@ -93,6 +97,7 @@ class NodeModel { torEnabled: torEnabled ?? this.torEnabled, clearnetEnabled: clearnetEnabled ?? this.clearnetEnabled, forceNoTor: forceNoTor ?? this.forceNoTor, + isPrimary: isPrimary ?? this.isPrimary, ); } @@ -117,6 +122,7 @@ class NodeModel { map['torEnabled'] = torEnabled; map['clearEnabled'] = clearnetEnabled; map['forceNoTor'] = forceNoTor; + map['isPrimary'] = isPrimary; return map; } diff --git a/lib/models/type_adaptors/node_model.g.dart b/lib/models/type_adaptors/node_model.g.dart index 381091edd..218731a69 100644 --- a/lib/models/type_adaptors/node_model.g.dart +++ b/lib/models/type_adaptors/node_model.g.dart @@ -31,13 +31,14 @@ class NodeModelAdapter extends TypeAdapter { torEnabled: fields[11] as bool? ?? true, clearnetEnabled: fields[12] as bool? ?? true, forceNoTor: fields[13] as bool? ?? false, + isPrimary: fields[14] as bool? ?? false, ); } @override void write(BinaryWriter writer, NodeModel obj) { writer - ..writeByte(14) + ..writeByte(15) ..writeByte(0) ..write(obj.id) ..writeByte(1) @@ -65,7 +66,9 @@ class NodeModelAdapter extends TypeAdapter { ..writeByte(12) ..write(obj.clearnetEnabled) ..writeByte(13) - ..write(obj.forceNoTor); + ..write(obj.forceNoTor) + ..writeByte(14) + ..write(obj.isPrimary); } @override From 0f54f975f11b2e3de7f4dbbc1c2269d83210178f Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 2 Jun 2025 10:13:54 -0600 Subject: [PATCH 03/11] WIP remove store primary nodes separately. Still requires SWB changes as well as a db migration with version update --- lib/services/node_service.dart | 100 +++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 41 deletions(-) diff --git a/lib/services/node_service.dart b/lib/services/node_service.dart index 35f595050..1657cfa78 100644 --- a/lib/services/node_service.dart +++ b/lib/services/node_service.dart @@ -27,9 +27,7 @@ class NodeService extends ChangeNotifier { final SecureStorageInterface secureStorageInterface; /// Exposed [secureStorageInterface] in order to inject mock for tests - NodeService({ - required this.secureStorageInterface, - }); + NodeService({required this.secureStorageInterface}); Future updateDefaults() async { // hack @@ -64,6 +62,7 @@ class NodeService extends ChangeNotifier { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: false, ); await DB.instance.put( @@ -75,17 +74,15 @@ class NodeService extends ChangeNotifier { } } - for (final defaultNode in AppConfig.coins.map( - (e) => e.defaultNode, - )) { - final savedNode = DB.instance - .get(boxName: DB.boxNameNodeModels, key: defaultNode.id); + for (final defaultNode in AppConfig.coins.map((e) => e.defaultNode)) { + final savedNode = DB.instance.get( + boxName: DB.boxNameNodeModels, + key: defaultNode.id, + ); if (savedNode == null) { // save the default node to hive only if no other nodes for the specific coin exist if (getNodesFor( - AppConfig.getCryptoCurrencyByPrettyName( - defaultNode.coinName, - ), + AppConfig.getCryptoCurrencyByPrettyName(defaultNode.coinName), ).isEmpty) { await DB.instance.put( boxName: DB.boxNameNodeModels, @@ -111,8 +108,9 @@ class NodeService extends ChangeNotifier { // check if a default node is the primary node for the crypto currency // and update it if needed - final coin = - AppConfig.getCryptoCurrencyByPrettyName(defaultNode.coinName); + final coin = AppConfig.getCryptoCurrencyByPrettyName( + defaultNode.coinName, + ); final primaryNode = getPrimaryNodeFor(currency: coin); if (primaryNode != null && primaryNode.id == defaultNode.id) { await setPrimaryNodeFor( @@ -135,25 +133,48 @@ class NodeService extends ChangeNotifier { required NodeModel node, bool shouldNotifyListeners = false, }) async { - await DB.instance.put( - boxName: DB.boxNamePrimaryNodes, - key: coin.identifier, - value: node, + // current + final currentPrimaries = primaryNodes.where( + (e) => e.coinName == coin.identifier && e.id != node.id, ); + final List toStore = []; + for (final node in currentPrimaries) { + final updated = node.copyWith( + loginName: node.loginName, + trusted: node.trusted, + isPrimary: false, + ); + toStore.add(updated); + } + toStore.add( + node.copyWith( + loginName: node.loginName, + trusted: node.trusted, + isPrimary: true, + ), + ); + + for (final node in toStore) { + await DB.instance.put( + boxName: DB.boxNameNodeModels, + key: node.id, + value: node, + ); + } + if (shouldNotifyListeners) { notifyListeners(); } } NodeModel? getPrimaryNodeFor({required CryptoCurrency currency}) { - return DB.instance.get( - boxName: DB.boxNamePrimaryNodes, - key: currency.identifier, - ); + return primaryNodes + .where((e) => e.coinName == currency.identifier) + .firstOrNull; } List get primaryNodes { - return DB.instance.values(boxName: DB.boxNamePrimaryNodes); + return nodes.where((e) => e.isPrimary).toList(); } List get nodes { @@ -161,14 +182,15 @@ class NodeService extends ChangeNotifier { } List getNodesFor(CryptoCurrency coin) { - final list = DB.instance - .values(boxName: DB.boxNameNodeModels) - .where( - (e) => - e.coinName == coin.identifier && - !e.id.startsWith(DefaultNodes.defaultNodeIdPrefix), - ) - .toList(); + final list = + DB.instance + .values(boxName: DB.boxNameNodeModels) + .where( + (e) => + e.coinName == coin.identifier && + !e.id.startsWith(DefaultNodes.defaultNodeIdPrefix), + ) + .toList(); // add default to end of list list.addAll( @@ -191,9 +213,9 @@ class NodeService extends ChangeNotifier { } List failoverNodesFor({required CryptoCurrency currency}) { - return getNodesFor(currency) - .where((e) => e.isFailover && !e.isDown) - .toList(); + return getNodesFor( + currency, + ).where((e) => e.isFailover && !e.isDown).toList(); } // should probably just combine this and edit into a save() func at some point @@ -237,10 +259,8 @@ class NodeService extends ChangeNotifier { bool enabled, bool shouldNotifyListeners, ) async { - final model = DB.instance.get( - boxName: DB.boxNameNodeModels, - key: id, - )!; + final model = + DB.instance.get(boxName: DB.boxNameNodeModels, key: id)!; await DB.instance.put( boxName: DB.boxNameNodeModels, key: model.id, @@ -284,10 +304,7 @@ class NodeService extends ChangeNotifier { final response = await client.post( uri, headers: {'Content-Type': 'application/json'}, - body: jsonEncode({ - "jsonrpc": "2.0", - "id": "0", - }), + body: jsonEncode({"jsonrpc": "2.0", "id": "0"}), ); final json = jsonDecode(response.body) as Map; @@ -312,6 +329,7 @@ class NodeService extends ChangeNotifier { torEnabled: nodeMap["torEnabled"] == "true", isDown: nodeMap["isDown"] == "true", clearnetEnabled: nodeMap["plainEnabled"] == "true", + isPrimary: nodeMap["plainEnabled"] == "true", ); final currentNode = getNodeById(id: nodeMap["id"] as String); if (currentNode != null) { From 905c64b131276e72e1f40f23ce2b0cc038d40a78 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 2 Jun 2025 12:22:12 -0600 Subject: [PATCH 04/11] migrate primary nodes --- lib/db/db_version_migration.dart | 40 ++++++++++++++++ lib/db/hive/db.dart | 80 ++++++++++++++++---------------- lib/utilities/constants.dart | 2 +- test/hive/db_test.dart | 44 +++++++++++------- 4 files changed, 106 insertions(+), 60 deletions(-) diff --git a/lib/db/db_version_migration.dart b/lib/db/db_version_migration.dart index 8ef1f2bb5..2e5ebf219 100644 --- a/lib/db/db_version_migration.dart +++ b/lib/db/db_version_migration.dart @@ -19,6 +19,7 @@ import '../models/isar/models/blockchain_data/address.dart'; import '../models/isar/models/contact_entry.dart' as isar_contact; import '../models/isar/models/isar_models.dart' as isar_models; import '../models/models.dart'; +import '../models/node_model.dart'; import '../services/mixins/wallet_db.dart'; import '../services/wallets_service.dart'; import '../utilities/amount/amount.dart'; @@ -361,6 +362,20 @@ class DbVersionMigrator with WalletDB { // try to continue migrating return await migrate(14, secureStore: secureStore); + case 14: + // migrate + await _v14(); + + // update version + await DB.instance.put( + boxName: DB.boxNameDBInfo, + key: "hive_data_version", + value: 15, + ); + + // try to continue migrating + return await migrate(15, secureStore: secureStore); + default: // finally return return; @@ -632,4 +647,29 @@ class DbVersionMigrator with WalletDB { await isar.close(deleteFromDisk: true); } } + + Future _v14() async { + final nodesBox = await DB.instance.hive.openBox( + DB.boxNameNodeModels, + ); + final primariesBox = await DB.instance.hive.openBox( + DB.boxNamePrimaryNodesDeprecated, + ); + + final primaries = primariesBox.values; + + for (final node in primaries) { + await nodesBox.put( + node.id, + node.copyWith( + loginName: node.loginName, + trusted: node.trusted, + isPrimary: true, + ), + ); + } + + await primariesBox.close(); + await primariesBox.deleteFromDisk(); + } } diff --git a/lib/db/hive/db.dart b/lib/db/hive/db.dart index 0e9449094..be431aba7 100644 --- a/lib/db/hive/db.dart +++ b/lib/db/hive/db.dart @@ -33,11 +33,11 @@ class DB { static const String boxNameTrades = "exchangeTransactionsBox"; static const String boxNameAllWalletsData = "wallets"; static const String boxNameFavoriteWallets = "favoriteWallets"; + static const String boxNamePrimaryNodesDeprecated = "primaryNodes"; // in use // TODO: migrate static const String boxNameNodeModels = "nodeModels"; - static const String boxNamePrimaryNodes = "primaryNodes"; static const String boxNameNotifications = "notificationModels"; static const String boxNameWatchedTransactions = "watchedTxNotificationModels"; @@ -127,29 +127,27 @@ class DB { _boxNodeModels = await hive.openBox(boxNameNodeModels); } - if (hive.isBoxOpen(boxNamePrimaryNodes)) { - _boxPrimaryNodes = hive.box(boxNamePrimaryNodes); - } else { - _boxPrimaryNodes = await hive.openBox(boxNamePrimaryNodes); - } - if (hive.isBoxOpen(boxNameAllWalletsData)) { _boxAllWalletsData = hive.box(boxNameAllWalletsData); } else { _boxAllWalletsData = await hive.openBox(boxNameAllWalletsData); } - _boxNotifications = - await hive.openBox(boxNameNotifications); - _boxWatchedTransactions = - await hive.openBox(boxNameWatchedTransactions); - _boxWatchedTrades = - await hive.openBox(boxNameWatchedTrades); + _boxNotifications = await hive.openBox( + boxNameNotifications, + ); + _boxWatchedTransactions = await hive.openBox( + boxNameWatchedTransactions, + ); + _boxWatchedTrades = await hive.openBox( + boxNameWatchedTrades, + ); _boxTradesV2 = await hive.openBox(boxNameTradesV2); _boxTradeNotes = await hive.openBox(boxNameTradeNotes); _boxTradeLookup = await hive.openBox(boxNameTradeLookup); _walletInfoSource = await hive.openBox( - lib_monero_compat.WalletInfo.boxName); + lib_monero_compat.WalletInfo.boxName, + ); _boxFavoriteWallets = await hive.openBox(boxNameFavoriteWallets); await Future.wait([ @@ -183,11 +181,13 @@ class DB { for (final entry in mapped.entries) { if (hive.isBoxOpen(entry.value.walletId)) { - _walletBoxes[entry.value.walletId] = - hive.box(entry.value.walletId); + _walletBoxes[entry.value.walletId] = hive.box( + entry.value.walletId, + ); } else { - _walletBoxes[entry.value.walletId] = - await hive.openBox(entry.value.walletId); + _walletBoxes[entry.value.walletId] = await hive.openBox( + entry.value.walletId, + ); } } } @@ -196,8 +196,9 @@ class DB { if (_txCacheBoxes[currency.identifier]?.isOpen != true) { _txCacheBoxes.remove(currency.identifier); } - return _txCacheBoxes[currency.identifier] ??= - await hive.openBox(_boxNameTxCache(currency: currency)); + return _txCacheBoxes[currency.identifier] ??= await hive.openBox( + _boxNameTxCache(currency: currency), + ); } Future closeTxCacheBox({required CryptoCurrency currency}) async { @@ -210,8 +211,9 @@ class DB { if (_setCacheBoxes[currency.identifier]?.isOpen != true) { _setCacheBoxes.remove(currency.identifier); } - return _setCacheBoxes[currency.identifier] ??= - await hive.openBox(_boxNameSetCache(currency: currency)); + return _setCacheBoxes[currency.identifier] ??= await hive.openBox( + _boxNameSetCache(currency: currency), + ); } Future closeAnonymitySetCacheBox({ @@ -226,10 +228,8 @@ class DB { if (_usedSerialsCacheBoxes[currency.identifier]?.isOpen != true) { _usedSerialsCacheBoxes.remove(currency.identifier); } - return _usedSerialsCacheBoxes[currency.identifier] ??= - await hive.openBox( - _boxNameUsedSerialsCache(currency: currency), - ); + return _usedSerialsCacheBoxes[currency.identifier] ??= await hive + .openBox(_boxNameUsedSerialsCache(currency: currency)); } Future closeUsedSerialsCacheBox({ @@ -274,10 +274,7 @@ class DB { List values({required String boxName}) => hive.box(boxName).values.toList(growable: false); - T? get({ - required String boxName, - required dynamic key, - }) => + T? get({required String boxName, required dynamic key}) => hive.box(boxName).get(key); bool containsKey({required String boxName, required dynamic key}) => @@ -289,9 +286,9 @@ class DB { required String boxName, required dynamic key, required T value, - }) async => - await mutex - .protect(() async => await hive.box(boxName).put(key, value)); + }) async => await mutex.protect( + () async => await hive.box(boxName).put(key, value), + ); Future add({required String boxName, required T value}) async => await mutex.protect(() async => await hive.box(boxName).add(value)); @@ -299,9 +296,9 @@ class DB { Future addAll({ required String boxName, required Iterable values, - }) async => - await mutex - .protect(() async => await hive.box(boxName).addAll(values)); + }) async => await mutex.protect( + () async => await hive.box(boxName).addAll(values), + ); Future delete({ required dynamic key, @@ -325,11 +322,11 @@ class DB { await DB.instance.deleteBoxFromDisk(boxName: DB.boxNameAddressBook); await DB.instance.deleteBoxFromDisk(boxName: "debugInfoBox"); await DB.instance.deleteBoxFromDisk(boxName: DB.boxNameNodeModels); - await DB.instance.deleteBoxFromDisk(boxName: DB.boxNamePrimaryNodes); await DB.instance.deleteBoxFromDisk(boxName: DB.boxNameAllWalletsData); await DB.instance.deleteBoxFromDisk(boxName: DB.boxNameNotifications); - await DB.instance - .deleteBoxFromDisk(boxName: DB.boxNameWatchedTransactions); + await DB.instance.deleteBoxFromDisk( + boxName: DB.boxNameWatchedTransactions, + ); await DB.instance.deleteBoxFromDisk(boxName: DB.boxNameWatchedTrades); await DB.instance.deleteBoxFromDisk(boxName: DB.boxNameTrades); await DB.instance.deleteBoxFromDisk(boxName: DB.boxNameTradesV2); @@ -337,8 +334,9 @@ class DB { await DB.instance.deleteBoxFromDisk(boxName: DB.boxNameTradeLookup); await DB.instance.deleteBoxFromDisk(boxName: DB.boxNameFavoriteWallets); await DB.instance.deleteBoxFromDisk(boxName: DB.boxNamePrefs); - await DB.instance - .deleteBoxFromDisk(boxName: DB.boxNameWalletsToDeleteOnStart); + await DB.instance.deleteBoxFromDisk( + boxName: DB.boxNameWalletsToDeleteOnStart, + ); await DB.instance.deleteBoxFromDisk(boxName: DB.boxNamePriceCache); await DB.instance.deleteBoxFromDisk(boxName: DB.boxNameDBInfo); await DB.instance.deleteBoxFromDisk(boxName: "theme"); diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart index 1c3b908a1..69205f1f0 100644 --- a/lib/utilities/constants.dart +++ b/lib/utilities/constants.dart @@ -40,7 +40,7 @@ abstract class Constants { // Enable Logger.print statements static const bool disableLogger = false; - static const int currentDataVersion = 14; + static const int currentDataVersion = 15; static const int rescanV1 = 1; diff --git a/test/hive/db_test.dart b/test/hive/db_test.dart index 2f5130837..fb4e71434 100644 --- a/test/hive/db_test.dart +++ b/test/hive/db_test.dart @@ -6,31 +6,39 @@ void main() { group("DB box names", () { test("address book", () => expect(DB.boxNameAddressBook, "addressBook")); test("nodes", () => expect(DB.boxNameNodeModels, "nodeModels")); - test("primary nodes", () => expect(DB.boxNamePrimaryNodes, "primaryNodes")); test("wallets info", () => expect(DB.boxNameAllWalletsData, "wallets")); - test("notifications", - () => expect(DB.boxNameNotifications, "notificationModels")); test( - "watched transactions", - () => expect( - DB.boxNameWatchedTransactions, "watchedTxNotificationModels")); + "notifications", + () => expect(DB.boxNameNotifications, "notificationModels"), + ); test( - "watched trades", - () => - expect(DB.boxNameWatchedTrades, "watchedTradesNotificationModels")); + "watched transactions", + () => + expect(DB.boxNameWatchedTransactions, "watchedTxNotificationModels"), + ); + test( + "watched trades", + () => expect(DB.boxNameWatchedTrades, "watchedTradesNotificationModels"), + ); test("trades", () => expect(DB.boxNameTrades, "exchangeTransactionsBox")); test("trade notes", () => expect(DB.boxNameTradeNotes, "tradeNotesBox")); - test("tx <> trade lookup table", - () => expect(DB.boxNameTradeLookup, "tradeToTxidLookUpBox")); - test("favorite wallets", - () => expect(DB.boxNameFavoriteWallets, "favoriteWallets")); + test( + "tx <> trade lookup table", + () => expect(DB.boxNameTradeLookup, "tradeToTxidLookUpBox"), + ); + test( + "favorite wallets", + () => expect(DB.boxNameFavoriteWallets, "favoriteWallets"), + ); test("preferences", () => expect(DB.boxNamePrefs, "prefs")); test( - "deleted wallets to clear out on start", - () => - expect(DB.boxNameWalletsToDeleteOnStart, "walletsToDeleteOnStart")); - test("price cache", - () => expect(DB.boxNamePriceCache, "priceAPIPrice24hCache")); + "deleted wallets to clear out on start", + () => expect(DB.boxNameWalletsToDeleteOnStart, "walletsToDeleteOnStart"), + ); + test( + "price cache", + () => expect(DB.boxNamePriceCache, "priceAPIPrice24hCache"), + ); }); group("tests requiring test hive environment", () { From 6ffdf3dedc58eca11e85414e6cc6b90f4bec1fca Mon Sep 17 00:00:00 2001 From: sneurlax Date: Mon, 2 Jun 2025 13:30:52 -0500 Subject: [PATCH 05/11] refactor: extract canPing-related checks to helper fn --- .../intermediate/lib_monero_wallet.dart | 67 ++++++++----------- 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/lib/wallets/wallet/intermediate/lib_monero_wallet.dart b/lib/wallets/wallet/intermediate/lib_monero_wallet.dart index 9e2661311..82f3bce3c 100644 --- a/lib/wallets/wallet/intermediate/lib_monero_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_monero_wallet.dart @@ -19,6 +19,7 @@ import '../../../models/isar/models/blockchain_data/v2/output_v2.dart'; import '../../../models/isar/models/blockchain_data/v2/transaction_v2.dart'; import '../../../models/keys/cw_key_data.dart'; import '../../../models/keys/view_only_wallet_data.dart'; +import '../../../models/node_model.dart'; import '../../../models/paymint/fee_object_model.dart'; import '../../../services/event_bus/events/global/blocks_remaining_event.dart'; import '../../../services/event_bus/events/global/refresh_percent_changed_event.dart'; @@ -494,30 +495,16 @@ abstract class LibMoneroWallet Future updateNode() async { final node = getCurrentNode(); + if (_torNodeMismatchGuard(node)) { + throw Exception("TOR – clearnet mismatch"); + } + final host = node.host.endsWith(".onion") ? node.host : Uri.parse(node.host).host; ({InternetAddress host, int port})? proxy; - _canPing = true; - if (prefs.useTor) { - if (node.clearnetEnabled && !node.torEnabled) { - _canPing = false; - libMoneroWallet?.stopAutoSaving(); - libMoneroWallet?.stopListeners(); - libMoneroWallet?.stopSyncing(); - _setSyncStatus(lib_monero_compat.FailedSyncStatus()); - throw Exception("TOR - clearnet mismatch"); - } - proxy = TorService.sharedInstance.getProxyInfo(); - } else { - if (!node.clearnetEnabled && node.torEnabled) { - _canPing = false; - libMoneroWallet?.stopAutoSaving(); - libMoneroWallet?.stopListeners(); - libMoneroWallet?.stopSyncing(); - _setSyncStatus(lib_monero_compat.FailedSyncStatus()); - throw Exception("TOR - clearnet mismatch"); - } - } + proxy = prefs.useTor && !node.forceNoTor + ? TorService.sharedInstance.getProxyInfo() + : null; _setSyncStatus(lib_monero_compat.ConnectingSyncStatus()); try { @@ -1001,6 +988,23 @@ abstract class LibMoneroWallet } } + bool _torNodeMismatchGuard(NodeModel node) { + _canPing = true; // Reset. + + final bool mismatch = (prefs.useTor && node.clearnetEnabled && !node.torEnabled) || + (!prefs.useTor && !node.clearnetEnabled && node.torEnabled); + + if (mismatch) { + _canPing = false; + libMoneroWallet?.stopAutoSaving(); + libMoneroWallet?.stopListeners(); + libMoneroWallet?.stopSyncing(); + _setSyncStatus(lib_monero_compat.FailedSyncStatus()); + } + + return mismatch; // Caller decides whether to throw. + } + // ============ Overrides ==================================================== @override @@ -1097,25 +1101,8 @@ abstract class LibMoneroWallet final node = getCurrentNode(); - _canPing = true; - if (prefs.useTor) { - if (node.clearnetEnabled && !node.torEnabled) { - _canPing = false; - libMoneroWallet?.stopAutoSaving(); - libMoneroWallet?.stopListeners(); - libMoneroWallet?.stopSyncing(); - _setSyncStatus(lib_monero_compat.FailedSyncStatus()); - throw Exception("TOR - clearnet mismatch"); - } - } else { - if (!node.clearnetEnabled && node.torEnabled) { - _canPing = false; - libMoneroWallet?.stopAutoSaving(); - libMoneroWallet?.stopListeners(); - libMoneroWallet?.stopSyncing(); - _setSyncStatus(lib_monero_compat.FailedSyncStatus()); - throw Exception("TOR - clearnet mismatch"); - } + if (_torNodeMismatchGuard(node)) { + throw Exception("TOR – clearnet mismatch"); } // this acquire should be almost instant due to above check. From 505ba4c439f9a814f1f48d751dda697d11c85e22 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Mon, 2 Jun 2025 13:41:02 -0500 Subject: [PATCH 06/11] feat: avoid crash w local node + "TOR only" node and tor off --- .../intermediate/lib_salvium_wallet.dart | 69 +++++++++---------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/lib/wallets/wallet/intermediate/lib_salvium_wallet.dart b/lib/wallets/wallet/intermediate/lib_salvium_wallet.dart index fcb1cae60..7f7eea6f0 100644 --- a/lib/wallets/wallet/intermediate/lib_salvium_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_salvium_wallet.dart @@ -17,6 +17,7 @@ import '../../../models/isar/models/blockchain_data/v2/output_v2.dart'; import '../../../models/isar/models/blockchain_data/v2/transaction_v2.dart'; import '../../../models/keys/cw_key_data.dart'; import '../../../models/keys/view_only_wallet_data.dart'; +import '../../../models/node_model.dart'; import '../../../models/paymint/fee_object_model.dart'; import '../../../services/event_bus/events/global/blocks_remaining_event.dart'; import '../../../services/event_bus/events/global/refresh_percent_changed_event.dart'; @@ -457,36 +458,31 @@ abstract class LibSalviumWallet }); } + bool _canPing = false; + @override Future pingCheck() async { - return (await libSalviumWallet?.isConnectedToDaemon()) ?? false; + if (_canPing) { + return (await libSalviumWallet?.isConnectedToDaemon()) ?? false; + } else { + return false; + } } @override Future updateNode() async { final node = getCurrentNode(); + if (_torNodeMismatchGuard(node)) { + throw Exception("TOR – clearnet mismatch"); + } + final host = node.host.endsWith(".onion") ? node.host : Uri.parse(node.host).host; ({InternetAddress host, int port})? proxy; - if (prefs.useTor) { - if (node.clearnetEnabled && !node.torEnabled) { - libSalviumWallet?.stopAutoSaving(); - libSalviumWallet?.stopListeners(); - libSalviumWallet?.stopSyncing(); - _setSyncStatus(FailedSyncStatus()); - throw Exception("TOR - clearnet mismatch"); - } - proxy = TorService.sharedInstance.getProxyInfo(); - } else { - if (!node.clearnetEnabled && node.torEnabled) { - libSalviumWallet?.stopAutoSaving(); - libSalviumWallet?.stopListeners(); - libSalviumWallet?.stopSyncing(); - _setSyncStatus(FailedSyncStatus()); - throw Exception("TOR - clearnet mismatch"); - } - } + proxy = prefs.useTor && !node.forceNoTor + ? TorService.sharedInstance.getProxyInfo() + : null; _setSyncStatus(ConnectingSyncStatus()); try { @@ -957,6 +953,23 @@ abstract class LibSalviumWallet } } + bool _torNodeMismatchGuard(NodeModel node) { + _canPing = true; // Reset. + + final bool mismatch = (prefs.useTor && node.clearnetEnabled && !node.torEnabled) || + (!prefs.useTor && !node.clearnetEnabled && node.torEnabled); + + if (mismatch) { + _canPing = false; + libSalviumWallet?.stopAutoSaving(); + libSalviumWallet?.stopListeners(); + libSalviumWallet?.stopSyncing(); + _setSyncStatus(FailedSyncStatus()); + } + + return mismatch; // Caller decides whether to throw. + } + // ============ Overrides ==================================================== @override @@ -1053,22 +1066,8 @@ abstract class LibSalviumWallet final node = getCurrentNode(); - if (prefs.useTor) { - if (node.clearnetEnabled && !node.torEnabled) { - libSalviumWallet?.stopAutoSaving(); - libSalviumWallet?.stopListeners(); - libSalviumWallet?.stopSyncing(); - _setSyncStatus(FailedSyncStatus()); - throw Exception("TOR - clearnet mismatch"); - } - } else { - if (!node.clearnetEnabled && node.torEnabled) { - libSalviumWallet?.stopAutoSaving(); - libSalviumWallet?.stopListeners(); - libSalviumWallet?.stopSyncing(); - _setSyncStatus(FailedSyncStatus()); - throw Exception("TOR - clearnet mismatch"); - } + if (_torNodeMismatchGuard(node)) { + throw Exception("TOR – clearnet mismatch"); } // this acquire should be almost instant due to above check. From 0c42fbedced1c67fa8a06078f2ca5640de8f8a94 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 2 Jun 2025 12:45:12 -0600 Subject: [PATCH 07/11] update swb to handle updated primary node handling --- .../helpers/restore_create_backup.dart | 68 +++---------------- 1 file changed, 11 insertions(+), 57 deletions(-) diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart index d0200b034..c61d73d1d 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart @@ -47,7 +47,6 @@ import '../../../../../utilities/format.dart'; import '../../../../../utilities/logger.dart'; import '../../../../../utilities/prefs.dart'; import '../../../../../utilities/util.dart'; -import '../../../../../wallets/crypto_currency/crypto_currency.dart'; import '../../../../../wallets/crypto_currency/intermediate/frost_currency.dart'; import '../../../../../wallets/isar/models/frost_wallet_info.dart'; import '../../../../../wallets/isar/models/wallet_info.dart'; @@ -242,17 +241,6 @@ abstract class SWB { await DB.instance.mutex.protect(() async { Logging.instance.i("...createStackWalletJSON DB.instance.mutex acquired"); Logging.instance.i("SWB backing up nodes"); - try { - final primaryNodes = - nodeService.primaryNodes.map((e) async { - final map = e.toMap(); - map["password"] = await e.getPassword(_secureStore); - return map; - }).toList(); - backupJson['primaryNodes'] = await Future.wait(primaryNodes); - } catch (e, s) { - Logging.instance.e("", error: e, stackTrace: s); - } try { final nodesFuture = nodeService.nodes.map((e) async { @@ -896,8 +884,6 @@ abstract class SWB { revertToState.validJSON["prefs"] as Map; final List? addressBookEntries = revertToState.validJSON["addressBookEntries"] as List?; - final List? primaryNodes = - revertToState.validJSON["primaryNodes"] as List?; final List? nodes = revertToState.validJSON["nodes"] as List?; final List? trades = revertToState.validJSON["tradeHistory"] as List?; @@ -1001,6 +987,7 @@ abstract class SWB { isFailover: nodeData['isFailover'] as bool, isDown: nodeData['isDown'] as bool, trusted: nodeData['trusted'] as bool?, + isPrimary: nodeData["isPrimary"] as bool? ?? false, ), nodeData['password'] as String?, true, @@ -1011,28 +998,6 @@ abstract class SWB { } } - // primary nodes - if (primaryNodes != null) { - for (final node in primaryNodes) { - try { - final CryptoCurrency coin; - try { - coin = AppConfig.getCryptoCurrencyByPrettyName( - node['coinName'] as String, - ); - } catch (_) { - continue; - } - - await nodeService.setPrimaryNodeFor( - coin: coin, - node: nodeService.getNodeById(id: node['id'] as String)!, - ); - } catch (e, s) { - Logging.instance.e("", error: e, stackTrace: s); - } - } - } await nodeService.updateDefaults(); // trades @@ -1204,13 +1169,20 @@ abstract class SWB { secureStorageInterface: secureStorageInterface, ); if (nodes != null) { + final primaryIds = + primaryNodes + ?.map((e) => e["id"] as String?) + .whereType() + .toSet(); + for (final node in nodes) { + final id = node['id'] as String; await nodeService.add( NodeModel( host: node['host'] as String, port: node['port'] as int, name: node['name'] as String, - id: node['id'] as String, + id: id, useSSL: node['useSSL'] == "false" ? false : true, enabled: node['enabled'] == "false" ? false : true, coinName: node['coinName'] as String, @@ -1219,33 +1191,15 @@ abstract class SWB { isDown: node['isDown'] as bool, torEnabled: node['torEnabled'] as bool? ?? true, clearnetEnabled: node['plainEnabled'] as bool? ?? true, + isPrimary: + node["isPrimary"] as bool? ?? primaryIds?.contains(id) ?? false, ), node["password"] as String?, true, ); } } - if (primaryNodes != null) { - for (final node in primaryNodes) { - final CryptoCurrency coin; - try { - coin = AppConfig.getCryptoCurrencyByPrettyName( - node['coinName'] as String, - ); - } catch (_) { - continue; - } - try { - await nodeService.setPrimaryNodeFor( - coin: coin, - node: nodeService.getNodeById(id: node['id'] as String)!, - ); - } catch (e, s) { - Logging.instance.e("", error: e, stackTrace: s); - } - } - } await nodeService.updateDefaults(); } From a6ba1cd568bc2b094912b8c6b89990f5f86adc68 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Mon, 2 Jun 2025 14:04:22 -0500 Subject: [PATCH 08/11] refactor: combine NodeService add and edit -> save --- .../add_edit_node_view.dart | 19 +++++--- .../manage_nodes_views/node_details_view.dart | 2 +- .../helpers/restore_create_backup.dart | 4 +- lib/services/node_service.dart | 43 ++++++++----------- .../pages/send_view/send_view_test.mocks.dart | 2 +- .../lockscreen_view_screen_test.mocks.dart | 2 +- .../create_pin_view_screen_test.mocks.dart | 2 +- ...restore_wallet_view_screen_test.mocks.dart | 2 +- ...dd_custom_node_view_screen_test.mocks.dart | 2 +- .../node_details_view_screen_test.mocks.dart | 2 +- ...twork_settings_view_screen_test.mocks.dart | 2 +- test/services/node_service_test.dart | 12 ++++-- .../managed_favorite_test.mocks.dart | 2 +- test/widget_tests/node_card_test.dart | 6 +++ test/widget_tests/node_card_test.mocks.dart | 2 +- .../widget_tests/node_options_sheet_test.dart | 8 +++- .../node_options_sheet_test.mocks.dart | 2 +- ...et_info_row_balance_future_test.mocks.dart | 2 +- .../wallet_info_row_test.mocks.dart | 2 +- 19 files changed, 67 insertions(+), 51 deletions(-) diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart index 98b80995d..27b50796d 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart @@ -262,11 +262,12 @@ class _AddEditNodeViewState extends ConsumerState { torEnabled: torEnabled, clearnetEnabled: plainEnabled, forceNoTor: forceNoTor, + isPrimary: false, ); await ref .read(nodeServiceChangeNotifierProvider) - .add(node, formData.password, true); + .save(node, formData.password, true); await _notifyWalletsOfUpdatedNode(); if (mounted) { Navigator.of( @@ -290,11 +291,12 @@ class _AddEditNodeViewState extends ConsumerState { torEnabled: torEnabled, clearnetEnabled: plainEnabled, forceNoTor: forceNoTor, + isPrimary: formData.isPrimary ?? false, ); await ref .read(nodeServiceChangeNotifierProvider) - .add(node, formData.password, true); + .save(node, formData.password, true); await _notifyWalletsOfUpdatedNode(); if (mounted) { Navigator.of( @@ -420,6 +422,7 @@ class _AddEditNodeViewState extends ConsumerState { torEnabled: true, clearnetEnabled: !nodeQrData.host.endsWith(".onion"), loginName: (nodeQrData as LibMoneroNodeQrData?)?.user, + isPrimary: false, ), (nodeQrData as LibMoneroNodeQrData?)?.password ?? "", ); @@ -766,12 +769,12 @@ class _AddEditNodeViewState extends ConsumerState { class NodeFormData { String? name, host, login, password; int? port; - bool? useSSL, isFailover, trusted, forceNoTor; + bool? useSSL, isFailover, trusted, forceNoTor, isPrimary; TorPlainNetworkOption? netOption; @override String toString() { - return "{ name: $name, host: $host, port: $port, useSSL: $useSSL, trusted: $trusted, netOption: $netOption }"; + return "{ name: $name, host: $host, port: $port, useSSL: $useSSL, trusted: $trusted, netOption: $netOption, isPrimary: $isPrimary }"; } } @@ -819,6 +822,7 @@ class _NodeFormState extends ConsumerState { int? port; late bool enableSSLCheckbox; late TorPlainNetworkOption netOption; + bool _isPrimary = false; late final bool enableAuthFields; @@ -875,6 +879,8 @@ class _NodeFormState extends ConsumerState { ref.read(nodeFormDataProvider).trusted = _trusted; ref.read(nodeFormDataProvider).netOption = netOption; ref.read(nodeFormDataProvider).forceNoTor = _forceNoTor; + ref.read(nodeFormDataProvider).host; + ref.read(nodeFormDataProvider).isPrimary = _isPrimary; } @override @@ -910,6 +916,7 @@ class _NodeFormState extends ConsumerState { _isFailover = node.isFailover; _trusted = node.trusted ?? false; _forceNoTor = node.forceNoTor ?? false; + _isPrimary = node.isPrimary ?? false; if (node.torEnabled && !node.clearnetEnabled) { netOption = TorPlainNetworkOption.tor; @@ -1359,7 +1366,7 @@ class _NodeFormState extends ConsumerState { if (widget.readOnly) { ref .read(nodeServiceChangeNotifierProvider) - .edit( + .save( widget.node!.copyWith( isFailover: _isFailover, loginName: widget.node!.loginName, @@ -1390,7 +1397,7 @@ class _NodeFormState extends ConsumerState { if (widget.readOnly) { ref .read(nodeServiceChangeNotifierProvider) - .edit( + .save( widget.node!.copyWith( isFailover: _isFailover, loginName: widget.node!.loginName, diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart index 414ba8097..481c3906d 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart @@ -396,7 +396,7 @@ class _NodeDetailsViewState extends ConsumerState { await ref .read(nodeServiceChangeNotifierProvider) - .edit( + .save( editedNode, ref.read(nodeFormDataProvider).password, true, diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart index c61d73d1d..bcec91212 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart @@ -975,7 +975,7 @@ abstract class SWB { if (nodeData != null) { // node existed before restore attempt // revert to pre restore node - await nodeService.edit( + await nodeService.save( node.copyWith( host: nodeData['host'] as String, port: nodeData['port'] as int, @@ -1177,7 +1177,7 @@ abstract class SWB { for (final node in nodes) { final id = node['id'] as String; - await nodeService.add( + await nodeService.save( NodeModel( host: node['host'] as String, port: node['port'] as int, diff --git a/lib/services/node_service.dart b/lib/services/node_service.dart index 1657cfa78..6d061e146 100644 --- a/lib/services/node_service.dart +++ b/lib/services/node_service.dart @@ -218,20 +218,33 @@ class NodeService extends ChangeNotifier { ).where((e) => e.isFailover && !e.isDown).toList(); } - // should probably just combine this and edit into a save() func at some point - /// Over write node in hive if a node with existing id already exists. - /// Otherwise add node to hive - Future add( + /// Adds a new node to the database. + /// + /// If a node with the same ID already exists, it will be overwritten. + Future save( NodeModel node, String? password, bool shouldNotifyListeners, ) async { + // Handle primary node updates (logic from edit()) + final coin = AppConfig.getCryptoCurrencyByPrettyName(node.coinName); + final primaryNode = getPrimaryNodeFor(currency: coin); + if (primaryNode?.id == node.id) { + await setPrimaryNodeFor( + coin: coin, + node: node, + shouldNotifyListeners: true, + ); + } + + // Save to database (logic from add()). await DB.instance.put( boxName: DB.boxNameNodeModels, key: node.id, value: node, ); + // Save password to secure storage. if (password != null) { await secureStorageInterface.write( key: "${node.id}_nodePW", @@ -275,26 +288,6 @@ class NodeService extends ChangeNotifier { } } - /// convenience wrapper for add - Future edit( - NodeModel editedNode, - String? password, - bool shouldNotifyListeners, - ) async { - // check if the node being edited is the primary one; if it is, setPrimaryNodeFor coin - final coin = AppConfig.getCryptoCurrencyByPrettyName(editedNode.coinName); - final primaryNode = getPrimaryNodeFor(currency: coin); - if (primaryNode?.id == editedNode.id) { - await setPrimaryNodeFor( - coin: coin, - node: editedNode, - shouldNotifyListeners: true, - ); - } - - return add(editedNode, password, shouldNotifyListeners); - } - //============================================================================ Future updateCommunityNodes() async { @@ -344,7 +337,7 @@ class NodeService extends ChangeNotifier { trusted: node.trusted, ); } - await add(node, null, false); + await save(node, null, false); } } } catch (e, s) { diff --git a/test/pages/send_view/send_view_test.mocks.dart b/test/pages/send_view/send_view_test.mocks.dart index c4398cf4d..436a918fd 100644 --- a/test/pages/send_view/send_view_test.mocks.dart +++ b/test/pages/send_view/send_view_test.mocks.dart @@ -341,7 +341,7 @@ class MockNodeService extends _i1.Mock implements _i2.NodeService { ) as List<_i13.NodeModel>); @override - _i10.Future add( + _i10.Future save( _i13.NodeModel? node, String? password, bool? shouldNotifyListeners, diff --git a/test/screen_tests/lockscreen_view_screen_test.mocks.dart b/test/screen_tests/lockscreen_view_screen_test.mocks.dart index a3523a093..c68851019 100644 --- a/test/screen_tests/lockscreen_view_screen_test.mocks.dart +++ b/test/screen_tests/lockscreen_view_screen_test.mocks.dart @@ -202,7 +202,7 @@ class MockNodeService extends _i1.Mock implements _i6.NodeService { ) as List<_i7.NodeModel>); @override - _i4.Future add( + _i4.Future save( _i7.NodeModel? node, String? password, bool? shouldNotifyListeners, diff --git a/test/screen_tests/onboarding/create_pin_view_screen_test.mocks.dart b/test/screen_tests/onboarding/create_pin_view_screen_test.mocks.dart index 4f9addbc7..08e96b5a3 100644 --- a/test/screen_tests/onboarding/create_pin_view_screen_test.mocks.dart +++ b/test/screen_tests/onboarding/create_pin_view_screen_test.mocks.dart @@ -202,7 +202,7 @@ class MockNodeService extends _i1.Mock implements _i6.NodeService { ) as List<_i7.NodeModel>); @override - _i4.Future add( + _i4.Future save( _i7.NodeModel? node, String? password, bool? shouldNotifyListeners, diff --git a/test/screen_tests/onboarding/restore_wallet_view_screen_test.mocks.dart b/test/screen_tests/onboarding/restore_wallet_view_screen_test.mocks.dart index 0603d61be..3c66bf1f3 100644 --- a/test/screen_tests/onboarding/restore_wallet_view_screen_test.mocks.dart +++ b/test/screen_tests/onboarding/restore_wallet_view_screen_test.mocks.dart @@ -243,7 +243,7 @@ class MockNodeService extends _i1.Mock implements _i8.NodeService { ) as List<_i9.NodeModel>); @override - _i5.Future add( + _i5.Future save( _i9.NodeModel? node, String? password, bool? shouldNotifyListeners, diff --git a/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/add_custom_node_view_screen_test.mocks.dart b/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/add_custom_node_view_screen_test.mocks.dart index 75a10f43e..d6d788327 100644 --- a/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/add_custom_node_view_screen_test.mocks.dart +++ b/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/add_custom_node_view_screen_test.mocks.dart @@ -142,7 +142,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService { ) as List<_i4.NodeModel>); @override - _i5.Future add( + _i5.Future save( _i4.NodeModel? node, String? password, bool? shouldNotifyListeners, diff --git a/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/node_details_view_screen_test.mocks.dart b/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/node_details_view_screen_test.mocks.dart index fb159cea3..6a4ad08ce 100644 --- a/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/node_details_view_screen_test.mocks.dart +++ b/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/node_details_view_screen_test.mocks.dart @@ -142,7 +142,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService { ) as List<_i4.NodeModel>); @override - _i5.Future add( + _i5.Future save( _i4.NodeModel? node, String? password, bool? shouldNotifyListeners, diff --git a/test/screen_tests/settings_view/settings_subviews/network_settings_view_screen_test.mocks.dart b/test/screen_tests/settings_view/settings_subviews/network_settings_view_screen_test.mocks.dart index c60df280d..b8fee8040 100644 --- a/test/screen_tests/settings_view/settings_subviews/network_settings_view_screen_test.mocks.dart +++ b/test/screen_tests/settings_view/settings_subviews/network_settings_view_screen_test.mocks.dart @@ -142,7 +142,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService { ) as List<_i4.NodeModel>); @override - _i5.Future add( + _i5.Future save( _i4.NodeModel? node, String? password, bool? shouldNotifyListeners, diff --git a/test/services/node_service_test.dart b/test/services/node_service_test.dart index 2fac42b96..8865c748c 100644 --- a/test/services/node_service_test.dart +++ b/test/services/node_service_test.dart @@ -17,7 +17,7 @@ void main() { Hive.registerAdapter(NodeModelAdapter()); } await Hive.openBox(DB.boxNameNodeModels); - await Hive.openBox(DB.boxNamePrimaryNodes); + // await Hive.openBox(DB.boxNamePrimaryNodes); }); group("Empty nodes DB tests", () { @@ -50,6 +50,7 @@ void main() { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: true, ); await service.setPrimaryNodeFor( coin: Bitcoin(CryptoCurrencyNetwork.main), @@ -133,6 +134,7 @@ void main() { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: true, ); final nodeB = NodeModel( host: "host2", @@ -146,6 +148,7 @@ void main() { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: true, ); final nodeC = NodeModel( host: "host3", @@ -159,6 +162,7 @@ void main() { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: true, ); setUp(() async { @@ -226,7 +230,7 @@ void main() { test("add a node without a password", () async { final fakeStore = FakeSecureStorage(); final service = NodeService(secureStorageInterface: fakeStore); - await service.add(nodeA, null, true); + await service.save(nodeA, null, true); expect( service.nodes.length, AppConfig.coins.map((e) => e.defaultNode).length + 1, @@ -237,7 +241,7 @@ void main() { test("add a node with a password", () async { final fakeStore = FakeSecureStorage(); final service = NodeService(secureStorageInterface: fakeStore); - await service.add(nodeA, "some password", true); + await service.save(nodeA, "some password", true); expect( service.nodes.length, AppConfig.coins.map((e) => e.defaultNode).length + 1, @@ -276,7 +280,7 @@ void main() { trusted: null, ); - await service.edit(editedNode, "123456", true); + await service.save(editedNode, "123456", true); expect(service.nodes.length, currentLength); diff --git a/test/widget_tests/managed_favorite_test.mocks.dart b/test/widget_tests/managed_favorite_test.mocks.dart index 6eb09a26e..4b1944af8 100644 --- a/test/widget_tests/managed_favorite_test.mocks.dart +++ b/test/widget_tests/managed_favorite_test.mocks.dart @@ -1256,7 +1256,7 @@ class MockNodeService extends _i1.Mock implements _i2.NodeService { ) as List<_i23.NodeModel>); @override - _i10.Future add( + _i10.Future save( _i23.NodeModel? node, String? password, bool? shouldNotifyListeners, diff --git a/test/widget_tests/node_card_test.dart b/test/widget_tests/node_card_test.dart index cc706824c..71a08f851 100644 --- a/test/widget_tests/node_card_test.dart +++ b/test/widget_tests/node_card_test.dart @@ -39,6 +39,7 @@ void main() { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: true, ), ); @@ -55,6 +56,7 @@ void main() { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: true, ), ); @@ -118,6 +120,7 @@ void main() { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: true, ), ); @@ -134,6 +137,7 @@ void main() { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: true, ), ); @@ -198,6 +202,7 @@ void main() { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: true, ), ); @@ -214,6 +219,7 @@ void main() { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: true, ), ); diff --git a/test/widget_tests/node_card_test.mocks.dart b/test/widget_tests/node_card_test.mocks.dart index 441edcdbf..808f10fab 100644 --- a/test/widget_tests/node_card_test.mocks.dart +++ b/test/widget_tests/node_card_test.mocks.dart @@ -142,7 +142,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService { ) as List<_i4.NodeModel>); @override - _i5.Future add( + _i5.Future save( _i4.NodeModel? node, String? password, bool? shouldNotifyListeners, diff --git a/test/widget_tests/node_options_sheet_test.dart b/test/widget_tests/node_options_sheet_test.dart index 998f6322a..cedc9158b 100644 --- a/test/widget_tests/node_options_sheet_test.dart +++ b/test/widget_tests/node_options_sheet_test.dart @@ -38,6 +38,7 @@ void main() { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: true, )); when(mockNodeService.getPrimaryNodeFor( @@ -53,7 +54,8 @@ void main() { isFailover: false, torEnabled: true, clearnetEnabled: true, - isDown: false)); + isDown: false, + isPrimary: true)); await tester.pumpWidget( ProviderScope( @@ -116,6 +118,7 @@ void main() { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: true, ), ); @@ -134,6 +137,7 @@ void main() { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: true, ), ); @@ -197,6 +201,7 @@ void main() { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: true, ), ); @@ -215,6 +220,7 @@ void main() { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: true, ), ); diff --git a/test/widget_tests/node_options_sheet_test.mocks.dart b/test/widget_tests/node_options_sheet_test.mocks.dart index 172abecf2..d01578f3f 100644 --- a/test/widget_tests/node_options_sheet_test.mocks.dart +++ b/test/widget_tests/node_options_sheet_test.mocks.dart @@ -1060,7 +1060,7 @@ class MockNodeService extends _i1.Mock implements _i2.NodeService { ) as List<_i19.NodeModel>); @override - _i10.Future add( + _i10.Future save( _i19.NodeModel? node, String? password, bool? shouldNotifyListeners, diff --git a/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.mocks.dart b/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.mocks.dart index 7ded2cf87..fc2c10fbb 100644 --- a/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.mocks.dart +++ b/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.mocks.dart @@ -309,7 +309,7 @@ class MockNodeService extends _i1.Mock implements _i2.NodeService { ) as List<_i11.NodeModel>); @override - _i8.Future add( + _i8.Future save( _i11.NodeModel? node, String? password, bool? shouldNotifyListeners, diff --git a/test/widget_tests/wallet_info_row/wallet_info_row_test.mocks.dart b/test/widget_tests/wallet_info_row/wallet_info_row_test.mocks.dart index 3f2a24ac7..5f16a8a2e 100644 --- a/test/widget_tests/wallet_info_row/wallet_info_row_test.mocks.dart +++ b/test/widget_tests/wallet_info_row/wallet_info_row_test.mocks.dart @@ -449,7 +449,7 @@ class MockNodeService extends _i1.Mock implements _i2.NodeService { ) as List<_i15.NodeModel>); @override - _i9.Future add( + _i9.Future save( _i15.NodeModel? node, String? password, bool? shouldNotifyListeners, From e8a13f9aa4054e9bbe88e6971d8b5cf5ff733e21 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 2 Jun 2025 13:05:12 -0600 Subject: [PATCH 09/11] update nodeservice delete func --- lib/services/node_service.dart | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/services/node_service.dart b/lib/services/node_service.dart index 6d061e146..3fb226809 100644 --- a/lib/services/node_service.dart +++ b/lib/services/node_service.dart @@ -259,9 +259,34 @@ class NodeService extends ChangeNotifier { } Future delete(String id, bool shouldNotifyListeners) async { - await DB.instance.delete(boxName: DB.boxNameNodeModels, key: id); + final nodeToDelete = getNodeById(id: id); + + if (nodeToDelete == null) { + // doesn't exist + Logging.instance.w( + "Attempted delete of a node model that does not exist", + ); + return; + } + + final coin = AppConfig.getCryptoCurrencyByPrettyName(nodeToDelete.coinName); + final remaining = getNodesFor(coin); + + if (remaining.length - 1 < 1) { + // doesn't exist + Logging.instance.w("Attempted delete the last remaining node for $coin"); + return; + } + + remaining.retainWhere((e) => e.id != nodeToDelete.id); + await DB.instance.delete(boxName: DB.boxNameNodeModels, key: id); await secureStorageInterface.delete(key: "${id}_nodePW"); + + if (nodeToDelete.isPrimary) { + await setPrimaryNodeFor(coin: coin, node: remaining.first); + } + if (shouldNotifyListeners) { notifyListeners(); } From d5945b457b772667e3aa246531facab27329a3ca Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 2 Jun 2025 13:25:40 -0600 Subject: [PATCH 10/11] clean up remaining node service refactor code issues --- ...w_wallet_recovery_phrase_warning_view.dart | 4 +- .../restore_view_only_wallet_view.dart | 4 +- .../restore_wallet_view.dart | 4 +- .../helpers/restore_create_backup.dart | 4 +- lib/services/ethereum/ethereum_api.dart | 2 +- lib/services/node_service.dart | 37 +------ .../show_node_tor_settings_mismatch.dart | 99 +++++++++---------- lib/wallets/crypto_currency/coins/banano.dart | 10 +- .../crypto_currency/coins/bitcoin.dart | 30 +++--- .../crypto_currency/coins/bitcoin_frost.dart | 14 +-- .../crypto_currency/coins/bitcoincash.dart | 16 +-- .../crypto_currency/coins/cardano.dart | 6 +- lib/wallets/crypto_currency/coins/dash.dart | 18 ++-- .../crypto_currency/coins/dogecoin.dart | 19 ++-- lib/wallets/crypto_currency/coins/ecash.dart | 15 ++- .../crypto_currency/coins/epiccash.dart | 6 +- .../crypto_currency/coins/ethereum.dart | 3 +- .../crypto_currency/coins/fact0rn.dart | 3 +- lib/wallets/crypto_currency/coins/firo.dart | 19 ++-- .../crypto_currency/coins/litecoin.dart | 33 +++---- lib/wallets/crypto_currency/coins/monero.dart | 6 +- .../crypto_currency/coins/namecoin.dart | 28 +++--- lib/wallets/crypto_currency/coins/nano.dart | 10 +- .../crypto_currency/coins/particl.dart | 15 ++- .../crypto_currency/coins/peercoin.dart | 27 ++--- .../crypto_currency/coins/salvium.dart | 3 +- lib/wallets/crypto_currency/coins/solana.dart | 3 +- .../crypto_currency/coins/stellar.dart | 15 ++- lib/wallets/crypto_currency/coins/tezos.dart | 18 ++-- .../crypto_currency/coins/wownero.dart | 6 +- lib/wallets/crypto_currency/coins/xelis.dart | 8 +- .../crypto_currency/crypto_currency.dart | 2 +- lib/wallets/wallet/impl/solana_wallet.dart | 4 +- lib/wallets/wallet/impl/tezos_wallet.dart | 4 +- lib/wallets/wallet/wallet.dart | 2 +- .../nano_interface.dart | 4 +- test/services/node_service_test.dart | 18 ++-- 37 files changed, 248 insertions(+), 271 deletions(-) diff --git a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart index 970614542..a3e6f0093 100644 --- a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart +++ b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart @@ -165,10 +165,10 @@ class _NewWalletRecoveryPhraseWarningViewState .getPrimaryNodeFor(currency: coin); if (node == null) { - node = coin.defaultNode; + node = coin.defaultNode(isPrimary: true); await ref .read(nodeServiceChangeNotifierProvider) - .setPrimaryNodeFor(coin: coin, node: node); + .save(node, null, false); } final txTracker = TransactionNotificationTracker(walletId: info.walletId); diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_view_only_wallet_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_view_only_wallet_view.dart index 606841139..a473d83ec 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_view_only_wallet_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_view_only_wallet_view.dart @@ -198,10 +198,10 @@ class _RestoreViewOnlyWalletViewState .getPrimaryNodeFor(currency: widget.coin); if (node == null) { - node = widget.coin.defaultNode; + node = widget.coin.defaultNode(isPrimary: true); await ref .read(nodeServiceChangeNotifierProvider) - .setPrimaryNodeFor(coin: widget.coin, node: node); + .save(node, null, false); } try { diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart index b4aeb3693..535fbe07a 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart @@ -298,10 +298,10 @@ class _RestoreWalletViewState extends ConsumerState { .getPrimaryNodeFor(currency: widget.coin); if (node == null) { - node = widget.coin.defaultNode; + node = widget.coin.defaultNode(isPrimary: true); await ref .read(nodeServiceChangeNotifierProvider) - .setPrimaryNodeFor(coin: widget.coin, node: node); + .save(node, null, false); } final txTracker = TransactionNotificationTracker( diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart index bcec91212..1d8d9c90f 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart @@ -794,8 +794,8 @@ abstract class SWB { var node = nodeService.getPrimaryNodeFor(currency: coin); if (node == null) { - node = coin.defaultNode; - await nodeService.setPrimaryNodeFor(coin: coin, node: node); + node = coin.defaultNode(isPrimary: true); + await nodeService.save(node, null, false); } // final txTracker = TransactionNotificationTracker(walletId: walletId); diff --git a/lib/services/ethereum/ethereum_api.dart b/lib/services/ethereum/ethereum_api.dart index 091165b30..fd644944a 100644 --- a/lib/services/ethereum/ethereum_api.dart +++ b/lib/services/ethereum/ethereum_api.dart @@ -43,7 +43,7 @@ class EthereumResponse { abstract class EthereumAPI { static String get stackBaseServer => - Ethereum(CryptoCurrencyNetwork.main).defaultNode.host; + Ethereum(CryptoCurrencyNetwork.main).defaultNode(isPrimary: true).host; static HTTP client = HTTP(); diff --git a/lib/services/node_service.dart b/lib/services/node_service.dart index 3fb226809..c1bc338b3 100644 --- a/lib/services/node_service.dart +++ b/lib/services/node_service.dart @@ -74,7 +74,9 @@ class NodeService extends ChangeNotifier { } } - for (final defaultNode in AppConfig.coins.map((e) => e.defaultNode)) { + for (final defaultNode in AppConfig.coins.map( + (e) => e.defaultNode(isPrimary: true), + )) { final savedNode = DB.instance.get( boxName: DB.boxNameNodeModels, key: defaultNode.id, @@ -102,26 +104,8 @@ class NodeService extends ChangeNotifier { torEnabled: savedNode.torEnabled, clearnetEnabled: savedNode.clearnetEnabled, loginName: savedNode.loginName, - ), - ); - } - - // check if a default node is the primary node for the crypto currency - // and update it if needed - final coin = AppConfig.getCryptoCurrencyByPrettyName( - defaultNode.coinName, - ); - final primaryNode = getPrimaryNodeFor(currency: coin); - if (primaryNode != null && primaryNode.id == defaultNode.id) { - await setPrimaryNodeFor( - coin: coin, - node: defaultNode.copyWith( - enabled: primaryNode.enabled, - isFailover: primaryNode.isFailover, - trusted: primaryNode.trusted, - torEnabled: primaryNode.torEnabled, - clearnetEnabled: primaryNode.clearnetEnabled, - loginName: primaryNode.loginName, + isPrimary: savedNode.isPrimary, + forceNoTor: savedNode.forceNoTor, ), ); } @@ -226,17 +210,6 @@ class NodeService extends ChangeNotifier { String? password, bool shouldNotifyListeners, ) async { - // Handle primary node updates (logic from edit()) - final coin = AppConfig.getCryptoCurrencyByPrettyName(node.coinName); - final primaryNode = getPrimaryNodeFor(currency: coin); - if (primaryNode?.id == node.id) { - await setPrimaryNodeFor( - coin: coin, - node: node, - shouldNotifyListeners: true, - ); - } - // Save to database (logic from add()). await DB.instance.put( boxName: DB.boxNameNodeModels, diff --git a/lib/utilities/show_node_tor_settings_mismatch.dart b/lib/utilities/show_node_tor_settings_mismatch.dart index 6c2490b51..ce9f595f1 100644 --- a/lib/utilities/show_node_tor_settings_mismatch.dart +++ b/lib/utilities/show_node_tor_settings_mismatch.dart @@ -20,7 +20,8 @@ Future checkShowNodeTorSettingsMismatch({ bool rootNavigator = false, }) async { final node = - nodeService.getPrimaryNodeFor(currency: currency) ?? currency.defaultNode; + nodeService.getPrimaryNodeFor(currency: currency) ?? + currency.defaultNode(isPrimary: true); if (prefs.useTor) { if (node.torEnabled) { return true; @@ -34,63 +35,57 @@ Future checkShowNodeTorSettingsMismatch({ final result = await showDialog( context: context, barrierDismissible: false, - builder: (context) => ConditionalParent( - condition: Util.isDesktop, - builder: (child) => DesktopDialog( - maxHeight: double.infinity, - child: Padding( - padding: const EdgeInsets.all(32), - child: child, - ), - ), - child: ConditionalParent( - condition: !Util.isDesktop, - builder: (child) => StackDialogBase( - child: child, - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "Attention! Node connection issue detected. " - "The current node will not sync due to its connectivity settings. " - "Please adjust the node settings or enable/disable TOR.", - style: STextStyles.w600_16(context), - ), - SizedBox( - height: Util.isDesktop ? 32 : 24, - ), - Row( + builder: + (context) => ConditionalParent( + condition: Util.isDesktop, + builder: + (child) => DesktopDialog( + maxHeight: double.infinity, + child: Padding(padding: const EdgeInsets.all(32), child: child), + ), + child: ConditionalParent( + condition: !Util.isDesktop, + builder: (child) => StackDialogBase(child: child), + child: Column( + mainAxisSize: MainAxisSize.min, children: [ - allowCancel - ? Expanded( - child: SecondaryButton( - buttonHeight: Util.isDesktop ? ButtonHeight.l : null, - label: "Cancel", - onPressed: () { - Navigator.of(context).pop(false); - }, - ), - ) - : const Spacer(), - SizedBox( - width: Util.isDesktop ? 24 : 16, + Text( + "Attention! Node connection issue detected. " + "The current node will not sync due to its connectivity settings. " + "Please adjust the node settings or enable/disable TOR.", + style: STextStyles.w600_16(context), ), - Expanded( - child: PrimaryButton( - buttonHeight: Util.isDesktop ? ButtonHeight.l : null, - label: "Continue", - onPressed: () { - Navigator.of(context).pop(true); - }, - ), + SizedBox(height: Util.isDesktop ? 32 : 24), + Row( + children: [ + allowCancel + ? Expanded( + child: SecondaryButton( + buttonHeight: + Util.isDesktop ? ButtonHeight.l : null, + label: "Cancel", + onPressed: () { + Navigator.of(context).pop(false); + }, + ), + ) + : const Spacer(), + SizedBox(width: Util.isDesktop ? 24 : 16), + Expanded( + child: PrimaryButton( + buttonHeight: Util.isDesktop ? ButtonHeight.l : null, + label: "Continue", + onPressed: () { + Navigator.of(context).pop(true); + }, + ), + ), + ], ), ], ), - ], + ), ), - ), - ), ); return result ?? true; diff --git a/lib/wallets/crypto_currency/coins/banano.dart b/lib/wallets/crypto_currency/coins/banano.dart index 8b1e1114b..2a62acb57 100644 --- a/lib/wallets/crypto_currency/coins/banano.dart +++ b/lib/wallets/crypto_currency/coins/banano.dart @@ -45,9 +45,7 @@ class Banano extends NanoCurrency { int get fractionDigits => 29; @override - BigInt get satsPerCoin => BigInt.parse( - "100000000000000000000000000000", - ); // 1*10^29 + BigInt get satsPerCoin => BigInt.parse("100000000000000000000000000000"); // 1*10^29 @override int get minConfirms => 1; @@ -63,7 +61,7 @@ class Banano extends NanoCurrency { int get nanoAccountType => NanoAccountType.BANANO; @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -79,6 +77,7 @@ class Banano extends NanoCurrency { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: @@ -99,7 +98,8 @@ class Banano extends NanoCurrency { } @override - DerivePathType get defaultDerivePathType => throw UnsupportedError( + DerivePathType get defaultDerivePathType => + throw UnsupportedError( "$runtimeType does not use bitcoin style derivation paths", ); } diff --git a/lib/wallets/crypto_currency/coins/bitcoin.dart b/lib/wallets/crypto_currency/coins/bitcoin.dart index 35a9cf8f0..e6862edb5 100644 --- a/lib/wallets/crypto_currency/coins/bitcoin.dart +++ b/lib/wallets/crypto_currency/coins/bitcoin.dart @@ -62,11 +62,11 @@ class Bitcoin extends Bip39HDCurrency @override List get supportedDerivationPathTypes => [ - DerivePathType.bip44, - DerivePathType.bip49, - DerivePathType.bip84, - DerivePathType.bip86, // P2TR. - ]; + DerivePathType.bip44, + DerivePathType.bip49, + DerivePathType.bip84, + DerivePathType.bip86, // P2TR. + ]; @override String get genesisHash { @@ -83,10 +83,8 @@ class Bitcoin extends Bip39HDCurrency } @override - Amount get dustLimit => Amount( - rawValue: BigInt.from(294), - fractionDigits: fractionDigits, - ); + Amount get dustLimit => + Amount(rawValue: BigInt.from(294), fractionDigits: fractionDigits); @override coinlib.Network get networkParams { @@ -180,10 +178,11 @@ class Bitcoin extends Bip39HDCurrency // TODO: [prio=high] verify this works similarly to bitcoindart's p2sh or something(!!) case DerivePathType.bip49: - final p2wpkhScript = coinlib.P2WPKHAddress.fromPublicKey( - publicKey, - hrp: networkParams.bech32Hrp, - ).program.script; + final p2wpkhScript = + coinlib.P2WPKHAddress.fromPublicKey( + publicKey, + hrp: networkParams.bech32Hrp, + ).program.script; final addr = coinlib.P2SHAddress.fromRedeemScript( p2wpkhScript, @@ -226,7 +225,7 @@ class Bitcoin extends Bip39HDCurrency } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -241,6 +240,7 @@ class Bitcoin extends Bip39HDCurrency isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); case CryptoCurrencyNetwork.test: @@ -256,6 +256,7 @@ class Bitcoin extends Bip39HDCurrency isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); case CryptoCurrencyNetwork.test4: @@ -271,6 +272,7 @@ class Bitcoin extends Bip39HDCurrency isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: diff --git a/lib/wallets/crypto_currency/coins/bitcoin_frost.dart b/lib/wallets/crypto_currency/coins/bitcoin_frost.dart index d1f22227e..330d3cb86 100644 --- a/lib/wallets/crypto_currency/coins/bitcoin_frost.dart +++ b/lib/wallets/crypto_currency/coins/bitcoin_frost.dart @@ -60,7 +60,7 @@ class BitcoinFrost extends FrostCurrency { bool get torSupport => true; @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -75,6 +75,7 @@ class BitcoinFrost extends FrostCurrency { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); case CryptoCurrencyNetwork.test: @@ -90,6 +91,7 @@ class BitcoinFrost extends FrostCurrency { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); case CryptoCurrencyNetwork.test4: @@ -105,6 +107,7 @@ class BitcoinFrost extends FrostCurrency { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: @@ -127,10 +130,8 @@ class BitcoinFrost extends FrostCurrency { } @override - Amount get dustLimit => Amount( - rawValue: BigInt.from(294), - fractionDigits: fractionDigits, - ); + Amount get dustLimit => + Amount(rawValue: BigInt.from(294), fractionDigits: fractionDigits); @override Uint8List addressToPubkey({required String address}) { @@ -222,7 +223,8 @@ class BitcoinFrost extends FrostCurrency { int get targetBlockTimeSeconds => 600; @override - DerivePathType get defaultDerivePathType => throw UnsupportedError( + DerivePathType get defaultDerivePathType => + throw UnsupportedError( "$runtimeType does not use bitcoin style derivation paths", ); diff --git a/lib/wallets/crypto_currency/coins/bitcoincash.dart b/lib/wallets/crypto_currency/coins/bitcoincash.dart index 6f6d5e4b5..6ea2a8c3e 100644 --- a/lib/wallets/crypto_currency/coins/bitcoincash.dart +++ b/lib/wallets/crypto_currency/coins/bitcoincash.dart @@ -65,9 +65,9 @@ class Bitcoincash extends Bip39HDCurrency with ElectrumXCurrencyInterface { @override List get supportedDerivationPathTypes => [ - DerivePathType.bip44, - if (network != CryptoCurrencyNetwork.test) DerivePathType.bch44, - ]; + DerivePathType.bip44, + if (network != CryptoCurrencyNetwork.test) DerivePathType.bch44, + ]; @override String get genesisHash { @@ -82,10 +82,8 @@ class Bitcoincash extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - Amount get dustLimit => Amount( - rawValue: BigInt.from(546), - fractionDigits: fractionDigits, - ); + Amount get dustLimit => + Amount(rawValue: BigInt.from(546), fractionDigits: fractionDigits); @override coinlib.Network get networkParams { @@ -285,7 +283,7 @@ class Bitcoincash extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -300,6 +298,7 @@ class Bitcoincash extends Bip39HDCurrency with ElectrumXCurrencyInterface { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); case CryptoCurrencyNetwork.test: @@ -315,6 +314,7 @@ class Bitcoincash extends Bip39HDCurrency with ElectrumXCurrencyInterface { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: diff --git a/lib/wallets/crypto_currency/coins/cardano.dart b/lib/wallets/crypto_currency/coins/cardano.dart index 71ea2c372..976093a03 100644 --- a/lib/wallets/crypto_currency/coins/cardano.dart +++ b/lib/wallets/crypto_currency/coins/cardano.dart @@ -52,7 +52,8 @@ class Cardano extends Bip39Currency { switch (network) { case CryptoCurrencyNetwork.main: return Uri.parse( - "https://explorer.cardano.org/en/transaction?id=$txid"); + "https://explorer.cardano.org/en/transaction?id=$txid", + ); default: throw Exception( "Unsupported network for defaultBlockExplorer(): $network", @@ -64,7 +65,7 @@ class Cardano extends Bip39Currency { DerivePathType get defaultDerivePathType => DerivePathType.cardanoShelley; @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -79,6 +80,7 @@ class Cardano extends Bip39Currency { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: diff --git a/lib/wallets/crypto_currency/coins/dash.dart b/lib/wallets/crypto_currency/coins/dash.dart index 1a63f1811..e2ad041ea 100644 --- a/lib/wallets/crypto_currency/coins/dash.dart +++ b/lib/wallets/crypto_currency/coins/dash.dart @@ -52,8 +52,8 @@ class Dash extends Bip39HDCurrency with ElectrumXCurrencyInterface { @override List get supportedDerivationPathTypes => [ - DerivePathType.bip44, - ]; + DerivePathType.bip44, + ]; @override String constructDerivePath({ @@ -89,10 +89,8 @@ class Dash extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - Amount get dustLimit => Amount( - rawValue: BigInt.from(1000000), - fractionDigits: fractionDigits, - ); + Amount get dustLimit => + Amount(rawValue: BigInt.from(1000000), fractionDigits: fractionDigits); @override String get genesisHash { @@ -107,10 +105,7 @@ class Dash extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - ({ - coinlib.Address address, - AddressType addressType, - }) getAddressForPublicKey({ + ({coinlib.Address address, AddressType addressType}) getAddressForPublicKey({ required coinlib.ECPublicKey publicKey, required DerivePathType derivePathType, }) { @@ -176,7 +171,7 @@ class Dash extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -191,6 +186,7 @@ class Dash extends Bip39HDCurrency with ElectrumXCurrencyInterface { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: diff --git a/lib/wallets/crypto_currency/coins/dogecoin.dart b/lib/wallets/crypto_currency/coins/dogecoin.dart index ce10bc0d7..1d281f5bb 100644 --- a/lib/wallets/crypto_currency/coins/dogecoin.dart +++ b/lib/wallets/crypto_currency/coins/dogecoin.dart @@ -52,8 +52,8 @@ class Dogecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { @override List get supportedDerivationPathTypes => [ - DerivePathType.bip44, - ]; + DerivePathType.bip44, + ]; @override String constructDerivePath({ @@ -89,10 +89,8 @@ class Dogecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - Amount get dustLimit => Amount( - rawValue: BigInt.from(1000000), - fractionDigits: fractionDigits, - ); + Amount get dustLimit => + Amount(rawValue: BigInt.from(1000000), fractionDigits: fractionDigits); @override String get genesisHash { @@ -107,10 +105,7 @@ class Dogecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - ({ - coinlib.Address address, - AddressType addressType, - }) getAddressForPublicKey({ + ({coinlib.Address address, AddressType addressType}) getAddressForPublicKey({ required coinlib.ECPublicKey publicKey, required DerivePathType derivePathType, }) { @@ -176,7 +171,7 @@ class Dogecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -191,6 +186,7 @@ class Dogecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); case CryptoCurrencyNetwork.test: @@ -206,6 +202,7 @@ class Dogecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: diff --git a/lib/wallets/crypto_currency/coins/ecash.dart b/lib/wallets/crypto_currency/coins/ecash.dart index 4074b249d..a41a47394 100644 --- a/lib/wallets/crypto_currency/coins/ecash.dart +++ b/lib/wallets/crypto_currency/coins/ecash.dart @@ -60,9 +60,9 @@ class Ecash extends Bip39HDCurrency with ElectrumXCurrencyInterface { @override List get supportedDerivationPathTypes => [ - DerivePathType.eCash44, - DerivePathType.bip44, - ]; + DerivePathType.eCash44, + DerivePathType.bip44, + ]; @override String get genesisHash { @@ -77,10 +77,8 @@ class Ecash extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - Amount get dustLimit => Amount( - rawValue: BigInt.from(546), - fractionDigits: fractionDigits, - ); + Amount get dustLimit => + Amount(rawValue: BigInt.from(546), fractionDigits: fractionDigits); @override coinlib.Network get networkParams { @@ -276,7 +274,7 @@ class Ecash extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -291,6 +289,7 @@ class Ecash extends Bip39HDCurrency with ElectrumXCurrencyInterface { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: diff --git a/lib/wallets/crypto_currency/coins/epiccash.dart b/lib/wallets/crypto_currency/coins/epiccash.dart index 25fdd6c9c..d35c0fb74 100644 --- a/lib/wallets/crypto_currency/coins/epiccash.dart +++ b/lib/wallets/crypto_currency/coins/epiccash.dart @@ -67,7 +67,7 @@ class Epiccash extends Bip39Currency { } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -82,6 +82,7 @@ class Epiccash extends Bip39Currency { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: @@ -114,7 +115,8 @@ class Epiccash extends Bip39Currency { int get targetBlockTimeSeconds => 60; @override - DerivePathType get defaultDerivePathType => throw UnsupportedError( + DerivePathType get defaultDerivePathType => + throw UnsupportedError( "$runtimeType does not use bitcoin style derivation paths", ); diff --git a/lib/wallets/crypto_currency/coins/ethereum.dart b/lib/wallets/crypto_currency/coins/ethereum.dart index cd908b9e6..f6f3601a1 100644 --- a/lib/wallets/crypto_currency/coins/ethereum.dart +++ b/lib/wallets/crypto_currency/coins/ethereum.dart @@ -48,7 +48,7 @@ class Ethereum extends Bip39Currency { bool get hasTokenSupport => true; @override - NodeModel get defaultNode => NodeModel( + NodeModel defaultNode({required bool isPrimary}) => NodeModel( host: "https://eth2.stackwallet.com", port: 443, name: DefaultNodes.defaultName, @@ -60,6 +60,7 @@ class Ethereum extends Bip39Currency { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); @override diff --git a/lib/wallets/crypto_currency/coins/fact0rn.dart b/lib/wallets/crypto_currency/coins/fact0rn.dart index 84fc902b5..a168c9dec 100644 --- a/lib/wallets/crypto_currency/coins/fact0rn.dart +++ b/lib/wallets/crypto_currency/coins/fact0rn.dart @@ -171,7 +171,7 @@ class Fact0rn extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -186,6 +186,7 @@ class Fact0rn extends Bip39HDCurrency with ElectrumXCurrencyInterface { isDown: false, torEnabled: false, clearnetEnabled: true, + isPrimary: isPrimary, ); default: diff --git a/lib/wallets/crypto_currency/coins/firo.dart b/lib/wallets/crypto_currency/coins/firo.dart index 79ed783f8..f432bd77b 100644 --- a/lib/wallets/crypto_currency/coins/firo.dart +++ b/lib/wallets/crypto_currency/coins/firo.dart @@ -62,8 +62,8 @@ class Firo extends Bip39HDCurrency with ElectrumXCurrencyInterface { @override List get supportedDerivationPathTypes => [ - DerivePathType.bip44, - ]; + DerivePathType.bip44, + ]; @override String get genesisHash { @@ -78,10 +78,8 @@ class Firo extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - Amount get dustLimit => Amount( - rawValue: BigInt.from(1000), - fractionDigits: fractionDigits, - ); + Amount get dustLimit => + Amount(rawValue: BigInt.from(1000), fractionDigits: fractionDigits); Uint8List get exAddressVersion { switch (network) { @@ -207,10 +205,7 @@ class Firo extends Bip39HDCurrency with ElectrumXCurrencyInterface { bool isExchangeAddress(String address) { try { - EXP2PKHAddress.fromString( - address, - exAddressVersion, - ); + EXP2PKHAddress.fromString(address, exAddressVersion); return true; } catch (_) { return false; @@ -218,7 +213,7 @@ class Firo extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -233,6 +228,7 @@ class Firo extends Bip39HDCurrency with ElectrumXCurrencyInterface { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); case CryptoCurrencyNetwork.test: @@ -248,6 +244,7 @@ class Firo extends Bip39HDCurrency with ElectrumXCurrencyInterface { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: diff --git a/lib/wallets/crypto_currency/coins/litecoin.dart b/lib/wallets/crypto_currency/coins/litecoin.dart index 91b444f73..4ab8ec0c2 100644 --- a/lib/wallets/crypto_currency/coins/litecoin.dart +++ b/lib/wallets/crypto_currency/coins/litecoin.dart @@ -56,10 +56,10 @@ class Litecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { @override List get supportedDerivationPathTypes => [ - DerivePathType.bip44, - DerivePathType.bip49, - DerivePathType.bip84, - ]; + DerivePathType.bip44, + DerivePathType.bip49, + DerivePathType.bip84, + ]; @override String get genesisHash { @@ -74,15 +74,11 @@ class Litecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - Amount get dustLimit => Amount( - rawValue: BigInt.from(294), - fractionDigits: fractionDigits, - ); + Amount get dustLimit => + Amount(rawValue: BigInt.from(294), fractionDigits: fractionDigits); - Amount get dustLimitP2PKH => Amount( - rawValue: BigInt.from(546), - fractionDigits: fractionDigits, - ); + Amount get dustLimitP2PKH => + Amount(rawValue: BigInt.from(546), fractionDigits: fractionDigits); @override coinlib.Network get networkParams { @@ -171,10 +167,11 @@ class Litecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { return (address: addr, addressType: AddressType.p2pkh); case DerivePathType.bip49: - final p2wpkhScript = coinlib.P2WPKHAddress.fromPublicKey( - publicKey, - hrp: networkParams.bech32Hrp, - ).program.script; + final p2wpkhScript = + coinlib.P2WPKHAddress.fromPublicKey( + publicKey, + hrp: networkParams.bech32Hrp, + ).program.script; final addr = coinlib.P2SHAddress.fromRedeemScript( p2wpkhScript, @@ -207,7 +204,7 @@ class Litecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -222,6 +219,7 @@ class Litecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); case CryptoCurrencyNetwork.test: @@ -237,6 +235,7 @@ class Litecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: diff --git a/lib/wallets/crypto_currency/coins/monero.dart b/lib/wallets/crypto_currency/coins/monero.dart index 4cbeeeb68..4d1535179 100644 --- a/lib/wallets/crypto_currency/coins/monero.dart +++ b/lib/wallets/crypto_currency/coins/monero.dart @@ -61,7 +61,7 @@ class Monero extends CryptonoteCurrency { } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -77,6 +77,7 @@ class Monero extends CryptonoteCurrency { trusted: true, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: @@ -106,7 +107,8 @@ class Monero extends CryptonoteCurrency { int get targetBlockTimeSeconds => 120; @override - DerivePathType get defaultDerivePathType => throw UnsupportedError( + DerivePathType get defaultDerivePathType => + throw UnsupportedError( "$runtimeType does not use bitcoin style derivation paths", ); diff --git a/lib/wallets/crypto_currency/coins/namecoin.dart b/lib/wallets/crypto_currency/coins/namecoin.dart index 77940784e..7945e8bca 100644 --- a/lib/wallets/crypto_currency/coins/namecoin.dart +++ b/lib/wallets/crypto_currency/coins/namecoin.dart @@ -89,7 +89,7 @@ class Namecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -104,6 +104,7 @@ class Namecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); // case CryptoCurrencyNetwork.test: // TODO: [prio=low] Add testnet support. @@ -114,10 +115,8 @@ class Namecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { @override // See https://github.com/cypherstack/stack_wallet/blob/621aff47969761014e0a6c4e699cb637d5687ab3/lib/services/coins/namecoin/namecoin_wallet.dart#L60 - Amount get dustLimit => Amount( - rawValue: BigInt.from(546), - fractionDigits: fractionDigits, - ); + Amount get dustLimit => + Amount(rawValue: BigInt.from(546), fractionDigits: fractionDigits); @override // See https://github.com/cypherstack/stack_wallet/blob/621aff47969761014e0a6c4e699cb637d5687ab3/lib/services/coins/namecoin/namecoin_wallet.dart#L6 @@ -149,10 +148,11 @@ class Namecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { return (address: addr, addressType: AddressType.p2pkh); case DerivePathType.bip49: - final p2wpkhScript = coinlib.P2WPKHAddress.fromPublicKey( - publicKey, - hrp: networkParams.bech32Hrp, - ).program.script; + final p2wpkhScript = + coinlib.P2WPKHAddress.fromPublicKey( + publicKey, + hrp: networkParams.bech32Hrp, + ).program.script; final addr = coinlib.P2SHAddress.fromRedeemScript( p2wpkhScript, @@ -200,11 +200,11 @@ class Namecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { @override List get supportedDerivationPathTypes => [ - // DerivePathType.bip16, - DerivePathType.bip44, - DerivePathType.bip49, - DerivePathType.bip84, - ]; + // DerivePathType.bip16, + DerivePathType.bip44, + DerivePathType.bip49, + DerivePathType.bip84, + ]; @override bool validateAddress(String address) { diff --git a/lib/wallets/crypto_currency/coins/nano.dart b/lib/wallets/crypto_currency/coins/nano.dart index 0909b8aa8..07f464926 100644 --- a/lib/wallets/crypto_currency/coins/nano.dart +++ b/lib/wallets/crypto_currency/coins/nano.dart @@ -45,9 +45,7 @@ class Nano extends NanoCurrency { int get fractionDigits => 30; @override - BigInt get satsPerCoin => BigInt.parse( - "1000000000000000000000000000000", - ); // 1*10^30 + BigInt get satsPerCoin => BigInt.parse("1000000000000000000000000000000"); // 1*10^30 @override int get minConfirms => 1; @@ -63,7 +61,7 @@ class Nano extends NanoCurrency { int get nanoAccountType => NanoAccountType.NANO; @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -79,6 +77,7 @@ class Nano extends NanoCurrency { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: @@ -87,7 +86,8 @@ class Nano extends NanoCurrency { } @override - DerivePathType get defaultDerivePathType => throw UnsupportedError( + DerivePathType get defaultDerivePathType => + throw UnsupportedError( "$runtimeType does not use bitcoin style derivation paths", ); diff --git a/lib/wallets/crypto_currency/coins/particl.dart b/lib/wallets/crypto_currency/coins/particl.dart index 8788b6114..2b07aad7e 100644 --- a/lib/wallets/crypto_currency/coins/particl.dart +++ b/lib/wallets/crypto_currency/coins/particl.dart @@ -84,7 +84,7 @@ class Particl extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -99,6 +99,7 @@ class Particl extends Bip39HDCurrency with ElectrumXCurrencyInterface { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); // case CryptoCurrencyNetwork.test: // TODO: [prio=low] Add testnet. @@ -109,10 +110,8 @@ class Particl extends Bip39HDCurrency with ElectrumXCurrencyInterface { @override // See https://github.com/cypherstack/stack_wallet/blob/d08b5c9b22b58db800ad07b2ceeb44c6d05f9cf3/lib/services/coins/particl/particl_wallet.dart#L58 - Amount get dustLimit => Amount( - rawValue: BigInt.from(294), - fractionDigits: fractionDigits, - ); + Amount get dustLimit => + Amount(rawValue: BigInt.from(294), fractionDigits: fractionDigits); @override // See https://github.com/cypherstack/stack_wallet/blob/d08b5c9b22b58db800ad07b2ceeb44c6d05f9cf3/lib/services/coins/particl/particl_wallet.dart#L63 @@ -180,9 +179,9 @@ class Particl extends Bip39HDCurrency with ElectrumXCurrencyInterface { @override List get supportedDerivationPathTypes => [ - DerivePathType.bip44, - DerivePathType.bip84, - ]; + DerivePathType.bip44, + DerivePathType.bip84, + ]; @override bool validateAddress(String address) { diff --git a/lib/wallets/crypto_currency/coins/peercoin.dart b/lib/wallets/crypto_currency/coins/peercoin.dart index b67b0e1ab..0515beb4c 100644 --- a/lib/wallets/crypto_currency/coins/peercoin.dart +++ b/lib/wallets/crypto_currency/coins/peercoin.dart @@ -90,7 +90,7 @@ class Peercoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -105,6 +105,7 @@ class Peercoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); case CryptoCurrencyNetwork.test: @@ -120,6 +121,7 @@ class Peercoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: @@ -129,10 +131,10 @@ class Peercoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { @override Amount get dustLimit => Amount( - // TODO should this be 10000 instead of 294 for peercoin? - rawValue: BigInt.from(294), - fractionDigits: fractionDigits, - ); + // TODO should this be 10000 instead of 294 for peercoin? + rawValue: BigInt.from(294), + fractionDigits: fractionDigits, + ); @override String get genesisHash { @@ -163,10 +165,11 @@ class Peercoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { return (address: addr, addressType: AddressType.p2pkh); case DerivePathType.bip49: - final p2wpkhScript = coinlib.P2WPKHAddress.fromPublicKey( - publicKey, - hrp: networkParams.bech32Hrp, - ).program.script; + final p2wpkhScript = + coinlib.P2WPKHAddress.fromPublicKey( + publicKey, + hrp: networkParams.bech32Hrp, + ).program.script; final addr = coinlib.P2SHAddress.fromRedeemScript( p2wpkhScript, @@ -202,9 +205,9 @@ class Peercoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { @override List get supportedDerivationPathTypes => [ - DerivePathType.bip44, - DerivePathType.bip84, - ]; + DerivePathType.bip44, + DerivePathType.bip84, + ]; @override bool validateAddress(String address) { diff --git a/lib/wallets/crypto_currency/coins/salvium.dart b/lib/wallets/crypto_currency/coins/salvium.dart index 1bbe599a3..d7618094c 100644 --- a/lib/wallets/crypto_currency/coins/salvium.dart +++ b/lib/wallets/crypto_currency/coins/salvium.dart @@ -61,7 +61,7 @@ class Salvium extends CryptonoteCurrency { } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -77,6 +77,7 @@ class Salvium extends CryptonoteCurrency { trusted: true, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: diff --git a/lib/wallets/crypto_currency/coins/solana.dart b/lib/wallets/crypto_currency/coins/solana.dart index 1db985c76..39d243a1c 100644 --- a/lib/wallets/crypto_currency/coins/solana.dart +++ b/lib/wallets/crypto_currency/coins/solana.dart @@ -42,7 +42,7 @@ class Solana extends Bip39Currency { String get ticker => _ticker; @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -57,6 +57,7 @@ class Solana extends Bip39Currency { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: throw Exception("Unsupported network: $network"); diff --git a/lib/wallets/crypto_currency/coins/stellar.dart b/lib/wallets/crypto_currency/coins/stellar.dart index d799de31b..077564a50 100644 --- a/lib/wallets/crypto_currency/coins/stellar.dart +++ b/lib/wallets/crypto_currency/coins/stellar.dart @@ -50,12 +50,10 @@ class Stellar extends Bip39Currency { bool get torSupport => true; @override - String get genesisHash => throw UnimplementedError( - "Not used for stellar", - ); + String get genesisHash => throw UnimplementedError("Not used for stellar"); @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -70,6 +68,7 @@ class Stellar extends Bip39Currency { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); case CryptoCurrencyNetwork.test: @@ -85,6 +84,7 @@ class Stellar extends Bip39Currency { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: @@ -115,15 +115,14 @@ class Stellar extends Bip39Currency { AddressType get defaultAddressType => AddressType.stellar; @override - BigInt get satsPerCoin => BigInt.from( - 10000000, - ); // https://developers.stellar.org/docs/fundamentals-and-concepts/stellar-data-structures/assets#amount-precision + BigInt get satsPerCoin => BigInt.from(10000000); // https://developers.stellar.org/docs/fundamentals-and-concepts/stellar-data-structures/assets#amount-precision @override int get targetBlockTimeSeconds => 5; @override - DerivePathType get defaultDerivePathType => throw UnsupportedError( + DerivePathType get defaultDerivePathType => + throw UnsupportedError( "$runtimeType does not use bitcoin style derivation paths", ); diff --git a/lib/wallets/crypto_currency/coins/tezos.dart b/lib/wallets/crypto_currency/coins/tezos.dart index 0cb8cca0c..78d3c02ad 100644 --- a/lib/wallets/crypto_currency/coins/tezos.dart +++ b/lib/wallets/crypto_currency/coins/tezos.dart @@ -54,11 +54,11 @@ class Tezos extends Bip39Currency { DerivationPath()..value = "m/44'/1729'/0'/0'"; static List get possibleDerivationPaths => [ - standardDerivationPath, - DerivationPath()..value = "", - DerivationPath()..value = "m/44'/1729'/0'/0'/0'", - DerivationPath()..value = "m/44'/1729'/0'/0/0", - ]; + standardDerivationPath, + DerivationPath()..value = "", + DerivationPath()..value = "m/44'/1729'/0'/0'/0'", + DerivationPath()..value = "m/44'/1729'/0'/0/0", + ]; static Keystore mnemonicToKeyStore({ required String mnemonic, @@ -88,9 +88,8 @@ class Tezos extends Bip39Currency { // =========== Overrides ===================================================== @override - String get genesisHash => throw UnimplementedError( - "Not used in tezos at the moment", - ); + String get genesisHash => + throw UnimplementedError("Not used in tezos at the moment"); @override int get minConfirms => 1; @@ -104,7 +103,7 @@ class Tezos extends Bip39Currency { } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -120,6 +119,7 @@ class Tezos extends Bip39Currency { isDown: false, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: diff --git a/lib/wallets/crypto_currency/coins/wownero.dart b/lib/wallets/crypto_currency/coins/wownero.dart index 2aea90aa8..0c702af40 100644 --- a/lib/wallets/crypto_currency/coins/wownero.dart +++ b/lib/wallets/crypto_currency/coins/wownero.dart @@ -61,7 +61,7 @@ class Wownero extends CryptonoteCurrency { } @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -77,6 +77,7 @@ class Wownero extends CryptonoteCurrency { trusted: true, torEnabled: true, clearnetEnabled: true, + isPrimary: isPrimary, ); default: @@ -106,7 +107,8 @@ class Wownero extends CryptonoteCurrency { int get targetBlockTimeSeconds => 120; @override - DerivePathType get defaultDerivePathType => throw UnsupportedError( + DerivePathType get defaultDerivePathType => + throw UnsupportedError( "$runtimeType does not use bitcoin style derivation paths", ); diff --git a/lib/wallets/crypto_currency/coins/xelis.dart b/lib/wallets/crypto_currency/coins/xelis.dart index b05fce216..fc1eaaa20 100644 --- a/lib/wallets/crypto_currency/coins/xelis.dart +++ b/lib/wallets/crypto_currency/coins/xelis.dart @@ -1,3 +1,5 @@ +import 'package:xelis_flutter/src/api/utils.dart' as x_utils; + import '../../../models/isar/models/blockchain_data/address.dart'; import '../../../models/node_model.dart'; import '../../../utilities/default_nodes.dart'; @@ -5,8 +7,6 @@ import '../../../utilities/enums/derive_path_type_enum.dart'; import '../crypto_currency.dart'; import '../intermediate/electrum_currency.dart'; -import 'package:xelis_flutter/src/api/utils.dart' as x_utils; - class Xelis extends ElectrumCurrency { Xelis(super.network) { _idMain = "xelis"; @@ -46,7 +46,7 @@ class Xelis extends ElectrumCurrency { String get ticker => _ticker; @override - NodeModel get defaultNode { + NodeModel defaultNode({required bool isPrimary}) { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( @@ -61,6 +61,7 @@ class Xelis extends ElectrumCurrency { isDown: false, torEnabled: false, clearnetEnabled: true, + isPrimary: isPrimary, ); case CryptoCurrencyNetwork.test: @@ -76,6 +77,7 @@ class Xelis extends ElectrumCurrency { isDown: false, torEnabled: false, clearnetEnabled: true, + isPrimary: isPrimary, ); default: diff --git a/lib/wallets/crypto_currency/crypto_currency.dart b/lib/wallets/crypto_currency/crypto_currency.dart index 363022e63..4f6c232e6 100644 --- a/lib/wallets/crypto_currency/crypto_currency.dart +++ b/lib/wallets/crypto_currency/crypto_currency.dart @@ -70,7 +70,7 @@ abstract class CryptoCurrency { bool validateAddress(String address); - NodeModel get defaultNode; + NodeModel defaultNode({required bool isPrimary}); int get defaultSeedPhraseLength; int get fractionDigits; diff --git a/lib/wallets/wallet/impl/solana_wallet.dart b/lib/wallets/wallet/impl/solana_wallet.dart index 0b7c2911d..5a5ef7c57 100644 --- a/lib/wallets/wallet/impl/solana_wallet.dart +++ b/lib/wallets/wallet/impl/solana_wallet.dart @@ -371,7 +371,7 @@ class SolanaWallet extends Bip39Wallet { NodeService( secureStorageInterface: secureStorageInterface, ).getPrimaryNodeFor(currency: info.coin) ?? - info.coin.defaultNode; + info.coin.defaultNode(isPrimary: true); await refresh(); } @@ -381,7 +381,7 @@ class SolanaWallet extends Bip39Wallet { NodeService( secureStorageInterface: secureStorageInterface, ).getPrimaryNodeFor(currency: info.coin) ?? - info.coin.defaultNode; + info.coin.defaultNode(isPrimary: true); return _solNode!; } diff --git a/lib/wallets/wallet/impl/tezos_wallet.dart b/lib/wallets/wallet/impl/tezos_wallet.dart index ae2183be0..53afa8df9 100644 --- a/lib/wallets/wallet/impl/tezos_wallet.dart +++ b/lib/wallets/wallet/impl/tezos_wallet.dart @@ -520,7 +520,7 @@ class TezosWallet extends Bip39Wallet { NodeService( secureStorageInterface: secureStorageInterface, ).getPrimaryNodeFor(currency: info.coin) ?? - info.coin.defaultNode; + info.coin.defaultNode(isPrimary: true); await refresh(); } @@ -531,7 +531,7 @@ class TezosWallet extends Bip39Wallet { NodeService( secureStorageInterface: secureStorageInterface, ).getPrimaryNodeFor(currency: info.coin) ?? - info.coin.defaultNode; + info.coin.defaultNode(isPrimary: true); } @override diff --git a/lib/wallets/wallet/wallet.dart b/lib/wallets/wallet/wallet.dart index 6ea950fe7..c2bfa5b41 100644 --- a/lib/wallets/wallet/wallet.dart +++ b/lib/wallets/wallet/wallet.dart @@ -506,7 +506,7 @@ abstract class Wallet { NodeModel getCurrentNode() { final node = nodeService.getPrimaryNodeFor(currency: cryptoCurrency) ?? - cryptoCurrency.defaultNode; + cryptoCurrency.defaultNode(isPrimary: true); return node; } diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart index 4c3233de7..f9efe7975 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart @@ -324,7 +324,7 @@ mixin NanoInterface on Bip39Wallet { NodeService( secureStorageInterface: secureStorageInterface, ).getPrimaryNodeFor(currency: info.coin) ?? - info.coin.defaultNode; + info.coin.defaultNode(isPrimary: true); unawaited(refresh()); } @@ -335,7 +335,7 @@ mixin NanoInterface on Bip39Wallet { NodeService( secureStorageInterface: secureStorageInterface, ).getPrimaryNodeFor(currency: info.coin) ?? - info.coin.defaultNode; + info.coin.defaultNode(isPrimary: true); } @override diff --git a/test/services/node_service_test.dart b/test/services/node_service_test.dart index 8865c748c..cb0acd6de 100644 --- a/test/services/node_service_test.dart +++ b/test/services/node_service_test.dart @@ -166,8 +166,9 @@ void main() { ); setUp(() async { - await NodeService(secureStorageInterface: FakeSecureStorage()) - .updateDefaults(); + await NodeService( + secureStorageInterface: FakeSecureStorage(), + ).updateDefaults(); }); test("setPrimaryNodeFor and getPrimaryNodeFor", () async { @@ -181,7 +182,7 @@ void main() { ); await service.setPrimaryNodeFor( coin: Bitcoin(CryptoCurrencyNetwork.main), - node: Bitcoin(CryptoCurrencyNetwork.main).defaultNode, + node: Bitcoin(CryptoCurrencyNetwork.main).defaultNode(isPrimary: true), ); expect( service @@ -197,17 +198,17 @@ void main() { final service = NodeService(secureStorageInterface: fakeStore); await service.setPrimaryNodeFor( coin: Bitcoin(CryptoCurrencyNetwork.main), - node: Bitcoin(CryptoCurrencyNetwork.main).defaultNode, + node: Bitcoin(CryptoCurrencyNetwork.main).defaultNode(isPrimary: true), ); await service.setPrimaryNodeFor( coin: Monero(CryptoCurrencyNetwork.main), - node: Monero(CryptoCurrencyNetwork.main).defaultNode, + node: Monero(CryptoCurrencyNetwork.main).defaultNode(isPrimary: true), ); expect( service.primaryNodes.toString(), [ - Bitcoin(CryptoCurrencyNetwork.main).defaultNode, - Monero(CryptoCurrencyNetwork.main).defaultNode, + Bitcoin(CryptoCurrencyNetwork.main).defaultNode(isPrimary: true), + Monero(CryptoCurrencyNetwork.main).defaultNode(isPrimary: true), ].toString(), ); expect(fakeStore.interactions, 0); @@ -217,7 +218,8 @@ void main() { final fakeStore = FakeSecureStorage(); final service = NodeService(secureStorageInterface: fakeStore); final nodes = service.nodes; - final defaults = AppConfig.coins.map((e) => e.defaultNode).toList(); + final defaults = + AppConfig.coins.map((e) => e.defaultNode(isPrimary: true)).toList(); nodes.sort((a, b) => a.id.compareTo(b.id)); defaults.sort((a, b) => a.id.compareTo(b.id)); From b9d15c843327cde2d19024b2f19a931a04e13c22 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 2 Jun 2025 13:36:57 -0600 Subject: [PATCH 11/11] fix file closed error --- lib/db/db_version_migration.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/db/db_version_migration.dart b/lib/db/db_version_migration.dart index 2e5ebf219..9c278ff19 100644 --- a/lib/db/db_version_migration.dart +++ b/lib/db/db_version_migration.dart @@ -669,7 +669,6 @@ class DbVersionMigrator with WalletDB { ); } - await primariesBox.close(); await primariesBox.deleteFromDisk(); } }